mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-13 23:43:47 +00:00
core/txpool: move setcode tx validation into legacyPool
This commit is contained in:
parent
2a81bbaa4f
commit
41e765004c
4 changed files with 57 additions and 41 deletions
|
|
@ -38,6 +38,10 @@ var (
|
||||||
// allowed by a pool for a single account.
|
// allowed by a pool for a single account.
|
||||||
ErrAccountLimitExceeded = errors.New("account limit exceeded")
|
ErrAccountLimitExceeded = errors.New("account limit exceeded")
|
||||||
|
|
||||||
|
// ErrInflightTxLimitReached is returned when the maximum number of in-flight
|
||||||
|
// transactions is reached for specific accounts.
|
||||||
|
ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts")
|
||||||
|
|
||||||
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
|
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
|
||||||
// maximum allowance of the current block.
|
// maximum allowance of the current block.
|
||||||
ErrGasLimit = errors.New("exceeds block gas limit")
|
ErrGasLimit = errors.New("exceeds block gas limit")
|
||||||
|
|
@ -65,8 +69,4 @@ var (
|
||||||
// signed by an address which already has in-flight transactions known to the
|
// signed by an address which already has in-flight transactions known to the
|
||||||
// pool.
|
// pool.
|
||||||
ErrAuthorityReserved = errors.New("authority already reserved")
|
ErrAuthorityReserved = errors.New("authority already reserved")
|
||||||
|
|
||||||
// ErrAuthorityNonce is returned if a transaction has an authorization with
|
|
||||||
// a nonce that is not currently valid for the authority.
|
|
||||||
ErrAuthorityNonceTooLow = errors.New("authority nonce too low")
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -581,11 +581,6 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error {
|
||||||
if list := pool.queue[addr]; list != nil {
|
if list := pool.queue[addr]; list != nil {
|
||||||
have += list.Len()
|
have += list.Len()
|
||||||
}
|
}
|
||||||
if pool.currentState.GetCodeHash(addr) != types.EmptyCodeHash || len(pool.all.auths[addr]) != 0 {
|
|
||||||
// Allow at most one in-flight tx for delegated accounts or those with
|
|
||||||
// a pending authorization.
|
|
||||||
return have, max(0, 1-have)
|
|
||||||
}
|
|
||||||
return have, math.MaxInt
|
return have, math.MaxInt
|
||||||
},
|
},
|
||||||
ExistingExpenditure: func(addr common.Address) *big.Int {
|
ExistingExpenditure: func(addr common.Address) *big.Int {
|
||||||
|
|
@ -602,18 +597,6 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
KnownConflicts: func(from common.Address, auths []common.Address) []common.Address {
|
|
||||||
var conflicts []common.Address
|
|
||||||
// Authorities cannot conflict with any pending or queued transactions.
|
|
||||||
for _, addr := range auths {
|
|
||||||
if list := pool.pending[addr]; list != nil {
|
|
||||||
conflicts = append(conflicts, addr)
|
|
||||||
} else if list := pool.queue[addr]; list != nil {
|
|
||||||
conflicts = append(conflicts, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conflicts
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil {
|
if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -621,6 +604,47 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateAuth verifies that the transaction complies with code authorization
|
||||||
|
// restrictions brought by SetCode transaction type.
|
||||||
|
func (pool *LegacyPool) validateAuth(tx *types.Transaction) error {
|
||||||
|
from, _ := types.Sender(pool.signer, tx) // validated
|
||||||
|
|
||||||
|
// Allow at most one in-flight tx for delegated accounts or those with a
|
||||||
|
// pending authorization.
|
||||||
|
if pool.currentState.GetCodeHash(from) != types.EmptyCodeHash || len(pool.all.auths[from]) != 0 {
|
||||||
|
var (
|
||||||
|
count int
|
||||||
|
exists bool
|
||||||
|
)
|
||||||
|
pending := pool.pending[from]
|
||||||
|
if pending != nil {
|
||||||
|
count += pending.Len()
|
||||||
|
exists = pending.Contains(tx.Nonce())
|
||||||
|
}
|
||||||
|
queue := pool.queue[from]
|
||||||
|
if queue != nil {
|
||||||
|
count += queue.Len()
|
||||||
|
if !exists {
|
||||||
|
exists = queue.Contains(tx.Nonce())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Replace the existing inflight transaction for delegated accounts
|
||||||
|
// are still supported
|
||||||
|
if count >= 1 && !exists {
|
||||||
|
return txpool.ErrInflightTxLimitReached
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Authorities cannot conflict with any pending or queued transactions.
|
||||||
|
if auths := tx.SetCodeAuthorities(); len(auths) > 0 {
|
||||||
|
for _, auth := range auths {
|
||||||
|
if pool.pending[auth] != nil || pool.queue[auth] != nil {
|
||||||
|
return txpool.ErrAuthorityReserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// add validates a transaction and inserts it into the non-executable queue for later
|
// add validates a transaction and inserts it into the non-executable queue for later
|
||||||
// pending promotion and execution. If the transaction is a replacement for an already
|
// pending promotion and execution. If the transaction is a replacement for an already
|
||||||
// pending or queued one, it overwrites the previous transaction if its price is higher.
|
// pending or queued one, it overwrites the previous transaction if its price is higher.
|
||||||
|
|
@ -639,6 +663,11 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) {
|
||||||
invalidTxMeter.Mark(1)
|
invalidTxMeter.Mark(1)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
if err := pool.validateAuth(tx); err != nil {
|
||||||
|
log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
|
||||||
|
invalidTxMeter.Mark(1)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
// already validated by this point
|
// already validated by this point
|
||||||
from, _ := types.Sender(pool.signer, tx)
|
from, _ := types.Sender(pool.signer, tx)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2248,12 +2248,12 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil {
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil {
|
||||||
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) {
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) {
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err)
|
||||||
}
|
}
|
||||||
// Also check gapped transaction.
|
// Also check gapped transaction.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) {
|
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) {
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err)
|
||||||
}
|
}
|
||||||
// Replace by fee.
|
// Replace by fee.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil {
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil {
|
||||||
|
|
@ -2287,8 +2287,8 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
t.Fatalf("%s: failed to add with pending delegatio: %v", name, err)
|
t.Fatalf("%s: failed to add with pending delegatio: %v", name, err)
|
||||||
}
|
}
|
||||||
// Also check gapped transaction is rejected.
|
// Also check gapped transaction is rejected.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrAccountLimitExceeded) {
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrInflightTxLimitReached) {
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -2363,7 +2363,7 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil {
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil {
|
||||||
t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err)
|
t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err)
|
||||||
}
|
}
|
||||||
if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrAccountLimitExceeded; !errors.Is(err, want) {
|
if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrInflightTxLimitReached; !errors.Is(err, want) {
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,6 @@ type ValidationOptionsWithState struct {
|
||||||
// ExistingCost is a mandatory callback to retrieve an already pooled
|
// ExistingCost is a mandatory callback to retrieve an already pooled
|
||||||
// transaction's cost with the given nonce to check for overdrafts.
|
// transaction's cost with the given nonce to check for overdrafts.
|
||||||
ExistingCost func(addr common.Address, nonce uint64) *big.Int
|
ExistingCost func(addr common.Address, nonce uint64) *big.Int
|
||||||
|
|
||||||
// KnownConflicts is an optional callback which iterates over the list of
|
|
||||||
// addresses and returns all addresses known to the pool with in-flight
|
|
||||||
// transactions.
|
|
||||||
KnownConflicts func(sender common.Address, authorizers []common.Address) []common.Address
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateTransactionWithState is a helper method to check whether a transaction
|
// ValidateTransactionWithState is a helper method to check whether a transaction
|
||||||
|
|
@ -276,14 +271,6 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
|
||||||
if used, left := opts.UsedAndLeftSlots(from); left <= 0 {
|
if used, left := opts.UsedAndLeftSlots(from); left <= 0 {
|
||||||
return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used)
|
return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify no authorizations will invalidate existing transactions known to
|
|
||||||
// the pool.
|
|
||||||
if opts.KnownConflicts != nil {
|
|
||||||
if conflicts := opts.KnownConflicts(from, tx.SetCodeAuthorities()); len(conflicts) > 0 {
|
|
||||||
return fmt.Errorf("%w: authorization conflicts with other known tx", ErrAuthorityReserved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue