github.com/ava-labs/subnet-evm@v0.6.4/core/blockchain_test.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package core 5 6 import ( 7 "fmt" 8 "math/big" 9 "os" 10 "testing" 11 12 "github.com/ava-labs/subnet-evm/consensus/dummy" 13 "github.com/ava-labs/subnet-evm/core/rawdb" 14 "github.com/ava-labs/subnet-evm/core/state" 15 "github.com/ava-labs/subnet-evm/core/state/pruner" 16 "github.com/ava-labs/subnet-evm/core/types" 17 "github.com/ava-labs/subnet-evm/core/vm" 18 "github.com/ava-labs/subnet-evm/eth/tracers/logger" 19 "github.com/ava-labs/subnet-evm/params" 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/crypto" 22 "github.com/ethereum/go-ethereum/ethdb" 23 "github.com/stretchr/testify/require" 24 ) 25 26 var ( 27 archiveConfig = &CacheConfig{ 28 TrieCleanLimit: 256, 29 TrieDirtyLimit: 256, 30 TrieDirtyCommitTarget: 20, 31 TriePrefetcherParallelism: 4, 32 Pruning: false, // Archive mode 33 SnapshotLimit: 256, 34 AcceptorQueueLimit: 64, 35 } 36 37 pruningConfig = &CacheConfig{ 38 TrieCleanLimit: 256, 39 TrieDirtyLimit: 256, 40 TrieDirtyCommitTarget: 20, 41 TriePrefetcherParallelism: 4, 42 Pruning: true, // Enable pruning 43 CommitInterval: 4096, 44 SnapshotLimit: 256, 45 AcceptorQueueLimit: 64, 46 } 47 ) 48 49 func newGwei(n int64) *big.Int { 50 return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) 51 } 52 53 func createBlockChain( 54 db ethdb.Database, 55 cacheConfig *CacheConfig, 56 gspec *Genesis, 57 lastAcceptedHash common.Hash, 58 ) (*BlockChain, error) { 59 // Import the chain. This runs all block validation rules. 60 blockchain, err := NewBlockChain( 61 db, 62 cacheConfig, 63 gspec, 64 dummy.NewCoinbaseFaker(), 65 vm.Config{}, 66 lastAcceptedHash, 67 false, 68 ) 69 return blockchain, err 70 } 71 72 func TestArchiveBlockChain(t *testing.T) { 73 createArchiveBlockChain := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 74 return createBlockChain(db, archiveConfig, gspec, lastAcceptedHash) 75 } 76 for _, tt := range tests { 77 t.Run(tt.Name, func(t *testing.T) { 78 tt.testFunc(t, createArchiveBlockChain) 79 }) 80 } 81 } 82 83 func TestArchiveBlockChainSnapsDisabled(t *testing.T) { 84 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 85 return createBlockChain( 86 db, 87 &CacheConfig{ 88 TrieCleanLimit: 256, 89 TrieDirtyLimit: 256, 90 TrieDirtyCommitTarget: 20, 91 TriePrefetcherParallelism: 4, 92 Pruning: false, // Archive mode 93 SnapshotLimit: 0, // Disable snapshots 94 AcceptorQueueLimit: 64, 95 }, 96 gspec, 97 lastAcceptedHash, 98 ) 99 } 100 for _, tt := range tests { 101 t.Run(tt.Name, func(t *testing.T) { 102 tt.testFunc(t, create) 103 }) 104 } 105 } 106 107 func TestPruningBlockChain(t *testing.T) { 108 createPruningBlockChain := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 109 return createBlockChain(db, pruningConfig, gspec, lastAcceptedHash) 110 } 111 for _, tt := range tests { 112 t.Run(tt.Name, func(t *testing.T) { 113 tt.testFunc(t, createPruningBlockChain) 114 }) 115 } 116 } 117 118 func TestPruningBlockChainSnapsDisabled(t *testing.T) { 119 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 120 return createBlockChain( 121 db, 122 &CacheConfig{ 123 TrieCleanLimit: 256, 124 TrieDirtyLimit: 256, 125 TrieDirtyCommitTarget: 20, 126 TriePrefetcherParallelism: 4, 127 Pruning: true, // Enable pruning 128 CommitInterval: 4096, 129 SnapshotLimit: 0, // Disable snapshots 130 AcceptorQueueLimit: 64, 131 }, 132 gspec, 133 lastAcceptedHash, 134 ) 135 } 136 for _, tt := range tests { 137 t.Run(tt.Name, func(t *testing.T) { 138 tt.testFunc(t, create) 139 }) 140 } 141 } 142 143 type wrappedStateManager struct { 144 TrieWriter 145 } 146 147 func (w *wrappedStateManager) Shutdown() error { return nil } 148 149 func TestPruningBlockChainUngracefulShutdown(t *testing.T) { 150 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 151 blockchain, err := createBlockChain(db, pruningConfig, gspec, lastAcceptedHash) 152 if err != nil { 153 return nil, err 154 } 155 156 // Overwrite state manager, so that Shutdown is not called. 157 // This tests to ensure that the state manager handles an ungraceful shutdown correctly. 158 blockchain.stateManager = &wrappedStateManager{TrieWriter: blockchain.stateManager} 159 return blockchain, err 160 } 161 for _, tt := range tests { 162 t.Run(tt.Name, func(t *testing.T) { 163 tt.testFunc(t, create) 164 }) 165 } 166 } 167 168 func TestPruningBlockChainUngracefulShutdownSnapsDisabled(t *testing.T) { 169 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 170 blockchain, err := createBlockChain( 171 db, 172 &CacheConfig{ 173 TrieCleanLimit: 256, 174 TrieDirtyLimit: 256, 175 TrieDirtyCommitTarget: 20, 176 TriePrefetcherParallelism: 4, 177 Pruning: true, // Enable pruning 178 CommitInterval: 4096, 179 SnapshotLimit: 0, // Disable snapshots 180 AcceptorQueueLimit: 64, 181 }, 182 gspec, 183 lastAcceptedHash, 184 ) 185 if err != nil { 186 return nil, err 187 } 188 189 // Overwrite state manager, so that Shutdown is not called. 190 // This tests to ensure that the state manager handles an ungraceful shutdown correctly. 191 blockchain.stateManager = &wrappedStateManager{TrieWriter: blockchain.stateManager} 192 return blockchain, err 193 } 194 for _, tt := range tests { 195 t.Run(tt.Name, func(t *testing.T) { 196 tt.testFunc(t, create) 197 }) 198 } 199 } 200 201 func TestEnableSnapshots(t *testing.T) { 202 // Set snapshots to be disabled the first time, and then enable them on the restart 203 snapLimit := 0 204 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 205 // Import the chain. This runs all block validation rules. 206 blockchain, err := createBlockChain( 207 db, 208 &CacheConfig{ 209 TrieCleanLimit: 256, 210 TrieDirtyLimit: 256, 211 TrieDirtyCommitTarget: 20, 212 TriePrefetcherParallelism: 4, 213 Pruning: true, // Enable pruning 214 CommitInterval: 4096, 215 SnapshotLimit: snapLimit, 216 AcceptorQueueLimit: 64, 217 }, 218 gspec, 219 lastAcceptedHash, 220 ) 221 if err != nil { 222 return nil, err 223 } 224 snapLimit = 256 225 226 return blockchain, err 227 } 228 for _, tt := range tests { 229 t.Run(tt.Name, func(t *testing.T) { 230 tt.testFunc(t, create) 231 }) 232 } 233 } 234 235 func TestCorruptSnapshots(t *testing.T) { 236 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 237 // Delete the snapshot block hash and state root to ensure that if we die in between writing a snapshot 238 // diff layer to disk at any point, we can still recover on restart. 239 rawdb.DeleteSnapshotBlockHash(db) 240 rawdb.DeleteSnapshotRoot(db) 241 242 return createBlockChain(db, pruningConfig, gspec, lastAcceptedHash) 243 } 244 for _, tt := range tests { 245 t.Run(tt.Name, func(t *testing.T) { 246 tt.testFunc(t, create) 247 }) 248 } 249 } 250 251 func TestBlockChainOfflinePruningUngracefulShutdown(t *testing.T) { 252 create := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 253 // Import the chain. This runs all block validation rules. 254 blockchain, err := createBlockChain(db, pruningConfig, gspec, lastAcceptedHash) 255 if err != nil { 256 return nil, err 257 } 258 259 // Overwrite state manager, so that Shutdown is not called. 260 // This tests to ensure that the state manager handles an ungraceful shutdown correctly. 261 blockchain.stateManager = &wrappedStateManager{TrieWriter: blockchain.stateManager} 262 263 if lastAcceptedHash == (common.Hash{}) { 264 return blockchain, nil 265 } 266 267 if err := blockchain.CleanBlockRootsAboveLastAccepted(); err != nil { 268 return nil, err 269 } 270 // get the target root to prune to before stopping the blockchain 271 targetRoot := blockchain.LastAcceptedBlock().Root() 272 if targetRoot == types.EmptyRootHash { 273 return blockchain, nil 274 } 275 blockchain.Stop() 276 277 tempDir := t.TempDir() 278 prunerConfig := pruner.Config{ 279 Datadir: tempDir, 280 BloomSize: 256, 281 } 282 283 pruner, err := pruner.NewPruner(db, prunerConfig) 284 if err != nil { 285 return nil, fmt.Errorf("offline pruning failed (%s, %d): %w", tempDir, 256, err) 286 } 287 288 if err := pruner.Prune(targetRoot); err != nil { 289 return nil, fmt.Errorf("failed to prune blockchain with target root: %s due to: %w", targetRoot, err) 290 } 291 // Re-initialize the blockchain after pruning 292 return createBlockChain(db, pruningConfig, gspec, lastAcceptedHash) 293 } 294 for _, tt := range tests { 295 tt := tt 296 t.Run(tt.Name, func(t *testing.T) { 297 t.Parallel() 298 tt.testFunc(t, create) 299 }) 300 } 301 } 302 303 func testRepopulateMissingTriesParallel(t *testing.T, parallelism int) { 304 var ( 305 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 306 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 307 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 308 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 309 chainDB = rawdb.NewMemoryDatabase() 310 ) 311 312 // Ensure that key1 has some funds in the genesis block. 313 genesisBalance := big.NewInt(1000000) 314 gspec := &Genesis{ 315 Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), FeeConfig: params.DefaultFeeConfig}, 316 Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}}, 317 } 318 319 blockchain, err := createBlockChain(chainDB, pruningConfig, gspec, common.Hash{}) 320 if err != nil { 321 t.Fatal(err) 322 } 323 defer blockchain.Stop() 324 325 // This call generates a chain of 3 blocks. 326 signer := types.HomesteadSigner{} 327 _, chain, _, err := GenerateChainWithGenesis(gspec, blockchain.engine, 10, 10, func(i int, gen *BlockGen) { 328 tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 329 gen.AddTx(tx) 330 }) 331 if err != nil { 332 t.Fatal(err) 333 } 334 335 if _, err := blockchain.InsertChain(chain); err != nil { 336 t.Fatal(err) 337 } 338 for _, block := range chain { 339 if err := blockchain.Accept(block); err != nil { 340 t.Fatal(err) 341 } 342 } 343 blockchain.DrainAcceptorQueue() 344 345 lastAcceptedHash := blockchain.LastConsensusAcceptedBlock().Hash() 346 blockchain.Stop() 347 348 blockchain, err = createBlockChain(chainDB, pruningConfig, gspec, lastAcceptedHash) 349 if err != nil { 350 t.Fatal(err) 351 } 352 353 // Confirm that the node does not have the state for intermediate nodes (exclude the last accepted block) 354 for _, block := range chain[:len(chain)-1] { 355 if blockchain.HasState(block.Root()) { 356 t.Fatalf("Expected blockchain to be missing state for intermediate block %d with pruning enabled", block.NumberU64()) 357 } 358 } 359 blockchain.Stop() 360 361 startHeight := uint64(1) 362 // Create a node in archival mode and re-populate the trie history. 363 blockchain, err = createBlockChain( 364 chainDB, 365 &CacheConfig{ 366 TrieCleanLimit: 256, 367 TrieDirtyLimit: 256, 368 TrieDirtyCommitTarget: 20, 369 TriePrefetcherParallelism: 4, 370 Pruning: false, // Archive mode 371 SnapshotLimit: 256, 372 PopulateMissingTries: &startHeight, // Starting point for re-populating. 373 PopulateMissingTriesParallelism: parallelism, 374 AcceptorQueueLimit: 64, 375 }, 376 gspec, 377 lastAcceptedHash, 378 ) 379 if err != nil { 380 t.Fatal(err) 381 } 382 defer blockchain.Stop() 383 384 for _, block := range chain { 385 if !blockchain.HasState(block.Root()) { 386 t.Fatalf("failed to re-generate state for block %d", block.NumberU64()) 387 } 388 } 389 } 390 391 func TestRepopulateMissingTries(t *testing.T) { 392 // Test with different levels of parallelism as a regression test. 393 for _, parallelism := range []int{1, 2, 4, 1024} { 394 testRepopulateMissingTriesParallel(t, parallelism) 395 } 396 } 397 398 func TestUngracefulAsyncShutdown(t *testing.T) { 399 var ( 400 create = func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 401 blockchain, err := createBlockChain(db, &CacheConfig{ 402 TrieCleanLimit: 256, 403 TrieDirtyLimit: 256, 404 TrieDirtyCommitTarget: 20, 405 TriePrefetcherParallelism: 4, 406 Pruning: true, 407 CommitInterval: 4096, 408 SnapshotLimit: 256, 409 SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails 410 AcceptorQueueLimit: 1000, // ensure channel doesn't block 411 }, gspec, lastAcceptedHash) 412 if err != nil { 413 return nil, err 414 } 415 return blockchain, nil 416 } 417 418 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 419 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 420 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 421 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 422 chainDB = rawdb.NewMemoryDatabase() 423 ) 424 425 // Ensure that key1 has some funds in the genesis block. 426 genesisBalance := big.NewInt(1000000) 427 gspec := &Genesis{ 428 Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), FeeConfig: params.DefaultFeeConfig}, 429 Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}}, 430 } 431 432 blockchain, err := create(chainDB, gspec, common.Hash{}) 433 if err != nil { 434 t.Fatal(err) 435 } 436 defer blockchain.Stop() 437 438 // This call generates a chain of 10 blocks. 439 signer := types.HomesteadSigner{} 440 _, chain, _, err := GenerateChainWithGenesis(gspec, blockchain.engine, 10, 10, func(i int, gen *BlockGen) { 441 tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 442 gen.AddTx(tx) 443 }) 444 if err != nil { 445 t.Fatal(err) 446 } 447 448 // Insert three blocks into the chain and accept only the first block. 449 if _, err := blockchain.InsertChain(chain); err != nil { 450 t.Fatal(err) 451 } 452 453 foundTxs := []common.Hash{} 454 missingTxs := []common.Hash{} 455 for i, block := range chain { 456 if err := blockchain.Accept(block); err != nil { 457 t.Fatal(err) 458 } 459 460 if i == 3 { 461 // At height 3, kill the async accepted block processor to force an 462 // ungraceful recovery 463 blockchain.stopAcceptor() 464 blockchain.acceptorQueue = nil 465 } 466 467 if i <= 3 { 468 // If <= height 3, all txs should be accessible on lookup 469 for _, tx := range block.Transactions() { 470 foundTxs = append(foundTxs, tx.Hash()) 471 } 472 } else { 473 // If > 3, all txs should be accessible on lookup 474 for _, tx := range block.Transactions() { 475 missingTxs = append(missingTxs, tx.Hash()) 476 } 477 } 478 } 479 480 // After inserting all blocks, we should confirm that txs added after the 481 // async worker shutdown cannot be found. 482 for _, tx := range foundTxs { 483 txLookup := blockchain.GetTransactionLookup(tx) 484 if txLookup == nil { 485 t.Fatalf("missing transaction: %v", tx) 486 } 487 } 488 for _, tx := range missingTxs { 489 txLookup := blockchain.GetTransactionLookup(tx) 490 if txLookup != nil { 491 t.Fatalf("transaction should be missing: %v", tx) 492 } 493 } 494 495 // check the state of the last accepted block 496 checkState := func(sdb *state.StateDB) error { 497 nonce := sdb.GetNonce(addr1) 498 if nonce != 10 { 499 return fmt.Errorf("expected nonce addr1: 10, found nonce: %d", nonce) 500 } 501 transferredFunds := big.NewInt(100000) 502 balance1 := sdb.GetBalance(addr1) 503 expectedBalance1 := new(big.Int).Sub(genesisBalance, transferredFunds) 504 if balance1.Cmp(expectedBalance1) != 0 { 505 return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance1, balance1) 506 } 507 508 balance2 := sdb.GetBalance(addr2) 509 expectedBalance2 := transferredFunds 510 if balance2.Cmp(expectedBalance2) != 0 { 511 return fmt.Errorf("expected addr2 balance: %d, found balance: %d", expectedBalance2, balance2) 512 } 513 514 nonce = sdb.GetNonce(addr2) 515 if nonce != 0 { 516 return fmt.Errorf("expected addr2 nonce: 0, found nonce: %d", nonce) 517 } 518 return nil 519 } 520 521 _, newChain, restartedChain := checkBlockChainState(t, blockchain, gspec, chainDB, create, checkState) 522 523 allTxs := append(foundTxs, missingTxs...) 524 for _, bc := range []*BlockChain{newChain, restartedChain} { 525 // We should confirm that snapshots were properly initialized 526 if bc.snaps == nil { 527 t.Fatal("snapshot initialization failed") 528 } 529 530 // We should confirm all transactions can now be queried 531 for _, tx := range allTxs { 532 txLookup := bc.GetTransactionLookup(tx) 533 if txLookup == nil { 534 t.Fatalf("missing transaction: %v", tx) 535 } 536 } 537 } 538 } 539 540 func TestTransactionIndices(t *testing.T) { 541 // Configure and generate a sample block chain 542 require := require.New(t) 543 var ( 544 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 545 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 546 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 547 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 548 funds = big.NewInt(10000000000000) 549 gspec = &Genesis{ 550 Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, 551 Alloc: GenesisAlloc{addr1: {Balance: funds}}, 552 } 553 signer = types.LatestSigner(gspec.Config) 554 ) 555 genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewFaker(), 128, 10, func(i int, block *BlockGen) { 556 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 557 require.NoError(err) 558 block.AddTx(tx) 559 }) 560 require.NoError(err) 561 562 blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewFaker(), genDb, 10, 10, func(i int, block *BlockGen) { 563 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 564 require.NoError(err) 565 block.AddTx(tx) 566 }) 567 require.NoError(err) 568 569 conf := &CacheConfig{ 570 TrieCleanLimit: 256, 571 TrieDirtyLimit: 256, 572 TrieDirtyCommitTarget: 20, 573 TriePrefetcherParallelism: 4, 574 Pruning: true, 575 CommitInterval: 4096, 576 SnapshotLimit: 256, 577 SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails 578 AcceptorQueueLimit: 64, 579 } 580 581 // Init block chain and check all needed indices has been indexed. 582 chainDB := rawdb.NewMemoryDatabase() 583 chain, err := createBlockChain(chainDB, conf, gspec, common.Hash{}) 584 require.NoError(err) 585 586 _, err = chain.InsertChain(blocks) 587 require.NoError(err) 588 589 for _, block := range blocks { 590 err := chain.Accept(block) 591 require.NoError(err) 592 } 593 chain.DrainAcceptorQueue() 594 595 lastAcceptedBlock := blocks[len(blocks)-1] 596 require.Equal(lastAcceptedBlock.Hash(), chain.CurrentHeader().Hash()) 597 598 CheckTxIndices(t, nil, lastAcceptedBlock.NumberU64(), chain.db, false) // check all indices has been indexed 599 chain.Stop() 600 601 // Reconstruct a block chain which only reserves limited tx indices 602 // 128 blocks were previously indexed. Now we add a new block at each test step. 603 limits := []uint64{ 604 0, /* tip: 129 reserve all (don't run) */ 605 131, /* tip: 130 reserve all */ 606 140, /* tip: 131 reserve all */ 607 64, /* tip: 132, limit:64 */ 608 32, /* tip: 133, limit:32 */ 609 } 610 for i, l := range limits { 611 t.Run(fmt.Sprintf("test-%d, limit: %d", i+1, l), func(t *testing.T) { 612 conf.TxLookupLimit = l 613 614 chain, err := createBlockChain(chainDB, conf, gspec, lastAcceptedBlock.Hash()) 615 require.NoError(err) 616 617 tail := getTail(l, lastAcceptedBlock.NumberU64()) 618 // check if startup indices are correct 619 CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false) 620 621 newBlks := blocks2[i : i+1] 622 _, err = chain.InsertChain(newBlks) // Feed chain a higher block to trigger indices updater. 623 require.NoError(err) 624 625 lastAcceptedBlock = newBlks[0] 626 err = chain.Accept(lastAcceptedBlock) // Accept the block to trigger indices updater. 627 require.NoError(err) 628 chain.DrainAcceptorQueue() 629 630 tail = getTail(l, lastAcceptedBlock.NumberU64()) 631 // check if indices are updated correctly 632 CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false) 633 chain.Stop() 634 }) 635 } 636 } 637 638 func getTail(limit uint64, lastAccepted uint64) *uint64 { 639 if limit == 0 { 640 return nil 641 } 642 var tail uint64 643 if lastAccepted > limit { 644 // tail should be the oldest block number which is indexed 645 // i.e the first block number that's in the lookup range 646 tail = lastAccepted - limit + 1 647 } 648 return &tail 649 } 650 651 func TestTransactionSkipIndexing(t *testing.T) { 652 // Configure and generate a sample block chain 653 require := require.New(t) 654 var ( 655 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 656 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 657 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 658 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 659 funds = big.NewInt(10000000000000) 660 gspec = &Genesis{ 661 Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, 662 Alloc: GenesisAlloc{addr1: {Balance: funds}}, 663 } 664 signer = types.LatestSigner(gspec.Config) 665 ) 666 genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewCoinbaseFaker(), 5, 10, func(i int, block *BlockGen) { 667 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 668 require.NoError(err) 669 block.AddTx(tx) 670 }) 671 require.NoError(err) 672 673 blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewCoinbaseFaker(), genDb, 5, 10, func(i int, block *BlockGen) { 674 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) 675 require.NoError(err) 676 block.AddTx(tx) 677 }) 678 require.NoError(err) 679 680 conf := &CacheConfig{ 681 TrieCleanLimit: 256, 682 TrieDirtyLimit: 256, 683 TrieDirtyCommitTarget: 20, 684 TriePrefetcherParallelism: 4, 685 Pruning: true, 686 CommitInterval: 4096, 687 SnapshotLimit: 256, 688 SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails 689 AcceptorQueueLimit: 64, 690 SkipTxIndexing: true, 691 } 692 693 // test1: Init block chain and check all indices has been skipped. 694 chainDB := rawdb.NewMemoryDatabase() 695 chain, err := createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{}, 696 func(b *types.Block) { 697 bNumber := b.NumberU64() 698 checkTxIndicesHelper(t, nil, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped 699 }) 700 require.NoError(err) 701 chain.Stop() 702 703 // test2: specify lookuplimit with tx index skipping enabled. Blocks should not be indexed but tail should be updated. 704 conf.TxLookupLimit = 2 705 chainDB = rawdb.NewMemoryDatabase() 706 chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{}, 707 func(b *types.Block) { 708 bNumber := b.NumberU64() 709 tail := bNumber - conf.TxLookupLimit + 1 710 checkTxIndicesHelper(t, &tail, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped 711 }) 712 require.NoError(err) 713 chain.Stop() 714 715 // test3: tx index skipping and unindexer disabled. Blocks should be indexed and tail should be updated. 716 conf.TxLookupLimit = 0 717 conf.SkipTxIndexing = false 718 chainDB = rawdb.NewMemoryDatabase() 719 chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{}, 720 func(b *types.Block) { 721 bNumber := b.NumberU64() 722 checkTxIndicesHelper(t, nil, 0, bNumber, bNumber, chainDB, false) // check all indices has been indexed 723 }) 724 require.NoError(err) 725 chain.Stop() 726 727 // now change tx index skipping to true and check that the indices are skipped for the last block 728 // and old indices are removed up to the tail, but [tail, current) indices are still there. 729 conf.TxLookupLimit = 2 730 conf.SkipTxIndexing = true 731 chain, err = createAndInsertChain(chainDB, conf, gspec, blocks2[0:1], chain.CurrentHeader().Hash(), 732 func(b *types.Block) { 733 bNumber := b.NumberU64() 734 tail := bNumber - conf.TxLookupLimit + 1 735 checkTxIndicesHelper(t, &tail, tail, bNumber-1, bNumber, chainDB, false) 736 }) 737 require.NoError(err) 738 chain.Stop() 739 } 740 741 // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted 742 // correctly in case reorg is called. 743 func TestCanonicalHashMarker(t *testing.T) { 744 testCanonicalHashMarker(t, rawdb.HashScheme) 745 testCanonicalHashMarker(t, rawdb.PathScheme) 746 } 747 748 func testCanonicalHashMarker(t *testing.T, scheme string) { 749 var cases = []struct { 750 forkA int 751 forkB int 752 }{ 753 // ForkA: 10 blocks 754 // ForkB: 1 blocks 755 // 756 // reorged: 757 // markers [2, 10] should be deleted 758 // markers [1] should be updated 759 {10, 1}, 760 761 // ForkA: 10 blocks 762 // ForkB: 2 blocks 763 // 764 // reorged: 765 // markers [3, 10] should be deleted 766 // markers [1, 2] should be updated 767 {10, 2}, 768 769 // ForkA: 10 blocks 770 // ForkB: 10 blocks 771 // 772 // reorged: 773 // markers [1, 10] should be updated 774 {10, 10}, 775 776 // ForkA: 10 blocks 777 // ForkB: 11 blocks 778 // 779 // reorged: 780 // markers [1, 11] should be updated 781 {10, 11}, 782 } 783 for _, c := range cases { 784 var ( 785 gspec = &Genesis{ 786 Config: params.TestChainConfig, 787 Alloc: GenesisAlloc{}, 788 BaseFee: big.NewInt(params.TestInitialBaseFee), 789 } 790 engine = dummy.NewCoinbaseFaker() 791 ) 792 _, forkA, _, err := GenerateChainWithGenesis(gspec, engine, c.forkA, 10, func(i int, gen *BlockGen) {}) 793 if err != nil { 794 t.Fatal(err) 795 } 796 _, forkB, _, err := GenerateChainWithGenesis(gspec, engine, c.forkB, 10, func(i int, gen *BlockGen) {}) 797 if err != nil { 798 t.Fatal(err) 799 } 800 801 // Initialize test chain 802 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, engine, vm.Config{}, common.Hash{}, false) 803 if err != nil { 804 t.Fatalf("failed to create tester chain: %v", err) 805 } 806 // Insert forkA and forkB, the canonical should on forkA still 807 if n, err := chain.InsertChain(forkA); err != nil { 808 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 809 } 810 if n, err := chain.InsertChain(forkB); err != nil { 811 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 812 } 813 814 verify := func(head *types.Block) { 815 if chain.CurrentBlock().Hash() != head.Hash() { 816 t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash()) 817 } 818 if chain.CurrentHeader().Hash() != head.Hash() { 819 t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash()) 820 } 821 if !chain.HasState(head.Root()) { 822 t.Fatalf("Lost block state %v %x", head.Number(), head.Hash()) 823 } 824 } 825 826 // Switch canonical chain to forkB if necessary 827 if len(forkA) < len(forkB) { 828 verify(forkB[len(forkB)-1]) 829 } else { 830 verify(forkA[len(forkA)-1]) 831 if err := chain.SetPreference(forkB[len(forkB)-1]); err != nil { 832 t.Fatal(err) 833 } 834 verify(forkB[len(forkB)-1]) 835 } 836 837 // Ensure all hash markers are updated correctly 838 for i := 0; i < len(forkB); i++ { 839 block := forkB[i] 840 hash := chain.GetCanonicalHash(block.NumberU64()) 841 if hash != block.Hash() { 842 t.Fatalf("Unexpected canonical hash %d", block.NumberU64()) 843 } 844 } 845 if c.forkA > c.forkB { 846 for i := uint64(c.forkB) + 1; i <= uint64(c.forkA); i++ { 847 hash := chain.GetCanonicalHash(i) 848 if hash != (common.Hash{}) { 849 t.Fatalf("Unexpected canonical hash %d", i) 850 } 851 } 852 } 853 chain.Stop() 854 } 855 } 856 857 func TestTxLookupBlockChain(t *testing.T) { 858 cacheConf := &CacheConfig{ 859 TrieCleanLimit: 256, 860 TrieDirtyLimit: 256, 861 TrieDirtyCommitTarget: 20, 862 TriePrefetcherParallelism: 4, 863 Pruning: true, 864 CommitInterval: 4096, 865 SnapshotLimit: 256, 866 SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails 867 AcceptorQueueLimit: 64, // ensure channel doesn't block 868 TxLookupLimit: 5, 869 } 870 createTxLookupBlockChain := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 871 return createBlockChain(db, cacheConf, gspec, lastAcceptedHash) 872 } 873 for _, tt := range tests { 874 t.Run(tt.Name, func(t *testing.T) { 875 tt.testFunc(t, createTxLookupBlockChain) 876 }) 877 } 878 } 879 880 func TestTxLookupSkipIndexingBlockChain(t *testing.T) { 881 cacheConf := &CacheConfig{ 882 TrieCleanLimit: 256, 883 TrieDirtyLimit: 256, 884 TrieDirtyCommitTarget: 20, 885 TriePrefetcherParallelism: 4, 886 Pruning: true, 887 CommitInterval: 4096, 888 SnapshotLimit: 256, 889 SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails 890 AcceptorQueueLimit: 64, // ensure channel doesn't block 891 TxLookupLimit: 5, 892 SkipTxIndexing: true, 893 } 894 createTxLookupBlockChain := func(db ethdb.Database, gspec *Genesis, lastAcceptedHash common.Hash) (*BlockChain, error) { 895 return createBlockChain(db, cacheConf, gspec, lastAcceptedHash) 896 } 897 for _, tt := range tests { 898 t.Run(tt.Name, func(t *testing.T) { 899 tt.testFunc(t, createTxLookupBlockChain) 900 }) 901 } 902 } 903 904 func TestCreateThenDeletePreByzantium(t *testing.T) { 905 // We want to use pre-byzantium rules where we have intermediate state roots 906 // between transactions. 907 config := *params.TestPreSubnetEVMConfig 908 config.ByzantiumBlock = nil 909 config.ConstantinopleBlock = nil 910 config.PetersburgBlock = nil 911 config.IstanbulBlock = nil 912 config.MuirGlacierBlock = nil 913 testCreateThenDelete(t, &config) 914 } 915 func TestCreateThenDeletePostByzantium(t *testing.T) { 916 testCreateThenDelete(t, params.TestChainConfig) 917 } 918 919 // testCreateThenDelete tests a creation and subsequent deletion of a contract, happening 920 // within the same block. 921 func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { 922 var ( 923 engine = dummy.NewFaker() 924 // A sender who makes transactions, has some funds 925 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 926 address = crypto.PubkeyToAddress(key.PublicKey) 927 destAddress = crypto.CreateAddress(address, 0) 928 funds = big.NewInt(params.Ether) // Note: additional funds are provided here compared to go-ethereum so test completes. 929 ) 930 931 // runtime code is 0x60ffff : PUSH1 0xFF SELFDESTRUCT, a.k.a SELFDESTRUCT(0xFF) 932 code := append([]byte{0x60, 0xff, 0xff}, make([]byte, 32-3)...) 933 initCode := []byte{ 934 // SSTORE 1:1 935 byte(vm.PUSH1), 0x1, 936 byte(vm.PUSH1), 0x1, 937 byte(vm.SSTORE), 938 // Get the runtime-code on the stack 939 byte(vm.PUSH32)} 940 initCode = append(initCode, code...) 941 initCode = append(initCode, []byte{ 942 byte(vm.PUSH1), 0x0, // offset 943 byte(vm.MSTORE), 944 byte(vm.PUSH1), 0x3, // size 945 byte(vm.PUSH1), 0x0, // offset 946 byte(vm.RETURN), // return 3 bytes of zero-code 947 }...) 948 gspec := &Genesis{ 949 Config: config, 950 Alloc: GenesisAlloc{ 951 address: {Balance: funds}, 952 }, 953 } 954 nonce := uint64(0) 955 signer := types.HomesteadSigner{} 956 _, blocks, _, _ := GenerateChainWithGenesis(gspec, engine, 2, 10, func(i int, b *BlockGen) { 957 fee := big.NewInt(1) 958 if b.header.BaseFee != nil { 959 fee = b.header.BaseFee 960 } 961 b.SetCoinbase(common.Address{1}) 962 tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ 963 Nonce: nonce, 964 GasPrice: new(big.Int).Set(fee), 965 Gas: 100000, 966 Data: initCode, 967 }) 968 nonce++ 969 b.AddTx(tx) 970 tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ 971 Nonce: nonce, 972 GasPrice: new(big.Int).Set(fee), 973 Gas: 100000, 974 To: &destAddress, 975 }) 976 b.AddTx(tx) 977 nonce++ 978 }) 979 // Import the canonical chain 980 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfig, gspec, engine, vm.Config{ 981 //Debug: true, 982 //Tracer: logger.NewJSONLogger(nil, os.Stdout), 983 }, common.Hash{}, false) 984 if err != nil { 985 t.Fatalf("failed to create tester chain: %v", err) 986 } 987 defer chain.Stop() 988 // Import the blocks 989 for _, block := range blocks { 990 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 991 t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) 992 } 993 } 994 } 995 996 func TestDeleteThenCreate(t *testing.T) { 997 var ( 998 engine = dummy.NewFaker() 999 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 1000 address = crypto.PubkeyToAddress(key.PublicKey) 1001 factoryAddr = crypto.CreateAddress(address, 0) 1002 funds = big.NewInt(params.Ether) // Note: additional funds are provided here compared to go-ethereum so test completes. 1003 ) 1004 /* 1005 contract Factory { 1006 function deploy(bytes memory code) public { 1007 address addr; 1008 assembly { 1009 addr := create2(0, add(code, 0x20), mload(code), 0) 1010 if iszero(extcodesize(addr)) { 1011 revert(0, 0) 1012 } 1013 } 1014 } 1015 } 1016 */ 1017 factoryBIN := common.Hex2Bytes("608060405234801561001057600080fd5b50610241806100206000396000f3fe608060405234801561001057600080fd5b506004361061002a5760003560e01c80627743601461002f575b600080fd5b610049600480360381019061004491906100d8565b61004b565b005b6000808251602084016000f59050803b61006457600080fd5b5050565b600061007b61007684610146565b610121565b905082815260208101848484011115610097576100966101eb565b5b6100a2848285610177565b509392505050565b600082601f8301126100bf576100be6101e6565b5b81356100cf848260208601610068565b91505092915050565b6000602082840312156100ee576100ed6101f5565b5b600082013567ffffffffffffffff81111561010c5761010b6101f0565b5b610118848285016100aa565b91505092915050565b600061012b61013c565b90506101378282610186565b919050565b6000604051905090565b600067ffffffffffffffff821115610161576101606101b7565b5b61016a826101fa565b9050602081019050919050565b82818337600083830152505050565b61018f826101fa565b810181811067ffffffffffffffff821117156101ae576101ad6101b7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f830116905091905056fea2646970667358221220ea8b35ed310d03b6b3deef166941140b4d9e90ea2c92f6b41eb441daf49a59c364736f6c63430008070033") 1018 1019 /* 1020 contract C { 1021 uint256 value; 1022 constructor() { 1023 value = 100; 1024 } 1025 function destruct() public payable { 1026 selfdestruct(payable(msg.sender)); 1027 } 1028 receive() payable external {} 1029 } 1030 */ 1031 contractABI := common.Hex2Bytes("6080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c63430008070033") 1032 contractAddr := crypto.CreateAddress2(factoryAddr, [32]byte{}, crypto.Keccak256(contractABI)) 1033 1034 gspec := &Genesis{ 1035 Config: params.TestChainConfig, 1036 Alloc: GenesisAlloc{ 1037 address: {Balance: funds}, 1038 }, 1039 } 1040 nonce := uint64(0) 1041 signer := types.HomesteadSigner{} 1042 _, blocks, _, err := GenerateChainWithGenesis(gspec, engine, 2, 10, func(i int, b *BlockGen) { 1043 fee := big.NewInt(1) 1044 if b.header.BaseFee != nil { 1045 fee = b.header.BaseFee 1046 } 1047 b.SetCoinbase(common.Address{1}) 1048 1049 // Block 1 1050 if i == 0 { 1051 tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ 1052 Nonce: nonce, 1053 GasPrice: new(big.Int).Set(fee), 1054 Gas: 500000, 1055 Data: factoryBIN, 1056 }) 1057 nonce++ 1058 b.AddTx(tx) 1059 1060 data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") 1061 tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ 1062 Nonce: nonce, 1063 GasPrice: new(big.Int).Set(fee), 1064 Gas: 500000, 1065 To: &factoryAddr, 1066 Data: data, 1067 }) 1068 b.AddTx(tx) 1069 nonce++ 1070 } else { 1071 // Block 2 1072 tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ 1073 Nonce: nonce, 1074 GasPrice: new(big.Int).Set(fee), 1075 Gas: 500000, 1076 To: &contractAddr, 1077 Data: common.Hex2Bytes("2b68b9c6"), // destruct 1078 }) 1079 nonce++ 1080 b.AddTx(tx) 1081 1082 data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") 1083 tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ 1084 Nonce: nonce, 1085 GasPrice: new(big.Int).Set(fee), 1086 Gas: 500000, 1087 To: &factoryAddr, // re-creation 1088 Data: data, 1089 }) 1090 b.AddTx(tx) 1091 nonce++ 1092 } 1093 }) 1094 if err != nil { 1095 t.Fatal(err) 1096 } 1097 // Import the canonical chain 1098 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfig, gspec, engine, vm.Config{}, common.Hash{}, false) 1099 if err != nil { 1100 t.Fatalf("failed to create tester chain: %v", err) 1101 } 1102 defer chain.Stop() 1103 for _, block := range blocks { 1104 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 1105 t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) 1106 } 1107 } 1108 } 1109 1110 // TestTransientStorageReset ensures the transient storage is wiped correctly 1111 // between transactions. 1112 func TestTransientStorageReset(t *testing.T) { 1113 var ( 1114 engine = dummy.NewFaker() 1115 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 1116 address = crypto.PubkeyToAddress(key.PublicKey) 1117 destAddress = crypto.CreateAddress(address, 0) 1118 funds = big.NewInt(params.Ether) // Note: additional funds are provided here compared to go-ethereum so test completes. 1119 vmConfig = vm.Config{ 1120 ExtraEips: []int{1153}, // Enable transient storage EIP 1121 } 1122 ) 1123 code := append([]byte{ 1124 // TLoad value with location 1 1125 byte(vm.PUSH1), 0x1, 1126 byte(vm.TLOAD), 1127 1128 // PUSH location 1129 byte(vm.PUSH1), 0x1, 1130 1131 // SStore location:value 1132 byte(vm.SSTORE), 1133 }, make([]byte, 32-6)...) 1134 initCode := []byte{ 1135 // TSTORE 1:1 1136 byte(vm.PUSH1), 0x1, 1137 byte(vm.PUSH1), 0x1, 1138 byte(vm.TSTORE), 1139 1140 // Get the runtime-code on the stack 1141 byte(vm.PUSH32)} 1142 initCode = append(initCode, code...) 1143 initCode = append(initCode, []byte{ 1144 byte(vm.PUSH1), 0x0, // offset 1145 byte(vm.MSTORE), 1146 byte(vm.PUSH1), 0x6, // size 1147 byte(vm.PUSH1), 0x0, // offset 1148 byte(vm.RETURN), // return 6 bytes of zero-code 1149 }...) 1150 gspec := &Genesis{ 1151 Config: params.TestChainConfig, 1152 Alloc: GenesisAlloc{ 1153 address: {Balance: funds}, 1154 }, 1155 } 1156 nonce := uint64(0) 1157 signer := types.HomesteadSigner{} 1158 _, blocks, _, _ := GenerateChainWithGenesis(gspec, engine, 1, 10, func(i int, b *BlockGen) { 1159 fee := big.NewInt(1) 1160 if b.header.BaseFee != nil { 1161 fee = b.header.BaseFee 1162 } 1163 b.SetCoinbase(common.Address{1}) 1164 tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ 1165 Nonce: nonce, 1166 GasPrice: new(big.Int).Set(fee), 1167 Gas: 100000, 1168 Data: initCode, 1169 }) 1170 nonce++ 1171 b.AddTxWithVMConfig(tx, vmConfig) 1172 1173 tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ 1174 Nonce: nonce, 1175 GasPrice: new(big.Int).Set(fee), 1176 Gas: 100000, 1177 To: &destAddress, 1178 }) 1179 b.AddTxWithVMConfig(tx, vmConfig) 1180 nonce++ 1181 }) 1182 1183 // Initialize the blockchain with 1153 enabled. 1184 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfig, gspec, engine, vmConfig, common.Hash{}, false) 1185 if err != nil { 1186 t.Fatalf("failed to create tester chain: %v", err) 1187 } 1188 defer chain.Stop() 1189 // Import the blocks 1190 if _, err := chain.InsertChain(blocks); err != nil { 1191 t.Fatalf("failed to insert into chain: %v", err) 1192 } 1193 // Check the storage 1194 state, err := chain.StateAt(chain.CurrentHeader().Root) 1195 if err != nil { 1196 t.Fatalf("Failed to load state %v", err) 1197 } 1198 loc := common.BytesToHash([]byte{1}) 1199 slot := state.GetState(destAddress, loc) 1200 if slot != (common.Hash{}) { 1201 t.Fatalf("Unexpected dirty storage slot") 1202 } 1203 } 1204 1205 func TestEIP3651(t *testing.T) { 1206 var ( 1207 aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") 1208 bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") 1209 engine = dummy.NewCoinbaseFaker() 1210 1211 // A sender who makes transactions, has some funds 1212 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 1213 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 1214 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 1215 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 1216 funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) 1217 gspec = &Genesis{ 1218 Config: params.TestChainConfig, 1219 Timestamp: uint64(params.DefaultGenesisTime.Unix()), 1220 Alloc: GenesisAlloc{ 1221 addr1: {Balance: funds}, 1222 addr2: {Balance: funds}, 1223 // The address 0xAAAA sloads 0x00 and 0x01 1224 aa: { 1225 Code: []byte{ 1226 byte(vm.PC), 1227 byte(vm.PC), 1228 byte(vm.SLOAD), 1229 byte(vm.SLOAD), 1230 }, 1231 Nonce: 0, 1232 Balance: big.NewInt(0), 1233 }, 1234 // The address 0xBBBB calls 0xAAAA 1235 bb: { 1236 Code: []byte{ 1237 byte(vm.PUSH1), 0, // out size 1238 byte(vm.DUP1), // out offset 1239 byte(vm.DUP1), // out insize 1240 byte(vm.DUP1), // in offset 1241 byte(vm.PUSH2), // address 1242 byte(0xaa), 1243 byte(0xaa), 1244 byte(vm.GAS), // gas 1245 byte(vm.DELEGATECALL), 1246 }, 1247 Nonce: 0, 1248 Balance: big.NewInt(0), 1249 }, 1250 }, 1251 } 1252 ) 1253 1254 signer := types.LatestSigner(gspec.Config) 1255 1256 _, blocks, _, _ := GenerateChainWithGenesis(gspec, engine, 1, 10, func(i int, b *BlockGen) { 1257 b.SetCoinbase(aa) 1258 // One transaction to Coinbase 1259 txdata := &types.DynamicFeeTx{ 1260 ChainID: gspec.Config.ChainID, 1261 Nonce: 0, 1262 To: &bb, 1263 Gas: 500000, 1264 GasFeeCap: newGwei(225), 1265 GasTipCap: big.NewInt(2), 1266 AccessList: nil, 1267 Data: []byte{}, 1268 } 1269 tx := types.NewTx(txdata) 1270 tx, _ = types.SignTx(tx, signer, key1) 1271 1272 b.AddTx(tx) 1273 }) 1274 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfig, gspec, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, common.Hash{}, false) 1275 if err != nil { 1276 t.Fatalf("failed to create tester chain: %v", err) 1277 } 1278 defer chain.Stop() 1279 if n, err := chain.InsertChain(blocks); err != nil { 1280 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 1281 } 1282 1283 block := chain.GetBlockByNumber(1) 1284 1285 // 1+2: Ensure EIP-1559 access lists are accounted for via gas usage. 1286 innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2 1287 expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list 1288 if block.GasUsed() != expectedGas { 1289 t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed()) 1290 } 1291 1292 state, _ := chain.State() 1293 1294 // 3: Ensure that miner received the gasUsed * (block baseFee + effectiveGasTip). 1295 // Note this differs from go-ethereum where the miner receives the gasUsed * block baseFee, 1296 // as our handling of the coinbase payment is different. 1297 // Note we use block.GasUsed() here as there is only one tx. 1298 actual := state.GetBalance(block.Coinbase()) 1299 tx := block.Transactions()[0] 1300 gasPrice := new(big.Int).Add(block.BaseFee(), tx.EffectiveGasTipValue(block.BaseFee())) 1301 expected := new(big.Int).SetUint64(block.GasUsed() * gasPrice.Uint64()) 1302 if actual.Cmp(expected) != 0 { 1303 t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) 1304 } 1305 1306 // 4: Ensure the tx sender paid for the gasUsed * (block baseFee + effectiveGasTip). 1307 // Note this differs from go-ethereum where the miner receives the gasUsed * block baseFee, 1308 // as our handling of the coinbase payment is different. 1309 actual = new(big.Int).Sub(funds, state.GetBalance(addr1)) 1310 if actual.Cmp(expected) != 0 { 1311 t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) 1312 } 1313 } 1314 1315 func createAndInsertChain(db ethdb.Database, cacheConfig *CacheConfig, gspec *Genesis, blocks types.Blocks, lastAcceptedHash common.Hash, accepted func(*types.Block)) (*BlockChain, error) { 1316 chain, err := createBlockChain(db, cacheConfig, gspec, lastAcceptedHash) 1317 if err != nil { 1318 return nil, err 1319 } 1320 _, err = chain.InsertChain(blocks) 1321 if err != nil { 1322 return nil, err 1323 } 1324 for _, block := range blocks { 1325 err := chain.Accept(block) 1326 if err != nil { 1327 return nil, err 1328 } 1329 chain.DrainAcceptorQueue() 1330 if accepted != nil { 1331 accepted(block) 1332 } 1333 } 1334 1335 return chain, nil 1336 }