mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
core/txpool/legacypool: reject gapped tx from delegated account
This commit is contained in:
parent
7d99f7df00
commit
bdc3e5d72f
2 changed files with 39 additions and 23 deletions
|
|
@ -66,6 +66,10 @@ var (
|
|||
// transactions is reached for specific accounts.
|
||||
ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts")
|
||||
|
||||
// ErrOutOfOrderTxFromDelegated is returned when the transaction with gapped
|
||||
// nonce received from the accounts with delegation or pending delegation.
|
||||
ErrOutOfOrderTxFromDelegated = errors.New("gapped-nonce tx from delegated accounts")
|
||||
|
||||
// ErrAuthorityReserved is returned if a transaction has an authorization
|
||||
// signed by an address which already has in-flight transactions known to the
|
||||
// pool.
|
||||
|
|
@ -605,33 +609,40 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error {
|
|||
return pool.validateAuth(tx)
|
||||
}
|
||||
|
||||
// limitTxFromDelegated ensures the account with either delegation or pending
|
||||
// delegation can at most send one inflight **executable** transaction.
|
||||
func (pool *LegacyPool) limitTxFromDelegated(tx *types.Transaction) error {
|
||||
from, _ := types.Sender(pool.signer, tx) // validated
|
||||
|
||||
// Short circuit if the sender has neither delegation nor pending delegation.
|
||||
if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && len(pool.all.auths[from]) == 0 {
|
||||
return nil
|
||||
}
|
||||
pending := pool.pending[from]
|
||||
if pending == nil {
|
||||
// Transaction with gapped nonce is not supported for delegated accounts
|
||||
if pool.pendingNonces.get(from) != tx.Nonce() {
|
||||
return ErrOutOfOrderTxFromDelegated
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Transaction replacement is supported
|
||||
if pending.Contains(tx.Nonce()) {
|
||||
return nil
|
||||
}
|
||||
if pending.Len() >= 1 {
|
||||
return ErrInflightTxLimitReached
|
||||
}
|
||||
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()
|
||||
exists = exists || queue.Contains(tx.Nonce())
|
||||
}
|
||||
// Replace the existing in-flight transaction for delegated accounts
|
||||
// are still supported
|
||||
if count >= 1 && !exists {
|
||||
return ErrInflightTxLimitReached
|
||||
}
|
||||
if err := pool.limitTxFromDelegated(tx); err != nil {
|
||||
return err
|
||||
}
|
||||
// Authorities cannot conflict with any pending or queued transactions.
|
||||
if auths := tx.SetCodeAuthorities(); len(auths) > 0 {
|
||||
|
|
|
|||
|
|
@ -2262,6 +2262,11 @@ func TestSetCodeTransactions(t *testing.T) {
|
|||
aa := common.Address{0xaa, 0xaa}
|
||||
statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...))
|
||||
statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)})
|
||||
|
||||
// Send gapped transaction, it should be rejected
|
||||
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrOutOfOrderTxFromDelegated) {
|
||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrOutOfOrderTxFromDelegated, err)
|
||||
}
|
||||
// Send transactions. First is accepted, second is rejected.
|
||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil {
|
||||
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||
|
|
@ -2269,7 +2274,7 @@ func TestSetCodeTransactions(t *testing.T) {
|
|||
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||
}
|
||||
// Also check gapped transaction.
|
||||
// Also check gapped transaction again
|
||||
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue