mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
feat: migrate setcode tx upstream changes (#1175)
* internal/ethapi: exclude 7702 authorities from result in eth_createAccessList * txpool changes * bump version * migrate a comment change
This commit is contained in:
parent
7b56ff1d66
commit
0d72990d8e
6 changed files with 197 additions and 79 deletions
|
|
@ -486,7 +486,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
|
|
||||||
// validateAuthorization validates an EIP-7702 authorization against the state.
|
// validateAuthorization validates an EIP-7702 authorization against the state.
|
||||||
func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, preCode []byte, err error) {
|
func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, preCode []byte, err error) {
|
||||||
// Verify chain ID is 0 or equal to current chain ID.
|
// Verify chain ID is null or equal to current chain ID.
|
||||||
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
|
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
|
||||||
return authority, nil, ErrAuthorizationWrongChainID
|
return authority, nil, ErrAuthorizationWrongChainID
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,10 @@ var (
|
||||||
// transactions is reached for specific accounts.
|
// transactions is reached for specific accounts.
|
||||||
ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated 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
|
// ErrAuthorityReserved is returned if a transaction has an authorization
|
||||||
// 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.
|
||||||
|
|
@ -1909,36 +1913,50 @@ func (pool *TxPool) calculateTxsLifecycle(txs types.Transactions, t time.Time) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkDelegationLimit determines if the tx sender is delegated or has a
|
||||||
|
// pending delegation, and if so, ensures they have at most one in-flight
|
||||||
|
// **executable** transaction, e.g. disallow stacked and gapped transactions
|
||||||
|
// from the account.
|
||||||
|
func (pool *TxPool) checkDelegationLimit(from common.Address, tx *types.Transaction) error {
|
||||||
|
// Short circuit if the sender has neither delegation nor pending delegation.
|
||||||
|
if pool.currentState.GetKeccakCodeHash(from) == codehash.EmptyKeccakCodeHash && 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.Overlaps(tx) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ErrInflightTxLimitReached
|
||||||
|
}
|
||||||
|
|
||||||
// validateAuth verifies that the transaction complies with code authorization
|
// validateAuth verifies that the transaction complies with code authorization
|
||||||
// restrictions brought by SetCode transaction type.
|
// restrictions brought by SetCode transaction type.
|
||||||
func (pool *TxPool) validateAuth(from common.Address, tx *types.Transaction) error {
|
func (pool *TxPool) validateAuth(from common.Address, tx *types.Transaction) error {
|
||||||
// Allow at most one in-flight tx for delegated accounts or those with a
|
// Allow at most one in-flight tx for delegated accounts or those with a
|
||||||
// pending authorization.
|
// pending authorization.
|
||||||
if pool.currentState.GetKeccakCodeHash(from) != codehash.EmptyKeccakCodeHash || len(pool.all.auths[from]) != 0 {
|
if err := pool.checkDelegationLimit(from, tx); err != nil {
|
||||||
var (
|
return err
|
||||||
count int
|
|
||||||
exists bool
|
|
||||||
)
|
|
||||||
pending := pool.pending[from]
|
|
||||||
if pending != nil {
|
|
||||||
count += pending.Len()
|
|
||||||
exists = pending.Overlaps(tx)
|
|
||||||
}
|
}
|
||||||
queue := pool.queue[from]
|
// For symmetry, allow at most one in-flight tx for any authority with a
|
||||||
if queue != nil {
|
// pending transaction.
|
||||||
count += queue.Len()
|
|
||||||
exists = exists || queue.Overlaps(tx)
|
|
||||||
}
|
|
||||||
// Replace the existing in-flight transaction for delegated accounts
|
|
||||||
// are still supported
|
|
||||||
if count >= 1 && !exists {
|
|
||||||
return ErrInflightTxLimitReached
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Authorities cannot conflict with any pending or queued transactions.
|
|
||||||
if auths := tx.SetCodeAuthorities(); len(auths) > 0 {
|
if auths := tx.SetCodeAuthorities(); len(auths) > 0 {
|
||||||
for _, auth := range auths {
|
for _, auth := range auths {
|
||||||
if pool.pending[auth] != nil || pool.queue[auth] != nil {
|
var count int
|
||||||
|
if pending := pool.pending[auth]; pending != nil {
|
||||||
|
count += pending.Len()
|
||||||
|
}
|
||||||
|
if queue := pool.queue[auth]; queue != nil {
|
||||||
|
count += queue.Len()
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
return ErrAuthorityReserved
|
return ErrAuthorityReserved
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2722,22 +2722,27 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// Check that only one in-flight transaction is allowed for accounts
|
// Check that only one in-flight transaction is allowed for accounts
|
||||||
// with delegation set. Also verify the accepted transaction can be
|
// with delegation set.
|
||||||
// replaced by fee.
|
name: "accept-one-inflight-tx-of-delegated-account",
|
||||||
name: "only-one-in-flight",
|
|
||||||
pending: 1,
|
pending: 1,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
aa := common.Address{0xaa, 0xaa}
|
aa := common.Address{0xaa, 0xaa}
|
||||||
statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...))
|
statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...))
|
||||||
statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)})
|
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.
|
// Send transactions. First is accepted, second is rejected.
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
// Second and further transactions shall be rejected
|
||||||
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) {
|
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)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
}
|
}
|
||||||
// Also check gapped transaction.
|
// Check gapped transaction again.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) {
|
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)
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
}
|
}
|
||||||
|
|
@ -2745,6 +2750,70 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
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 {
|
||||||
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the delegation, avoid leaking state into the other tests
|
||||||
|
statedb.SetCode(addrA, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// This test is analogous to the previous one, but the delegation is pending
|
||||||
|
// instead of set.
|
||||||
|
name: "allow-one-tx-from-pooled-delegation",
|
||||||
|
pending: 2,
|
||||||
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
// Create a pending delegation request from B.
|
||||||
|
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
// First transaction from B is accepted.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
// Second transaction fails due to limit.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
|
}
|
||||||
|
// Replace by fee for first transaction from B works.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(2), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// This is the symmetric case of the previous one, where the delegation request
|
||||||
|
// is received after the transaction. The resulting state shall be the same.
|
||||||
|
name: "accept-authorization-from-sender-of-one-inflight-tx",
|
||||||
|
pending: 2,
|
||||||
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
// The first in-flight transaction is accepted.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add with pending delegation: %v", name, err)
|
||||||
|
}
|
||||||
|
// Delegation is accepted.
|
||||||
|
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
// The second in-flight transaction is rejected.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reject-authorization-from-sender-with-more-than-one-inflight-tx",
|
||||||
|
pending: 2,
|
||||||
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
// Submit two transactions.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add with pending delegation: %v", name, err)
|
||||||
|
}
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add with pending delegation: %v", name, err)
|
||||||
|
}
|
||||||
|
// Delegation rejected since two txs are already in-flight.
|
||||||
|
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); !errors.Is(err, ErrAuthorityReserved) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrAuthorityReserved, err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -2752,7 +2821,7 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
pending: 2,
|
pending: 2,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
// Send two transactions where the first has no conflicting delegations and
|
// Send two transactions where the first has no conflicting delegations and
|
||||||
// the second should be allowed despite conflicting with the authorities in 1).
|
// the second should be allowed despite conflicting with the authorities in the first.
|
||||||
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil {
|
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
@ -2761,28 +2830,10 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "allow-one-tx-from-pooled-delegation",
|
|
||||||
pending: 2,
|
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
|
||||||
// Verify C cannot originate another transaction when it has a pooled delegation.
|
|
||||||
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyC}})); err != nil {
|
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
|
||||||
}
|
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyC)); err != nil {
|
|
||||||
t.Fatalf("%s: failed to add with pending delegation: %v", name, err)
|
|
||||||
}
|
|
||||||
// Also check gapped transaction is rejected.
|
|
||||||
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, ErrInflightTxLimitReached) {
|
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "replace-by-fee-setcode-tx",
|
name: "replace-by-fee-setcode-tx",
|
||||||
pending: 1,
|
pending: 1,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
// 4. Fee bump the setcode tx send.
|
|
||||||
if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil {
|
if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
@ -2793,42 +2844,87 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allow-tx-from-replaced-authority",
|
name: "allow-tx-from-replaced-authority",
|
||||||
pending: 2,
|
pending: 3,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
// Fee bump with a different auth list. Make sure that unlocks the authorities.
|
// Send transaction from A with B as an authority.
|
||||||
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
// Replace transaction with another having C as an authority.
|
||||||
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(3000), uint256.NewInt(300), keyA, []unsignedAuth{{0, keyC}})); err != nil {
|
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(3000), uint256.NewInt(300), keyA, []unsignedAuth{{0, keyC}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
// Now send a regular tx from B.
|
// B should not be considred as having an in-flight delegation, so
|
||||||
|
// should allow more than one pooled transaction.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyB)); err != nil {
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyB)); err != nil {
|
||||||
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(10), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// This test is analogous to the previous one, but the the replaced
|
||||||
|
// transaction is self-sponsored.
|
||||||
name: "allow-tx-from-replaced-self-sponsor-authority",
|
name: "allow-tx-from-replaced-self-sponsor-authority",
|
||||||
pending: 2,
|
pending: 3,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
// Reset the delegation
|
||||||
|
statedb.SetCode(addrA, nil)
|
||||||
|
|
||||||
|
// Send transaction from A with A as an authority.
|
||||||
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyA}})); err != nil {
|
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyA}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
// Replace transaction with a transaction with B as an authority.
|
||||||
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
// Now send a regular tx from keyA.
|
// The one in-flight transaction limit from A no longer applies, so we
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyA)); err != nil {
|
// can stack a second transaction for the account.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyA)); err != nil {
|
||||||
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
// Make sure we can still send from keyB.
|
// B should still be able to send transactions.
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyB)); err != nil {
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyB)); err != nil {
|
||||||
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
}
|
}
|
||||||
|
// However B still has the limitation to one in-flight transaction.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "replacements-respect-inflight-tx-count",
|
||||||
|
pending: 2,
|
||||||
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
// Send transaction from A with B as an authority.
|
||||||
|
if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
// Send two transactions from B. Only the first should be accepted due
|
||||||
|
// to in-flight limit.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to add remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
|
}
|
||||||
|
// Replace the in-flight transaction from B.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(30), keyB)); err != nil {
|
||||||
|
t.Fatalf("%s: failed to replace with remote transaction: %v", name, err)
|
||||||
|
}
|
||||||
|
// Ensure the in-flight limit for B is still in place.
|
||||||
|
if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, ErrInflightTxLimitReached) {
|
||||||
|
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Since multiple authorizations can be pending simultaneously, replacing
|
||||||
|
// one of them should not break the one in-flight-transaction limit.
|
||||||
name: "track-multiple-conflicting-delegations",
|
name: "track-multiple-conflicting-delegations",
|
||||||
pending: 3,
|
pending: 3,
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
||||||
|
|
@ -2853,19 +2949,6 @@ func TestSetCodeTransactions(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "reject-delegation-from-pending-account",
|
|
||||||
pending: 1,
|
|
||||||
run: func(name string, pool *TxPool, statedb *state.StateDB) {
|
|
||||||
// Attempt to submit a delegation from an account with a pending tx.
|
|
||||||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil {
|
|
||||||
t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err)
|
|
||||||
}
|
|
||||||
if err, want := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})), ErrAuthorityReserved; !errors.Is(err, want) {
|
|
||||||
t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "nonce-gapped-invalid-auth-does-not-block-pending-tx",
|
name: "nonce-gapped-invalid-auth-does-not-block-pending-tx",
|
||||||
pending: 1,
|
pending: 1,
|
||||||
|
|
|
||||||
|
|
@ -115,16 +115,10 @@ type AccessListTracer struct {
|
||||||
// NewAccessListTracer creates a new tracer that can generate AccessLists.
|
// NewAccessListTracer creates a new tracer that can generate AccessLists.
|
||||||
// An optional AccessList can be specified to occupy slots and addresses in
|
// An optional AccessList can be specified to occupy slots and addresses in
|
||||||
// the resulting accesslist.
|
// the resulting accesslist.
|
||||||
func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompiles []common.Address) *AccessListTracer {
|
func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Address]struct{}) *AccessListTracer {
|
||||||
excl := map[common.Address]struct{}{
|
|
||||||
from: {}, to: {},
|
|
||||||
}
|
|
||||||
for _, addr := range precompiles {
|
|
||||||
excl[addr] = struct{}{}
|
|
||||||
}
|
|
||||||
list := newAccessList()
|
list := newAccessList()
|
||||||
for _, al := range acl {
|
for _, al := range acl {
|
||||||
if _, ok := excl[al.Address]; !ok {
|
if _, ok := addressesToExclude[al.Address]; !ok {
|
||||||
list.addAddress(al.Address)
|
list.addAddress(al.Address)
|
||||||
}
|
}
|
||||||
for _, slot := range al.StorageKeys {
|
for _, slot := range al.StorageKeys {
|
||||||
|
|
@ -132,7 +126,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &AccessListTracer{
|
return &AccessListTracer{
|
||||||
excl: excl,
|
excl: addressesToExclude,
|
||||||
list: list,
|
list: list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1536,10 +1536,33 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
// Retrieve the precompiles since they don't need to be added to the access list
|
// Retrieve the precompiles since they don't need to be added to the access list
|
||||||
precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, header.Time))
|
precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, header.Time))
|
||||||
|
|
||||||
|
// addressesToExclude contains sender, receiver, precompiles and valid authorizations
|
||||||
|
addressesToExclude := map[common.Address]struct{}{args.from(): {}, to: {}}
|
||||||
|
for _, addr := range precompiles {
|
||||||
|
addressesToExclude[addr] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent redundant operations if args contain more authorizations than EVM may handle
|
||||||
|
maxAuthorizations := uint64(*args.Gas) / params.CallNewAccountGas
|
||||||
|
if uint64(len(args.AuthorizationList)) > maxAuthorizations {
|
||||||
|
return nil, 0, nil, errors.New("insufficient gas to process all authorizations")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, auth := range args.AuthorizationList {
|
||||||
|
// Duplicating stateTransition.validateAuthorization() logic
|
||||||
|
if (!auth.ChainID.IsZero() && auth.ChainID.CmpBig(b.ChainConfig().ChainID) != 0) || auth.Nonce+1 < auth.Nonce {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if authority, err := auth.Authority(); err == nil {
|
||||||
|
addressesToExclude[authority] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create an initial tracer
|
// Create an initial tracer
|
||||||
prevTracer := vm.NewAccessListTracer(nil, args.from(), to, precompiles)
|
prevTracer := vm.NewAccessListTracer(nil, addressesToExclude)
|
||||||
if args.AccessList != nil {
|
if args.AccessList != nil {
|
||||||
prevTracer = vm.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles)
|
prevTracer = vm.NewAccessListTracer(*args.AccessList, addressesToExclude)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
// Retrieve the current access list to expand
|
// Retrieve the current access list to expand
|
||||||
|
|
@ -1565,7 +1588,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the transaction with the access list tracer
|
// Apply the transaction with the access list tracer
|
||||||
tracer := vm.NewAccessListTracer(accessList, args.from(), to, precompiles)
|
tracer := vm.NewAccessListTracer(accessList, addressesToExclude)
|
||||||
config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true}
|
config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true}
|
||||||
vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config)
|
vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor version component of the current release
|
VersionMinor = 8 // Minor version component of the current release
|
||||||
VersionPatch = 42 // Patch version component of the current release
|
VersionPatch = 43 // Patch version component of the current release
|
||||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue