github.com/ethereum/go-ethereum@v1.16.1/ethclient/simulated/rollback_test.go (about) 1 // Copyright 2025 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package simulated 18 19 import ( 20 "context" 21 "crypto/ecdsa" 22 "math/big" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/core/types" 27 ) 28 29 // TestTransactionRollbackBehavior tests that calling Rollback on the simulated backend doesn't prevent subsequent 30 // addition of new transactions 31 func TestTransactionRollbackBehavior(t *testing.T) { 32 sim := NewBackend( 33 types.GenesisAlloc{ 34 testAddr: {Balance: big.NewInt(10000000000000000)}, 35 testAddr2: {Balance: big.NewInt(10000000000000000)}, 36 }, 37 ) 38 defer sim.Close() 39 client := sim.Client() 40 41 btx0 := testSendSignedTx(t, testKey, sim, true) 42 tx0 := testSendSignedTx(t, testKey2, sim, false) 43 tx1 := testSendSignedTx(t, testKey2, sim, false) 44 45 sim.Rollback() 46 47 if pendingStateHasTx(client, btx0) || pendingStateHasTx(client, tx0) || pendingStateHasTx(client, tx1) { 48 t.Fatalf("all transactions were not rolled back") 49 } 50 51 btx2 := testSendSignedTx(t, testKey, sim, true) 52 tx2 := testSendSignedTx(t, testKey2, sim, false) 53 tx3 := testSendSignedTx(t, testKey2, sim, false) 54 55 sim.Commit() 56 57 if !pendingStateHasTx(client, btx2) || !pendingStateHasTx(client, tx2) || !pendingStateHasTx(client, tx3) { 58 t.Fatalf("all post-rollback transactions were not included") 59 } 60 } 61 62 // testSendSignedTx sends a signed transaction to the simulated backend. 63 // It does not commit the block. 64 func testSendSignedTx(t *testing.T, key *ecdsa.PrivateKey, sim *Backend, isBlobTx bool) *types.Transaction { 65 t.Helper() 66 client := sim.Client() 67 ctx := context.Background() 68 69 var ( 70 err error 71 signedTx *types.Transaction 72 ) 73 if isBlobTx { 74 signedTx, err = newBlobTx(sim, key) 75 } else { 76 signedTx, err = newTx(sim, key) 77 } 78 if err != nil { 79 t.Fatalf("failed to create transaction: %v", err) 80 } 81 82 if err = client.SendTransaction(ctx, signedTx); err != nil { 83 t.Fatalf("failed to send transaction: %v", err) 84 } 85 86 return signedTx 87 } 88 89 // pendingStateHasTx returns true if a given transaction was successfully included as of the latest pending state. 90 func pendingStateHasTx(client Client, tx *types.Transaction) bool { 91 ctx := context.Background() 92 93 var ( 94 receipt *types.Receipt 95 err error 96 ) 97 98 // Poll for receipt with timeout 99 deadline := time.Now().Add(2 * time.Second) 100 for time.Now().Before(deadline) { 101 receipt, err = client.TransactionReceipt(ctx, tx.Hash()) 102 if err == nil && receipt != nil { 103 break 104 } 105 time.Sleep(100 * time.Millisecond) 106 } 107 108 if err != nil { 109 return false 110 } 111 if receipt == nil { 112 return false 113 } 114 if receipt.Status != types.ReceiptStatusSuccessful { 115 return false 116 } 117 return true 118 }