mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Custom tx validator logic WIP
This commit is contained in:
parent
65e11e1ee1
commit
59008b6541
5 changed files with 137 additions and 57 deletions
42
core/txpool/custom_validator.go
Normal file
42
core/txpool/custom_validator.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package txpool
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type CustomValidationOptions struct {
|
||||
}
|
||||
|
||||
type CustomValidator interface {
|
||||
Validate(tx *types.Transaction, head *types.Header, signer types.Signer, opts *CustomValidationOptions) error
|
||||
}
|
||||
|
||||
type CustomValidatorHypernative struct {
|
||||
Config *CustomValidatorConfigHypernative
|
||||
}
|
||||
|
||||
type CustomValidatorConfigHypernative struct {
|
||||
BannedAddresses []common.Address
|
||||
}
|
||||
|
||||
func NewHypernativeValidator(config *CustomValidatorConfigHypernative) CustomValidator {
|
||||
return &CustomValidatorHypernative{
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *CustomValidatorHypernative) Validate(tx *types.Transaction, head *types.Header, signer types.Signer, opts *CustomValidationOptions) error {
|
||||
// ban certain senders just for the fun of it
|
||||
if address, err := signer.Sender(tx); err == nil {
|
||||
for _, bannedAddress := range v.Config.BannedAddresses {
|
||||
if address == bannedAddress {
|
||||
return ErrCustomValidationFailed
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -136,6 +136,7 @@ type Config struct {
|
|||
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
|
||||
|
||||
CustomValidationEnabled bool
|
||||
CustomValidator txpool.CustomValidator
|
||||
}
|
||||
|
||||
// DefaultConfig contains the default configurations for the transaction pool.
|
||||
|
|
@ -192,6 +193,9 @@ func (config *Config) sanitize() Config {
|
|||
log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime)
|
||||
conf.Lifetime = DefaultConfig.Lifetime
|
||||
}
|
||||
if config.CustomValidationEnabled && conf.CustomValidator == nil {
|
||||
log.Warn("Custom transaction validator is enabled but not configured")
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
|
|
@ -613,7 +617,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
|
|||
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 {
|
||||
if err := pool.config.CustomValidator.Validate(tx, pool.currentHead.Load(), pool.signer, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
90
core/txpool/legacypool/legacypool_custom_validator_test.go
Normal file
90
core/txpool/legacypool/legacypool_custom_validator_test.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package legacypool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Max returns the larger of x or y.
|
||||
func max(x, y int64) int64 {
|
||||
if x < y {
|
||||
return y
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func min(x, y int64) int64 {
|
||||
if x > y {
|
||||
return y
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
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()))
|
||||
|
||||
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
|
||||
|
||||
bannedKey, _ := crypto.GenerateKey()
|
||||
bannedTx := pricedTransaction(0, 990000, big.NewInt(4), bannedKey)
|
||||
|
||||
bannedAddresses := []common.Address{crypto.PubkeyToAddress(bannedKey.PublicKey)}
|
||||
hypernativeCustomValidatorConfig := &txpool.CustomValidatorConfigHypernative{
|
||||
BannedAddresses: bannedAddresses,
|
||||
}
|
||||
poolWithCustomValidationConfig.CustomValidator = txpool.NewHypernativeValidator(hypernativeCustomValidatorConfig)
|
||||
|
||||
poolWithCustomValidation := New(poolWithCustomValidationConfig, blockchain)
|
||||
poolWithCustomValidation.Init(new(big.Int).SetUint64(poolWithCustomValidationConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer poolWithCustomValidation.Close()
|
||||
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(bannedKey.PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(poolWithCustomValidation, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000))
|
||||
|
||||
gasTip := min(tx.GasPrice().Int64(), bannedTx.GasPrice().Int64())
|
||||
poolWithCustomValidation.SetGasTip(big.NewInt(gasTip))
|
||||
|
||||
if err := poolWithCustomValidation.Add([]*types.Transaction{tx}, true, false)[0]; err != nil {
|
||||
t.Fatalf("Custom TxValidation enforced wrongly")
|
||||
}
|
||||
|
||||
if err := poolWithCustomValidation.Add([]*types.Transaction{bannedTx}, true, false)[0]; !errors.Is(err, txpool.ErrCustomValidationFailed) {
|
||||
t.Fatalf("Custom TxValidation not enforced for banned address")
|
||||
}
|
||||
}
|
||||
|
|
@ -1536,52 +1536,6 @@ 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.
|
||||
|
|
|
|||
|
|
@ -40,9 +40,6 @@ 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).
|
||||
|
|
@ -248,10 +245,3 @@ 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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue