github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/ethclient/simulated/backend_test.go (about) 1 // Copyright 2019 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 "math/rand" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/accounts/abi/bind" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/params" 32 ) 33 34 var _ bind.ContractBackend = (Client)(nil) 35 36 var ( 37 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 38 testAddr = crypto.PubkeyToAddress(testKey.PublicKey) 39 ) 40 41 func simTestBackend(testAddr common.Address) *Backend { 42 return NewBackend( 43 types.GenesisAlloc{ 44 testAddr: {Balance: big.NewInt(10000000000000000)}, 45 }, 46 ) 47 } 48 49 func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) { 50 client := sim.Client() 51 52 // create a signed transaction to send 53 head, _ := client.HeaderByNumber(context.Background(), nil) // Should be child's, good enough 54 gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)) 55 addr := crypto.PubkeyToAddress(key.PublicKey) 56 chainid, _ := client.ChainID(context.Background()) 57 nonce, err := client.PendingNonceAt(context.Background(), addr) 58 if err != nil { 59 return nil, err 60 } 61 tx := types.NewTx(&types.DynamicFeeTx{ 62 ChainID: chainid, 63 Nonce: nonce, 64 GasTipCap: big.NewInt(params.GWei), 65 GasFeeCap: gasPrice, 66 Gas: 21000, 67 To: &addr, 68 }) 69 return types.SignTx(tx, types.LatestSignerForChainID(chainid), key) 70 } 71 72 func TestNewBackend(t *testing.T) { 73 sim := NewBackend(types.GenesisAlloc{}) 74 defer sim.Close() 75 76 client := sim.Client() 77 num, err := client.BlockNumber(context.Background()) 78 if err != nil { 79 t.Fatal(err) 80 } 81 if num != 0 { 82 t.Fatalf("expected 0 got %v", num) 83 } 84 // Create a block 85 sim.Commit() 86 num, err = client.BlockNumber(context.Background()) 87 if err != nil { 88 t.Fatal(err) 89 } 90 if num != 1 { 91 t.Fatalf("expected 1 got %v", num) 92 } 93 } 94 95 func TestAdjustTime(t *testing.T) { 96 sim := NewBackend(types.GenesisAlloc{}) 97 defer sim.Close() 98 99 client := sim.Client() 100 block1, _ := client.BlockByNumber(context.Background(), nil) 101 102 // Create a block 103 if err := sim.AdjustTime(time.Minute); err != nil { 104 t.Fatal(err) 105 } 106 block2, _ := client.BlockByNumber(context.Background(), nil) 107 prevTime := block1.Time() 108 newTime := block2.Time() 109 if newTime-prevTime != uint64(time.Minute) { 110 t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime) 111 } 112 } 113 114 func TestSendTransaction(t *testing.T) { 115 sim := simTestBackend(testAddr) 116 defer sim.Close() 117 118 client := sim.Client() 119 ctx := context.Background() 120 121 signedTx, err := newTx(sim, testKey) 122 if err != nil { 123 t.Errorf("could not create transaction: %v", err) 124 } 125 // send tx to simulated backend 126 err = client.SendTransaction(ctx, signedTx) 127 if err != nil { 128 t.Errorf("could not add tx to pending block: %v", err) 129 } 130 sim.Commit() 131 block, err := client.BlockByNumber(ctx, big.NewInt(1)) 132 if err != nil { 133 t.Errorf("could not get block at height 1: %v", err) 134 } 135 136 if signedTx.Hash() != block.Transactions()[0].Hash() { 137 t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), signedTx.Hash()) 138 } 139 } 140 141 // TestFork check that the chain length after a reorg is correct. 142 // Steps: 143 // 1. Save the current block which will serve as parent for the fork. 144 // 2. Mine n blocks with n ∈ [0, 20]. 145 // 3. Assert that the chain length is n. 146 // 4. Fork by using the parent block as ancestor. 147 // 5. Mine n+1 blocks which should trigger a reorg. 148 // 6. Assert that the chain length is n+1. 149 // Since Commit() was called 2n+1 times in total, 150 // having a chain length of just n+1 means that a reorg occurred. 151 func TestFork(t *testing.T) { 152 t.Parallel() 153 testAddr := crypto.PubkeyToAddress(testKey.PublicKey) 154 sim := simTestBackend(testAddr) 155 defer sim.Close() 156 157 client := sim.Client() 158 ctx := context.Background() 159 160 // 1. 161 parent, _ := client.HeaderByNumber(ctx, nil) 162 163 // 2. 164 n := int(rand.Int31n(21)) 165 for i := 0; i < n; i++ { 166 sim.Commit() 167 } 168 169 // 3. 170 b, _ := client.BlockNumber(ctx) 171 if b != uint64(n) { 172 t.Error("wrong chain length") 173 } 174 175 // 4. 176 sim.Fork(parent.Hash()) 177 178 // 5. 179 for i := 0; i < n+1; i++ { 180 sim.Commit() 181 } 182 183 // 6. 184 b, _ = client.BlockNumber(ctx) 185 if b != uint64(n+1) { 186 t.Error("wrong chain length") 187 } 188 } 189 190 // TestForkResendTx checks that re-sending a TX after a fork 191 // is possible and does not cause a "nonce mismatch" panic. 192 // Steps: 193 // 1. Save the current block which will serve as parent for the fork. 194 // 2. Send a transaction. 195 // 3. Check that the TX is included in block 1. 196 // 4. Fork by using the parent block as ancestor. 197 // 5. Mine a block, Re-send the transaction and mine another one. 198 // 6. Check that the TX is now included in block 2. 199 func TestForkResendTx(t *testing.T) { 200 t.Parallel() 201 testAddr := crypto.PubkeyToAddress(testKey.PublicKey) 202 sim := simTestBackend(testAddr) 203 defer sim.Close() 204 205 client := sim.Client() 206 ctx := context.Background() 207 208 // 1. 209 parent, _ := client.HeaderByNumber(ctx, nil) 210 211 // 2. 212 tx, err := newTx(sim, testKey) 213 if err != nil { 214 t.Fatalf("could not create transaction: %v", err) 215 } 216 client.SendTransaction(ctx, tx) 217 sim.Commit() 218 219 // 3. 220 receipt, _ := client.TransactionReceipt(ctx, tx.Hash()) 221 if h := receipt.BlockNumber.Uint64(); h != 1 { 222 t.Errorf("TX included in wrong block: %d", h) 223 } 224 225 // 4. 226 if err := sim.Fork(parent.Hash()); err != nil { 227 t.Errorf("forking: %v", err) 228 } 229 230 // 5. 231 sim.Commit() 232 if err := client.SendTransaction(ctx, tx); err != nil { 233 t.Fatalf("sending transaction: %v", err) 234 } 235 sim.Commit() 236 receipt, _ = client.TransactionReceipt(ctx, tx.Hash()) 237 if h := receipt.BlockNumber.Uint64(); h != 2 { 238 t.Errorf("TX included in wrong block: %d", h) 239 } 240 } 241 242 func TestCommitReturnValue(t *testing.T) { 243 t.Parallel() 244 testAddr := crypto.PubkeyToAddress(testKey.PublicKey) 245 sim := simTestBackend(testAddr) 246 defer sim.Close() 247 248 client := sim.Client() 249 ctx := context.Background() 250 251 // Test if Commit returns the correct block hash 252 h1 := sim.Commit() 253 cur, _ := client.HeaderByNumber(ctx, nil) 254 if h1 != cur.Hash() { 255 t.Error("Commit did not return the hash of the last block.") 256 } 257 258 // Create a block in the original chain (containing a transaction to force different block hashes) 259 head, _ := client.HeaderByNumber(ctx, nil) // Should be child's, good enough 260 gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) 261 _tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil) 262 tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey) 263 client.SendTransaction(ctx, tx) 264 265 h2 := sim.Commit() 266 267 // Create another block in the original chain 268 sim.Commit() 269 270 // Fork at the first bock 271 if err := sim.Fork(h1); err != nil { 272 t.Errorf("forking: %v", err) 273 } 274 275 // Test if Commit returns the correct block hash after the reorg 276 h2fork := sim.Commit() 277 if h2 == h2fork { 278 t.Error("The block in the fork and the original block are the same block!") 279 } 280 if header, err := client.HeaderByHash(ctx, h2fork); err != nil || header == nil { 281 t.Error("Could not retrieve the just created block (side-chain)") 282 } 283 } 284 285 // TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork 286 // block's parent rather than the canonical head's parent. 287 func TestAdjustTimeAfterFork(t *testing.T) { 288 t.Parallel() 289 testAddr := crypto.PubkeyToAddress(testKey.PublicKey) 290 sim := simTestBackend(testAddr) 291 defer sim.Close() 292 293 client := sim.Client() 294 ctx := context.Background() 295 296 sim.Commit() // h1 297 h1, _ := client.HeaderByNumber(ctx, nil) 298 299 sim.Commit() // h2 300 sim.Fork(h1.Hash()) 301 sim.AdjustTime(1 * time.Second) 302 sim.Commit() 303 304 head, _ := client.HeaderByNumber(ctx, nil) 305 if head.Number.Uint64() == 2 && head.ParentHash != h1.Hash() { 306 t.Errorf("failed to build block on fork") 307 } 308 }