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
|
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
|
||||||
|
|
||||||
CustomValidationEnabled bool
|
CustomValidationEnabled bool
|
||||||
|
CustomValidator txpool.CustomValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig contains the default configurations for the transaction pool.
|
// 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)
|
log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime)
|
||||||
conf.Lifetime = DefaultConfig.Lifetime
|
conf.Lifetime = DefaultConfig.Lifetime
|
||||||
}
|
}
|
||||||
|
if config.CustomValidationEnabled && conf.CustomValidator == nil {
|
||||||
|
log.Warn("Custom transaction validator is enabled but not configured")
|
||||||
|
}
|
||||||
return conf
|
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 {
|
func (pool *LegacyPool) validateTxWithCustomValidator(tx *types.Transaction, local bool) error {
|
||||||
if pool.config.CustomValidationEnabled {
|
if pool.config.CustomValidationEnabled {
|
||||||
opts := &txpool.CustomValidationOptions{}
|
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
|
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
|
// Tests that setting the transaction pool gas price to a higher value correctly
|
||||||
// discards everything cheaper (legacy & dynamic fee) than that and moves any
|
// discards everything cheaper (legacy & dynamic fee) than that and moves any
|
||||||
// gapped transactions back from the pending pool to the queue.
|
// 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
|
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
|
// ValidateTransaction is a helper method to check whether a transaction is valid
|
||||||
// according to the consensus rules, but does not check state-dependent validation
|
// according to the consensus rules, but does not check state-dependent validation
|
||||||
// (balance, nonce, etc).
|
// (balance, nonce, etc).
|
||||||
|
|
@ -248,10 +245,3 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
|
||||||
}
|
}
|
||||||
return nil
|
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