@@ -24,6 +24,7 @@ import (
2424 "math/big"
2525 "math/rand"
2626 "os"
27+ "slices"
2728 "sync/atomic"
2829 "testing"
2930 "time"
@@ -156,6 +157,10 @@ func pricedSetCodeTx(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, ke
156157 })
157158 authList = append (authList , auth )
158159 }
160+ return pricedSetCodeTxWithAuth (nonce , gaslimit , gasFee , tip , key , authList )
161+ }
162+
163+ func pricedSetCodeTxWithAuth (nonce uint64 , gaslimit uint64 , gasFee , tip * uint256.Int , key * ecdsa.PrivateKey , authList []types.SetCodeAuthorization ) * types.Transaction {
159164 return types .MustSignNewTx (key , types .LatestSignerForChainID (params .TestChainConfig .ChainID ), & types.SetCodeTx {
160165 ChainID : uint256 .MustFromBig (params .TestChainConfig .ChainID ),
161166 Nonce : nonce ,
@@ -214,6 +219,34 @@ func validateTxPoolInternals(pool *TxPool) error {
214219 return fmt .Errorf ("pending nonce mismatch: have %v, want %v" , nonce , last + 1 )
215220 }
216221 }
222+ // Ensure all auths in pool are tracked
223+ for _ , tx := range pool .all .locals {
224+ for _ , addr := range tx .SetCodeAuthorities () {
225+ list := pool .all .auths [addr ]
226+ if i := slices .Index (list , tx .Hash ()); i < 0 {
227+ return fmt .Errorf ("authority not tracked: addr %s, tx %s" , addr , tx .Hash ())
228+ }
229+ }
230+ }
231+ for _ , tx := range pool .all .remotes {
232+ for _ , addr := range tx .SetCodeAuthorities () {
233+ list := pool .all .auths [addr ]
234+ if i := slices .Index (list , tx .Hash ()); i < 0 {
235+ return fmt .Errorf ("authority not tracked: addr %s, tx %s" , addr , tx .Hash ())
236+ }
237+ }
238+ }
239+ // Ensure all auths in pool have an associated tx in locals or remotes.
240+ for addr , hashes := range pool .all .auths {
241+ for _ , hash := range hashes {
242+ _ , inLocals := pool .all .locals [hash ]
243+ _ , inRemotes := pool .all .remotes [hash ]
244+
245+ if ! inLocals && ! inRemotes {
246+ return fmt .Errorf ("dangling authority, missing originating tx: addr %s, hash %s" , addr , hash .Hex ())
247+ }
248+ }
249+ }
217250 return nil
218251}
219252
@@ -2701,12 +2734,12 @@ func TestSetCodeTransactions(t *testing.T) {
27012734 if err := pool .addRemoteSync (pricedTransaction (0 , 100000 , big .NewInt (1 ), keyA )); err != nil {
27022735 t .Fatalf ("%s: failed to add remote transaction: %v" , name , err )
27032736 }
2704- if err := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1 ), keyA )); ! errors .Is (err , ErrAccountLimitExceeded ) {
2705- t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrAccountLimitExceeded , err )
2737+ if err := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1 ), keyA )); ! errors .Is (err , ErrInflightTxLimitReached ) {
2738+ t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrInflightTxLimitReached , err )
27062739 }
27072740 // Also check gapped transaction.
2708- if err := pool .addRemoteSync (pricedTransaction (2 , 100000 , big .NewInt (1 ), keyA )); ! errors .Is (err , ErrAccountLimitExceeded ) {
2709- t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrAccountLimitExceeded , err )
2741+ if err := pool .addRemoteSync (pricedTransaction (2 , 100000 , big .NewInt (1 ), keyA )); ! errors .Is (err , ErrInflightTxLimitReached ) {
2742+ t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrInflightTxLimitReached , err )
27102743 }
27112744 // Replace by fee.
27122745 if err := pool .addRemoteSync (pricedTransaction (0 , 100000 , big .NewInt (10 ), keyA )); err != nil {
@@ -2740,8 +2773,8 @@ func TestSetCodeTransactions(t *testing.T) {
27402773 t .Fatalf ("%s: failed to add with pending delegation: %v" , name , err )
27412774 }
27422775 // Also check gapped transaction is rejected.
2743- if err := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1 ), keyC )); ! errors .Is (err , ErrAccountLimitExceeded ) {
2744- t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrAccountLimitExceeded , err )
2776+ if err := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1 ), keyC )); ! errors .Is (err , ErrInflightTxLimitReached ) {
2777+ t .Fatalf ("%s: error mismatch: want %v, have %v" , name , ErrInflightTxLimitReached , err )
27452778 }
27462779 },
27472780 },
@@ -2815,7 +2848,7 @@ func TestSetCodeTransactions(t *testing.T) {
28152848 if err := pool .addRemoteSync (pricedTransaction (0 , 100000 , big .NewInt (1000 ), keyC )); err != nil {
28162849 t .Fatalf ("%s: failed to added single pooled for account with pending delegation: %v" , name , err )
28172850 }
2818- if err , want := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1000 ), keyC )), ErrAccountLimitExceeded ; ! errors .Is (err , want ) {
2851+ if err , want := pool .addRemoteSync (pricedTransaction (1 , 100000 , big .NewInt (1000 ), keyC )), ErrInflightTxLimitReached ; ! errors .Is (err , want ) {
28192852 t .Fatalf ("%s: error mismatch: want %v, have %v" , name , want , err )
28202853 }
28212854 },
@@ -2846,6 +2879,32 @@ func TestSetCodeTransactions(t *testing.T) {
28462879 }
28472880 },
28482881 },
2882+ {
2883+ name : "remove-hash-from-authority-tracker" ,
2884+ pending : 10 ,
2885+ run : func (name string , pool * TxPool , statedb * state.StateDB ) {
2886+ var keys []* ecdsa.PrivateKey
2887+ for i := 0 ; i < 30 ; i ++ {
2888+ key , _ := crypto .GenerateKey ()
2889+ keys = append (keys , key )
2890+ addr := crypto .PubkeyToAddress (key .PublicKey )
2891+ testAddBalance (pool , addr , big .NewInt (params .Ether ))
2892+ }
2893+ // Create a transactions with 3 unique auths so the lookup's auth map is
2894+ // filled with addresses.
2895+ for i := 0 ; i < 30 ; i += 3 {
2896+ if err := pool .addRemoteSync (pricedSetCodeTx (0 , 250000 , uint256 .NewInt (10 ), uint256 .NewInt (3 ), keys [i ], []unsignedAuth {{0 , keys [i ]}, {0 , keys [i + 1 ]}, {0 , keys [i + 2 ]}})); err != nil {
2897+ t .Fatalf ("%s: failed to add with remote setcode transaction: %v" , name , err )
2898+ }
2899+ }
2900+ // Replace one of the transactions with a normal transaction so that the
2901+ // original hash is removed from the tracker. The hash should be
2902+ // associated with 3 different authorities.
2903+ if err := pool .addRemoteSync (pricedTransaction (0 , 100000 , big .NewInt (1000 ), keys [0 ])); err != nil {
2904+ t .Fatalf ("%s: failed to replace with remote transaction: %v" , name , err )
2905+ }
2906+ },
2907+ },
28492908 } {
28502909 // Create the pool to test the status retrievals with
28512910 statedb , _ := state .New (common.Hash {}, state .NewDatabase (rawdb .NewMemoryDatabase ()), nil )
@@ -2875,6 +2934,64 @@ func TestSetCodeTransactions(t *testing.T) {
28752934 }
28762935}
28772936
2937+ func TestSetCodeTransactionsReorg (t * testing.T ) {
2938+ t .Parallel ()
2939+
2940+ // Create the pool to test the status retrievals with
2941+ statedb , _ := state .New (common.Hash {}, state .NewDatabase (rawdb .NewMemoryDatabase ()), nil )
2942+ blockchain := & testBlockChain {1000000 , statedb , new (event.Feed )}
2943+
2944+ pool := NewTxPool (testTxPoolConfig , params .TestChainConfig , blockchain )
2945+ defer pool .Stop ()
2946+
2947+ // Create the test accounts
2948+ var (
2949+ keyA , _ = crypto .GenerateKey ()
2950+ addrA = crypto .PubkeyToAddress (keyA .PublicKey )
2951+ )
2952+ testAddBalance (pool , addrA , big .NewInt (params .Ether ))
2953+ // Send an authorization for 0x42
2954+ var authList []types.SetCodeAuthorization
2955+ auth , _ := types .SignSetCode (keyA , types.SetCodeAuthorization {
2956+ ChainID : * uint256 .MustFromBig (params .TestChainConfig .ChainID ),
2957+ Address : common.Address {0x42 },
2958+ Nonce : 0 ,
2959+ })
2960+ authList = append (authList , auth )
2961+ if err := pool .addRemoteSync (pricedSetCodeTxWithAuth (0 , 250000 , uint256 .NewInt (10 ), uint256 .NewInt (3 ), keyA , authList )); err != nil {
2962+ t .Fatalf ("failed to add with remote setcode transaction: %v" , err )
2963+ }
2964+ // Simulate the chain moving
2965+ blockchain .statedb .SetNonce (addrA , 1 )
2966+ blockchain .statedb .SetCode (addrA , types .AddressToDelegation (auth .Address ))
2967+ <- pool .requestReset (nil , nil )
2968+ // Set an authorization for 0x00
2969+ auth , _ = types .SignSetCode (keyA , types.SetCodeAuthorization {
2970+ ChainID : * uint256 .MustFromBig (params .TestChainConfig .ChainID ),
2971+ Address : common.Address {},
2972+ Nonce : 0 ,
2973+ })
2974+ authList = append (authList , auth )
2975+ if err := pool .addRemoteSync (pricedSetCodeTxWithAuth (1 , 250000 , uint256 .NewInt (10 ), uint256 .NewInt (3 ), keyA , authList )); err != nil {
2976+ t .Fatalf ("failed to add with remote setcode transaction: %v" , err )
2977+ }
2978+ // Try to add a transactions in
2979+ if err := pool .addRemoteSync (pricedTransaction (2 , 100000 , big .NewInt (1000 ), keyA )); ! errors .Is (err , ErrInflightTxLimitReached ) {
2980+ t .Fatalf ("unexpected error %v, expecting %v" , err , ErrInflightTxLimitReached )
2981+ }
2982+ // Simulate the chain moving
2983+ blockchain .statedb .SetNonce (addrA , 2 )
2984+ blockchain .statedb .SetCode (addrA , nil )
2985+ <- pool .requestReset (nil , nil )
2986+ // Now send two transactions from addrA
2987+ if err := pool .addRemoteSync (pricedTransaction (2 , 100000 , big .NewInt (1000 ), keyA )); err != nil {
2988+ t .Fatalf ("failed to added single transaction: %v" , err )
2989+ }
2990+ if err := pool .addRemoteSync (pricedTransaction (3 , 100000 , big .NewInt (1000 ), keyA )); err != nil {
2991+ t .Fatalf ("failed to added single transaction: %v" , err )
2992+ }
2993+ }
2994+
28782995// Benchmarks the speed of validating the contents of the pending queue of the
28792996// transaction pool.
28802997func BenchmarkPendingDemotion100 (b * testing.B ) { benchmarkPendingDemotion (b , 100 ) }
0 commit comments