Custom tx validator logic WIP

This commit is contained in:
Kirill Maksimov 2023-12-21 15:02:54 +02:00
parent 577be37e0e
commit 65e11e1ee1
4 changed files with 82 additions and 0 deletions

View file

@ -54,4 +54,7 @@ var (
// ErrFutureReplacePending is returned if a future transaction replaces a pending
// one. Future transactions should only be able to replace other future transactions.
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
// FIXME add proper explanation (Kirill)
ErrCustomValidationFailed = errors.New("tranaction failed custom validation")
)

View file

@ -134,6 +134,8 @@ type Config struct {
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
CustomValidationEnabled bool
}
// DefaultConfig contains the default configurations for the transaction pool.
@ -150,6 +152,8 @@ var DefaultConfig = Config{
GlobalQueue: 1024,
Lifetime: 3 * time.Hour,
CustomValidationEnabled: false,
}
// sanitize checks the provided user configurations and changes anything that's
@ -605,6 +609,17 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
return nil
}
// FIXME add proper explanation (Kirill)
func (pool *LegacyPool) validateTxWithCustomValidator(tx *types.Transaction, local bool) error {
if pool.config.CustomValidationEnabled {
opts := &txpool.CustomValidationOptions{}
if err := txpool.ValidateTransactionWithCustomValidator(tx, pool.currentHead.Load(), pool.signer, opts); err != nil {
return err
}
}
return nil
}
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
@ -981,6 +996,14 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error
invalidTxMeter.Mark(1)
continue
}
// FIXME kirill
if err := pool.validateTxWithCustomValidator(tx, local); err != nil {
errs[i] = err
log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err)
invalidTxMeter.Mark(1)
continue
}
// Accumulate all unknown transactions for deeper processing
news = append(news, tx)
}

View file

@ -1536,6 +1536,52 @@ func TestMinGasPriceEnforced(t *testing.T) {
}
}
func TestCustomTxValidationEnforced(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed))
txPoolConfig := DefaultConfig
if txPoolConfig.CustomValidationEnabled {
t.Fatalf("Custom validation should be disabled by default")
}
txPoolConfig.NoLocals = true
pool := New(txPoolConfig, blockchain)
pool.Init(new(big.Int).SetUint64(txPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
defer pool.Close()
key, _ := crypto.GenerateKey()
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000))
tx := pricedTransaction(0, 100000, big.NewInt(3), key)
pool.SetGasTip(big.NewInt(tx.GasPrice().Int64()))
// yo := pool.Add([]*types.Transaction{tx}, true, false)[0]
// t.Fatal(yo)
if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; err != nil {
t.Fatalf("TxValidation enforced in default config despite being disabled by default")
}
// Modifying local config to enable custom validation
poolWithCustomValidationConfig := DefaultConfig
poolWithCustomValidationConfig.CustomValidationEnabled = true
poolWithCustomValidationConfig.NoLocals = true
poolWithCustomValidation := New(poolWithCustomValidationConfig, blockchain)
poolWithCustomValidation.Init(new(big.Int).SetUint64(poolWithCustomValidationConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
defer poolWithCustomValidation.Close()
testAddBalance(poolWithCustomValidation, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000))
poolWithCustomValidation.SetGasTip(big.NewInt(tx.GasPrice().Int64()))
if err := poolWithCustomValidation.Add([]*types.Transaction{tx}, true, false)[0]; !errors.Is(err, txpool.ErrCustomValidationFailed) {
t.Fatalf("Custom TxValidation not enforced")
}
}
// Tests that setting the transaction pool gas price to a higher value correctly
// discards everything cheaper (legacy & dynamic fee) than that and moves any
// gapped transactions back from the pending pool to the queue.

View file

@ -40,6 +40,9 @@ type ValidationOptions struct {
MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool
}
type CustomValidationOptions struct {
}
// ValidateTransaction is a helper method to check whether a transaction is valid
// according to the consensus rules, but does not check state-dependent validation
// (balance, nonce, etc).
@ -245,3 +248,10 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
}
return nil
}
// FIXME add proper explanation (Kirill)
func ValidateTransactionWithCustomValidator(tx *types.Transaction, head *types.Header, signer types.Signer, opts *CustomValidationOptions) error {
// Ensure transactions not implemented by the calling pool are rejected
return ErrCustomValidationFailed
// return nil
}