| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 10:28:02 +01:00
										 |  |  | package core | 
					
						
							| 
									
										
										
										
											2014-12-17 12:57:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-12-04 12:22:19 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2014-12-17 12:57:35 +01:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-12-17 12:57:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 00:08:43 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2018-06-19 19:41:13 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/consensus" | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/consensus/ethash" | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							| 
									
										
										
										
											2014-12-18 13:12:54 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2014-12-18 13:12:54 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2020-08-21 20:10:40 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/trie" | 
					
						
							| 
									
										
										
										
											2014-12-17 12:57:35 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 19:41:13 +08:00
										 |  |  | // So we can deterministically seed different blockchains | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	canonicalSeed = 1 | 
					
						
							|  |  |  | 	forkSeed      = 2 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newCanonical creates a chain database, and injects a deterministic canonical | 
					
						
							|  |  |  | // chain. Depending on the full flag, if creates either a full block chain or a | 
					
						
							|  |  |  | // header only chain. | 
					
						
							|  |  |  | func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db      = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2018-06-19 19:41:13 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize a fresh chain with only a genesis block | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-06-19 19:41:13 +08:00
										 |  |  | 	// Create and inject the requested chain | 
					
						
							|  |  |  | 	if n == 0 { | 
					
						
							|  |  |  | 		return db, blockchain, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if full { | 
					
						
							|  |  |  | 		// Full block-chain requested | 
					
						
							|  |  |  | 		blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed) | 
					
						
							|  |  |  | 		_, err := blockchain.InsertChain(blocks) | 
					
						
							|  |  |  | 		return db, blockchain, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Header-only chain requested | 
					
						
							|  |  |  | 	headers := makeHeaderChain(genesis.Header(), n, engine, db, canonicalSeed) | 
					
						
							|  |  |  | 	_, err := blockchain.InsertHeaderChain(headers, 1) | 
					
						
							|  |  |  | 	return db, blockchain, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | func newGwei(n int64) *big.Int { | 
					
						
							|  |  |  | 	return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | // Test fork of length N starting from block i | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Copy old chain up to #i into a new db | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	db, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("could not make new canonical in testFork", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain2.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Assert the chains have the same header/block at #i | 
					
						
							|  |  |  | 	var hash1, hash2 common.Hash | 
					
						
							|  |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		hash1 = blockchain.GetBlockByNumber(uint64(i)).Hash() | 
					
						
							|  |  |  | 		hash2 = blockchain2.GetBlockByNumber(uint64(i)).Hash() | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		hash1 = blockchain.GetHeaderByNumber(uint64(i)).Hash() | 
					
						
							|  |  |  | 		hash2 = blockchain2.GetHeaderByNumber(uint64(i)).Hash() | 
					
						
							| 
									
										
										
										
											2015-02-28 14:58:37 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if hash1 != hash2 { | 
					
						
							|  |  |  | 		t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1) | 
					
						
							| 
									
										
										
										
											2015-02-28 14:58:37 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Extend the newly created chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		blockChainB  []*types.Block | 
					
						
							|  |  |  | 		headerChainB []*types.Header | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 		blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if _, err := blockchain2.InsertChain(blockChainB); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Fatalf("failed to insert forking chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 		headerChainB = makeHeaderChain(blockchain2.CurrentHeader(), n, ethash.NewFaker(), db, forkSeed) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Fatalf("failed to insert forking chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Sanity check that the forked chain can be imported into the original | 
					
						
							|  |  |  | 	var tdPre, tdPost *big.Int | 
					
						
							| 
									
										
										
										
											2015-04-29 12:43:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		tdPre = blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err := testBlockChainImport(blockChainB, blockchain); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Fatalf("failed to import forked block chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		tdPost = blockchain.GetTdByHash(blockChainB[len(blockChainB)-1].Hash()) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		tdPre = blockchain.GetTdByHash(blockchain.CurrentHeader().Hash()) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err := testHeaderChainImport(headerChainB, blockchain); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Fatalf("failed to import forked header chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		tdPost = blockchain.GetTdByHash(headerChainB[len(headerChainB)-1].Hash()) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Compare the total difficulties of the chains | 
					
						
							|  |  |  | 	comparator(tdPre, tdPost) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // testBlockChainImport tries to process a chain of blocks, writing them into | 
					
						
							|  |  |  | // the database if successful. | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	for _, block := range chain { | 
					
						
							|  |  |  | 		// Try and process the block | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			err = blockchain.validator.ValidateBody(block) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-04-06 14:58:03 +03:00
										 |  |  | 			if err == ErrKnownBlock { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-02-24 13:26:34 +02:00
										 |  |  | 		statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache, nil) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 		receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-23 13:32:25 +01:00
										 |  |  | 			blockchain.reportBlock(block, receipts, err) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-03-13 12:31:35 +02:00
										 |  |  | 		err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-23 13:32:25 +01:00
										 |  |  | 			blockchain.reportBlock(block, receipts, err) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-11 15:27:47 +02:00
										 |  |  | 		blockchain.chainmu.Lock() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) | 
					
						
							|  |  |  | 		rawdb.WriteBlock(blockchain.db, block) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		statedb.Commit(false) | 
					
						
							| 
									
										
										
										
											2019-01-11 15:27:47 +02:00
										 |  |  | 		blockchain.chainmu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // testHeaderChainImport tries to process a chain of header, writing them into | 
					
						
							|  |  |  | // the database if successful. | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	for _, header := range chain { | 
					
						
							|  |  |  | 		// Try and validate the header | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-15 11:55:39 -07:00
										 |  |  | 		// Manually insert the header into the database, but don't reorganise (allows subsequent testing) | 
					
						
							| 
									
										
										
										
											2019-01-11 15:27:47 +02:00
										 |  |  | 		blockchain.chainmu.Lock() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		rawdb.WriteTd(blockchain.db, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash))) | 
					
						
							|  |  |  | 		rawdb.WriteHeader(blockchain.db, header) | 
					
						
							| 
									
										
										
										
											2019-01-11 15:27:47 +02:00
										 |  |  | 		blockchain.chainmu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-05 16:51:06 +02:00
										 |  |  | func TestLastBlock(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	_, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	blocks := makeBlockChain(blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), blockchain.db, 0) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to insert block: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	if blocks[len(blocks)-1].Hash() != rawdb.ReadHeadBlockHash(blockchain.db) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		t.Fatalf("Write/Get HeadBlockHash failed") | 
					
						
							| 
									
										
										
										
											2015-10-05 16:51:06 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that given a starting canonical chain of a given size, it can be extended | 
					
						
							|  |  |  | // with various length chains. | 
					
						
							|  |  |  | func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) } | 
					
						
							|  |  |  | func TestExtendCanonicalBlocks(t *testing.T)  { testExtendCanonical(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testExtendCanonical(t *testing.T, full bool) { | 
					
						
							|  |  |  | 	length := 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make first chain starting from genesis | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	_, processor, err := newCanonical(ethash.NewFaker(), length, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to make new canonical chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer processor.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Define the difficulty comparator | 
					
						
							|  |  |  | 	better := func(td1, td2 *big.Int) { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		if td2.Cmp(td1) <= 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Start fork from current height | 
					
						
							|  |  |  | 	testFork(t, processor, length, 1, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, length, 2, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, length, 5, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, length, 10, full, better) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that given a starting canonical chain of a given size, creating shorter | 
					
						
							|  |  |  | // forks do not take canonical ownership. | 
					
						
							|  |  |  | func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) } | 
					
						
							|  |  |  | func TestShorterForkBlocks(t *testing.T)  { testShorterFork(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testShorterFork(t *testing.T, full bool) { | 
					
						
							|  |  |  | 	length := 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make first chain starting from genesis | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	_, processor, err := newCanonical(ethash.NewFaker(), length, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to make new canonical chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer processor.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Define the difficulty comparator | 
					
						
							|  |  |  | 	worse := func(td1, td2 *big.Int) { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		if td2.Cmp(td1) >= 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Sum of numbers must be less than `length` for this to be a shorter fork | 
					
						
							|  |  |  | 	testFork(t, processor, 0, 3, full, worse) | 
					
						
							|  |  |  | 	testFork(t, processor, 0, 7, full, worse) | 
					
						
							|  |  |  | 	testFork(t, processor, 1, 1, full, worse) | 
					
						
							|  |  |  | 	testFork(t, processor, 1, 7, full, worse) | 
					
						
							|  |  |  | 	testFork(t, processor, 5, 3, full, worse) | 
					
						
							|  |  |  | 	testFork(t, processor, 5, 4, full, worse) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that given a starting canonical chain of a given size, creating longer | 
					
						
							|  |  |  | // forks do take canonical ownership. | 
					
						
							|  |  |  | func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) } | 
					
						
							|  |  |  | func TestLongerForkBlocks(t *testing.T)  { testLongerFork(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testLongerFork(t *testing.T, full bool) { | 
					
						
							|  |  |  | 	length := 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make first chain starting from genesis | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	_, processor, err := newCanonical(ethash.NewFaker(), length, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to make new canonical chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer processor.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Define the difficulty comparator | 
					
						
							|  |  |  | 	better := func(td1, td2 *big.Int) { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		if td2.Cmp(td1) <= 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Sum of numbers must be greater than `length` for this to be a longer fork | 
					
						
							|  |  |  | 	testFork(t, processor, 0, 11, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, 0, 15, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, 1, 10, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, 1, 12, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, 5, 6, full, better) | 
					
						
							|  |  |  | 	testFork(t, processor, 5, 8, full, better) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that given a starting canonical chain of a given size, creating equal | 
					
						
							|  |  |  | // forks do take canonical ownership. | 
					
						
							|  |  |  | func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) } | 
					
						
							|  |  |  | func TestEqualForkBlocks(t *testing.T)  { testEqualFork(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testEqualFork(t *testing.T, full bool) { | 
					
						
							|  |  |  | 	length := 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make first chain starting from genesis | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	_, processor, err := newCanonical(ethash.NewFaker(), length, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to make new canonical chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer processor.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Define the difficulty comparator | 
					
						
							|  |  |  | 	equal := func(td1, td2 *big.Int) { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		if td2.Cmp(td1) != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Sum of numbers must be equal to `length` for this to be an equal fork | 
					
						
							|  |  |  | 	testFork(t, processor, 0, 10, full, equal) | 
					
						
							|  |  |  | 	testFork(t, processor, 1, 9, full, equal) | 
					
						
							|  |  |  | 	testFork(t, processor, 2, 8, full, equal) | 
					
						
							|  |  |  | 	testFork(t, processor, 5, 5, full, equal) | 
					
						
							|  |  |  | 	testFork(t, processor, 6, 4, full, equal) | 
					
						
							|  |  |  | 	testFork(t, processor, 9, 1, full, equal) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that chains missing links do not get accepted by the processor. | 
					
						
							|  |  |  | func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) } | 
					
						
							|  |  |  | func TestBrokenBlockChain(t *testing.T)  { testBrokenChain(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testBrokenChain(t *testing.T, full bool) { | 
					
						
							|  |  |  | 	// Make chain starting from genesis | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	db, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to make new canonical chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Create a forked chain, and try to insert with a missing link | 
					
						
							|  |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 		chain := makeBlockChain(blockchain.CurrentBlock(), 5, ethash.NewFaker(), db, forkSeed)[1:] | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err := testBlockChainImport(chain, blockchain); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("broken block chain not reported") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 		chain := makeHeaderChain(blockchain.CurrentHeader(), 5, ethash.NewFaker(), db, forkSeed)[1:] | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 		if err := testHeaderChainImport(chain, blockchain); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("broken header chain not reported") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-17 22:02:15 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 11:55:39 -07:00
										 |  |  | // Tests that reorganising a long difficult chain after a short easy one | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // overwrites the canonical numbers and links in the database. | 
					
						
							|  |  |  | func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } | 
					
						
							|  |  |  | func TestReorgLongBlocks(t *testing.T)  { testReorgLong(t, true) } | 
					
						
							| 
									
										
										
										
											2015-07-10 14:29:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | func testReorgLong(t *testing.T, full bool) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280, full) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-30 00:08:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 11:55:39 -07:00
										 |  |  | // Tests that reorganising a short difficult chain after a long easy one | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // overwrites the canonical numbers and links in the database. | 
					
						
							|  |  |  | func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } | 
					
						
							|  |  |  | func TestReorgShortBlocks(t *testing.T)  { testReorgShort(t, true) } | 
					
						
							| 
									
										
										
										
											2015-04-29 12:43:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | func testReorgShort(t *testing.T, full bool) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	// Create a long easy chain vs. a short heavy one. Due to difficulty adjustment | 
					
						
							|  |  |  | 	// we need a fairly long chain of blocks with different difficulties for a short | 
					
						
							|  |  |  | 	// one to become heavyer than a long one. The 96 is an empirical value. | 
					
						
							|  |  |  | 	easy := make([]int64, 96) | 
					
						
							|  |  |  | 	for i := 0; i < len(easy); i++ { | 
					
						
							|  |  |  | 		easy[i] = 60 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	diff := make([]int64, len(easy)-1) | 
					
						
							|  |  |  | 	for i := 0; i < len(diff); i++ { | 
					
						
							|  |  |  | 		diff[i] = -9 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	testReorg(t, easy, diff, 12615120, full) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-29 12:43:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | func testReorg(t *testing.T, first, second []int64, td int64, full bool) { | 
					
						
							|  |  |  | 	// Create a pristine chain and database | 
					
						
							|  |  |  | 	db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Insert an easy and a difficult chain afterwards | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.OffsetTime(first[i]) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.OffsetTime(second[i]) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if _, err := blockchain.InsertChain(easyBlocks); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to insert easy chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := blockchain.InsertChain(diffBlocks); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to insert difficult chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		easyHeaders := make([]*types.Header, len(easyBlocks)) | 
					
						
							|  |  |  | 		for i, block := range easyBlocks { | 
					
						
							|  |  |  | 			easyHeaders[i] = block.Header() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		diffHeaders := make([]*types.Header, len(diffBlocks)) | 
					
						
							|  |  |  | 		for i, block := range diffBlocks { | 
					
						
							|  |  |  | 			diffHeaders[i] = block.Header() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := blockchain.InsertHeaderChain(easyHeaders, 1); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to insert easy chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := blockchain.InsertHeaderChain(diffHeaders, 1); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to insert difficult chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Check that the chain is valid number and link wise | 
					
						
							|  |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		prev := blockchain.CurrentBlock() | 
					
						
							|  |  |  | 		for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			if prev.ParentHash() != block.Hash() { | 
					
						
							|  |  |  | 				t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		prev := blockchain.CurrentHeader() | 
					
						
							|  |  |  | 		for header := blockchain.GetHeaderByNumber(blockchain.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, blockchain.GetHeaderByNumber(header.Number.Uint64()-1) { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			if prev.ParentHash != header.Hash() { | 
					
						
							|  |  |  | 				t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Make sure the chain total difficulty is the correct one | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td)) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if have := blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()); have.Cmp(want) != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, want %v", have, want) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if have := blockchain.GetTdByHash(blockchain.CurrentHeader().Hash()); have.Cmp(want) != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Errorf("total difficulty mismatch: have %v, want %v", have, want) | 
					
						
							| 
									
										
										
										
											2015-04-29 12:43:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-30 00:08:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests that the insertion functions detect banned hashes. | 
					
						
							|  |  |  | func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } | 
					
						
							|  |  |  | func TestBadBlockHashes(t *testing.T)  { testBadHashes(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testBadHashes(t *testing.T, full bool) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	// Create a pristine chain and database | 
					
						
							|  |  |  | 	db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2015-09-14 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	// Create a chain, ban a hash and try to import | 
					
						
							|  |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		blocks := makeBlockChain(blockchain.CurrentBlock(), 3, ethash.NewFaker(), db, 10) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		BadHashes[blocks[2].Header().Hash()] = true | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, err = blockchain.InsertChain(blocks) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		headers := makeHeaderChain(blockchain.CurrentHeader(), 3, ethash.NewFaker(), db, 10) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		BadHashes[headers[2].Hash()] = true | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		defer func() { delete(BadHashes, headers[2].Hash()) }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, err = blockchain.InsertHeaderChain(headers, 1) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-04 12:22:19 +01:00
										 |  |  | 	if !errors.Is(err, ErrBlacklistedHash) { | 
					
						
							| 
									
										
										
										
											2017-04-06 14:58:03 +03:00
										 |  |  | 		t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash) | 
					
						
							| 
									
										
										
										
											2015-09-14 16:56:33 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 11:08:18 -07:00
										 |  |  | // Tests that bad hashes are detected on boot, and the chain rolled back to a | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // good state prior to the bad hash. | 
					
						
							|  |  |  | func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) } | 
					
						
							|  |  |  | func TestReorgBadBlockHashes(t *testing.T)  { testReorgBadHashes(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testReorgBadHashes(t *testing.T, full bool) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	// Create a pristine chain and database | 
					
						
							|  |  |  | 	db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-15 11:08:18 -07:00
										 |  |  | 	// Create a chain, import and ban afterwards | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	headers := makeHeaderChain(blockchain.CurrentHeader(), 4, ethash.NewFaker(), db, 10) | 
					
						
							|  |  |  | 	blocks := makeBlockChain(blockchain.CurrentBlock(), 4, ethash.NewFaker(), db, 10) | 
					
						
							| 
									
										
										
										
											2015-09-14 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if full { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if _, err = blockchain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 			t.Errorf("failed to import blocks: %v", err) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if blockchain.CurrentBlock().Hash() != blocks[3].Hash() { | 
					
						
							|  |  |  | 			t.Errorf("last block hash mismatch: have: %x, want %x", blockchain.CurrentBlock().Hash(), blocks[3].Header().Hash()) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		BadHashes[blocks[3].Header().Hash()] = true | 
					
						
							|  |  |  | 		defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if _, err = blockchain.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							|  |  |  | 			t.Errorf("failed to import headers: %v", err) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if blockchain.CurrentHeader().Hash() != headers[3].Hash() { | 
					
						
							|  |  |  | 			t.Errorf("last header hash mismatch: have: %x, want %x", blockchain.CurrentHeader().Hash(), headers[3].Hash()) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		BadHashes[headers[3].Hash()] = true | 
					
						
							|  |  |  | 		defer func() { delete(BadHashes, headers[3].Hash()) }() | 
					
						
							| 
									
										
										
										
											2015-09-14 16:56:33 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create a new BlockChain and check that it rolled back the state. | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-07-10 14:29:40 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		t.Fatalf("failed to create new chain manager: %v", err) | 
					
						
							| 
									
										
										
										
											2015-07-10 14:29:40 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 	if full { | 
					
						
							|  |  |  | 		if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { | 
					
						
							|  |  |  | 			t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 		if blocks[2].Header().GasLimit != ncm.GasLimit() { | 
					
						
							|  |  |  | 			t.Errorf("last  block gasLimit mismatch: have: %d, want %d", ncm.GasLimit(), blocks[2].Header().GasLimit) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 		if ncm.CurrentHeader().Hash() != headers[2].Hash() { | 
					
						
							|  |  |  | 			t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) | 
					
						
							| 
									
										
										
										
											2015-04-30 00:08:43 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	ncm.Stop() | 
					
						
							| 
									
										
										
										
											2015-04-30 00:08:43 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | // Tests chain insertions in the face of one entity containing an invalid nonce. | 
					
						
							|  |  |  | func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) } | 
					
						
							|  |  |  | func TestBlocksInsertNonceError(t *testing.T)  { testInsertNonceError(t, true) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testInsertNonceError(t *testing.T, full bool) { | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 	for i := 1; i < 25 && !t.Failed(); i++ { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		// Create a pristine chain and database | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 		db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) | 
					
						
							| 
									
										
										
										
											2015-07-10 14:29:40 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-07-10 14:29:40 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 		defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		// Create and insert a chain with a failing nonce | 
					
						
							|  |  |  | 		var ( | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 			failAt  int | 
					
						
							|  |  |  | 			failRes int | 
					
						
							|  |  |  | 			failNum uint64 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		) | 
					
						
							|  |  |  | 		if full { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 			blocks := makeBlockChain(blockchain.CurrentBlock(), i, ethash.NewFaker(), db, 0) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			failAt = rand.Int() % len(blocks) | 
					
						
							|  |  |  | 			failNum = blocks[failAt].NumberU64() | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 			blockchain.engine = ethash.NewFakeFailer(failNum) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 			failRes, err = blockchain.InsertChain(blocks) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 			headers := makeHeaderChain(blockchain.CurrentHeader(), i, ethash.NewFaker(), db, 0) | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 			failAt = rand.Int() % len(headers) | 
					
						
							|  |  |  | 			failNum = headers[failAt].Number.Uint64() | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 			blockchain.engine = ethash.NewFakeFailer(failNum) | 
					
						
							|  |  |  | 			blockchain.hc.engine = blockchain.engine | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 			failRes, err = blockchain.InsertHeaderChain(headers, 1) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 		// Check that the returned error indicates the failure | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		if failRes != failAt { | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 			t.Errorf("test %d: failure (%v) index mismatch: have %d, want %d", i, err, failRes, failAt) | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 		// Check that all blocks after the failing block have been inserted | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 		for j := 0; j < i-failAt; j++ { | 
					
						
							|  |  |  | 			if full { | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 				if block := blockchain.GetBlockByNumber(failNum + uint64(j)); block != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 					t.Errorf("test %d: invalid block in chain: %v", i, block) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 				if header := blockchain.GetHeaderByNumber(failNum + uint64(j)); header != nil { | 
					
						
							| 
									
										
										
										
											2015-09-21 15:36:29 +03:00
										 |  |  | 					t.Errorf("test %d: invalid header in chain: %v", i, header) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-06-08 02:19:39 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | // Tests that fast importing a block chain produces the same chain data as the | 
					
						
							|  |  |  | // classical full block processing. | 
					
						
							|  |  |  | func TestFastVsFullChains(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			Config:  params.TestChainConfig, | 
					
						
							|  |  |  | 			Alloc:   GenesisAlloc{address: {Balance: funds}}, | 
					
						
							|  |  |  | 			BaseFee: big.NewInt(params.InitialBaseFee), | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		block.SetCoinbase(common.Address{0x00}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// If the block number is multiple of 3, send a few bonus transactions to the miner | 
					
						
							|  |  |  | 		if i%3 == 2 { | 
					
						
							|  |  |  | 			for j := 0; j < i%4+1; j++ { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 				tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					panic(err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				block.AddTx(tx) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If the block number is a multiple of 5, add a few bonus uncles to the block | 
					
						
							|  |  |  | 		if i%5 == 5 { | 
					
						
							|  |  |  | 			block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the chain as an archive node for the comparison baseline | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	archiveDb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 	gspec.MustCommit(archiveDb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer archive.Stop() | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if n, err := archive.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to process block %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Fast import the chain as a non-archive node to test | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	fastDb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 	gspec.MustCommit(fastDb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer fast.Stop() | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 	if n, err := fast.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Freezer style fast import the chain. | 
					
						
							|  |  |  | 	frdir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(frdir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	defer ancient.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(len(blocks)/2)); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Iterate over all chain data components, and cross reference | 
					
						
							|  |  |  | 	for i := 0; i < len(blocks); i++ { | 
					
						
							|  |  |  | 		num, hash := blocks[i].NumberU64(), blocks[i].Hash() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		if ftd, atd := fast.GetTdByHash(hash), archive.GetTdByHash(hash); ftd.Cmp(atd) != 0 { | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			t.Errorf("block #%d [%x]: td mismatch: fastdb %v, archivedb %v", num, hash, ftd, atd) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if antd, artd := ancient.GetTdByHash(hash), archive.GetTdByHash(hash); antd.Cmp(artd) != 0 { | 
					
						
							|  |  |  | 			t.Errorf("block #%d [%x]: td mismatch: ancientdb %v, archivedb %v", num, hash, antd, artd) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-05 15:22:04 +02:00
										 |  |  | 		if fheader, aheader := fast.GetHeaderByHash(hash), archive.GetHeaderByHash(hash); fheader.Hash() != aheader.Hash() { | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			t.Errorf("block #%d [%x]: header mismatch: fastdb %v, archivedb %v", num, hash, fheader, aheader) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if anheader, arheader := ancient.GetHeaderByHash(hash), archive.GetHeaderByHash(hash); anheader.Hash() != arheader.Hash() { | 
					
						
							|  |  |  | 			t.Errorf("block #%d [%x]: header mismatch: ancientdb %v, archivedb %v", num, hash, anheader, arheader) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 		if fblock, arblock, anblock := fast.GetBlockByHash(hash), archive.GetBlockByHash(hash), ancient.GetBlockByHash(hash); fblock.Hash() != arblock.Hash() || anblock.Hash() != arblock.Hash() { | 
					
						
							|  |  |  | 			t.Errorf("block #%d [%x]: block mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, fblock, anblock, arblock) | 
					
						
							| 
									
										
										
										
											2021-02-02 20:09:23 +08:00
										 |  |  | 		} else if types.DeriveSha(fblock.Transactions(), trie.NewStackTrie(nil)) != types.DeriveSha(arblock.Transactions(), trie.NewStackTrie(nil)) || types.DeriveSha(anblock.Transactions(), trie.NewStackTrie(nil)) != types.DeriveSha(arblock.Transactions(), trie.NewStackTrie(nil)) { | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			t.Errorf("block #%d [%x]: transactions mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, fblock.Transactions(), anblock.Transactions(), arblock.Transactions()) | 
					
						
							|  |  |  | 		} else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(arblock.Uncles()) || types.CalcUncleHash(anblock.Uncles()) != types.CalcUncleHash(arblock.Uncles()) { | 
					
						
							|  |  |  | 			t.Errorf("block #%d [%x]: uncles mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, fblock.Uncles(), anblock, arblock.Uncles()) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-02-02 20:09:23 +08:00
										 |  |  | 		if freceipts, anreceipts, areceipts := rawdb.ReadReceipts(fastDb, hash, *rawdb.ReadHeaderNumber(fastDb, hash), fast.Config()), rawdb.ReadReceipts(ancientDb, hash, *rawdb.ReadHeaderNumber(ancientDb, hash), fast.Config()), rawdb.ReadReceipts(archiveDb, hash, *rawdb.ReadHeaderNumber(archiveDb, hash), fast.Config()); types.DeriveSha(freceipts, trie.NewStackTrie(nil)) != types.DeriveSha(areceipts, trie.NewStackTrie(nil)) { | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			t.Errorf("block #%d [%x]: receipts mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, freceipts, anreceipts, areceipts) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Check that the canonical chains are the same between the databases | 
					
						
							|  |  |  | 	for i := 0; i < len(blocks)+1; i++ { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		if fhash, ahash := rawdb.ReadCanonicalHash(fastDb, uint64(i)), rawdb.ReadCanonicalHash(archiveDb, uint64(i)); fhash != ahash { | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			t.Errorf("block #%d: canonical hash mismatch: fastdb %v, archivedb %v", i, fhash, ahash) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if anhash, arhash := rawdb.ReadCanonicalHash(ancientDb, uint64(i)), rawdb.ReadCanonicalHash(archiveDb, uint64(i)); anhash != arhash { | 
					
						
							|  |  |  | 			t.Errorf("block #%d: canonical hash mismatch: ancientdb %v, archivedb %v", i, anhash, arhash) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that various import methods move the chain head pointers to the correct | 
					
						
							|  |  |  | // positions. | 
					
						
							|  |  |  | func TestLightVsFastVsFullChainHeads(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(1000000000000000) | 
					
						
							|  |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config:  params.TestChainConfig, | 
					
						
							|  |  |  | 			Alloc:   GenesisAlloc{address: {Balance: funds}}, | 
					
						
							|  |  |  | 			BaseFee: big.NewInt(params.InitialBaseFee), | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-09 20:24:25 +08:00
										 |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	height := uint64(1024) | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	// makeDb creates a db instance for testing. | 
					
						
							|  |  |  | 	makeDb := func() (ethdb.Database, func()) { | 
					
						
							|  |  |  | 		dir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer os.Remove(dir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 		db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		gspec.MustCommit(db) | 
					
						
							|  |  |  | 		return db, func() { os.RemoveAll(dir) } | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	// Configure a subchain to roll back | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	remove := blocks[height/2].NumberU64() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	// Create a small assertion method to check the three heads | 
					
						
							|  |  |  | 	assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) { | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 		t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		if num := chain.CurrentBlock().NumberU64(); num != block { | 
					
						
							|  |  |  | 			t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if num := chain.CurrentFastBlock().NumberU64(); num != fast { | 
					
						
							|  |  |  | 			t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if num := chain.CurrentHeader().Number.Uint64(); num != header { | 
					
						
							|  |  |  | 			t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the chain as an archive node and ensure all pointers are updated | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	archiveDb, delfn := makeDb() | 
					
						
							|  |  |  | 	defer delfn() | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	archiveCaching := *defaultCacheConfig | 
					
						
							|  |  |  | 	archiveCaching.TrieDirtyDisabled = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	if n, err := archive.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to process block %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer archive.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	assert(t, "archive", archive, height, height, height) | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	archive.SetHead(remove - 1) | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	assert(t, "archive", archive, height/2, height/2, height/2) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Import the chain as a non-archive node and ensure all pointers are updated | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	fastDb, delfn := makeDb() | 
					
						
							|  |  |  | 	defer delfn() | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer fast.Stop() | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 	if n, err := fast.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assert(t, "fast", fast, height, height, 0) | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	fast.SetHead(remove - 1) | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	assert(t, "fast", fast, height/2, height/2, 0) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	// Import the chain as a ancient-first node and ensure all pointers are updated | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	ancientDb, delfn := makeDb() | 
					
						
							|  |  |  | 	defer delfn() | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	defer ancient.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	assert(t, "ancient", ancient, height, height, 0) | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	ancient.SetHead(remove - 1) | 
					
						
							|  |  |  | 	assert(t, "ancient", ancient, 0, 0, 0) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	if frozen, err := ancientDb.Ancients(); err != nil || frozen != 1 { | 
					
						
							|  |  |  | 		t.Fatalf("failed to truncate ancient store, want %v, have %v", 1, frozen) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	// Import the chain as a light node and ensure all pointers are updated | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	lightDb, delfn := makeDb() | 
					
						
							|  |  |  | 	defer delfn() | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-10-07 12:14:30 +03:00
										 |  |  | 	if n, err := light.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer light.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | 	assert(t, "light", light, height, 0, 0) | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	light.SetHead(remove - 1) | 
					
						
							| 
									
										
										
										
											2015-10-09 16:21:47 +03:00
										 |  |  | 	assert(t, "light", light, height/2, 0, 0) | 
					
						
							| 
									
										
										
										
											2015-09-30 19:23:31 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-15 11:55:39 -07:00
										 |  |  | // Tests that chain reorganisations handle transaction removals and reinsertions. | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | func TestChainTxReorgs(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") | 
					
						
							|  |  |  | 		key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") | 
					
						
							|  |  |  | 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							|  |  |  | 		addr2   = crypto.PubkeyToAddress(key2.PublicKey) | 
					
						
							|  |  |  | 		addr3   = crypto.PubkeyToAddress(key3.PublicKey) | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db      = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config:   params.TestChainConfig, | 
					
						
							|  |  |  | 			GasLimit: 3141592, | 
					
						
							|  |  |  | 			Alloc: GenesisAlloc{ | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 				addr1: {Balance: big.NewInt(1000000000000000)}, | 
					
						
							|  |  |  | 				addr2: {Balance: big.NewInt(1000000000000000)}, | 
					
						
							|  |  |  | 				addr3: {Balance: big.NewInt(1000000000000000)}, | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 	// Create two transactions shared between the chains: | 
					
						
							|  |  |  | 	//  - postponed: transaction included at a later block in the forked chain | 
					
						
							|  |  |  | 	//  - swapped: transaction included at the same block number in the forked chain | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, key1) | 
					
						
							|  |  |  | 	swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, key1) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create two transactions that will be dropped by the forked chain: | 
					
						
							|  |  |  | 	//  - pastDrop: transaction dropped retroactively from a past block | 
					
						
							|  |  |  | 	//  - freshDrop: transaction dropped exactly at the block where the reorg is detected | 
					
						
							|  |  |  | 	var pastDrop, freshDrop *types.Transaction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create three transactions that will be added in the forked chain: | 
					
						
							| 
									
										
										
										
											2016-03-15 11:08:18 -07:00
										 |  |  | 	//  - pastAdd:   transaction added before the reorganization is detected | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 	//  - freshAdd:  transaction added at the exact block the reorg is detected | 
					
						
							|  |  |  | 	//  - futureAdd: transaction added after the reorg has already finished | 
					
						
							|  |  |  | 	var pastAdd, freshAdd, futureAdd *types.Transaction | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		switch i { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key2) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			gen.AddTx(pastDrop)  // This transaction will be dropped in the fork from below the split point | 
					
						
							|  |  |  | 			gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 2: | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key2) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point | 
					
						
							|  |  |  | 			gen.AddTx(swapped)   // This transaction will be swapped out at the exact height | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gen.OffsetTime(9) // Lower the block difficulty to simulate a weaker chain | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the chain. This runs all block validation rules. | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 	if i, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		t.Fatalf("failed to insert original chain[%d]: %v", i, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// overwrite the old chain | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		switch i { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key3) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			gen.AddTx(pastAdd) // This transaction needs to be injected during reorg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain | 
					
						
							|  |  |  | 			gen.AddTx(swapped)   // This transaction was swapped from the exact current spot in the original chain | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key3) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 3: | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key3) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			gen.AddTx(futureAdd) // This transaction will be added after a full reorg | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-10-19 16:08:17 +02:00
										 |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							| 
									
										
										
										
											2015-06-08 12:12:13 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// removed tx | 
					
						
							|  |  |  | 	for i, tx := range (types.Transactions{pastDrop, freshDrop}) { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn != nil { | 
					
						
							| 
									
										
										
										
											2015-10-22 15:43:21 +03:00
										 |  |  | 			t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-04-15 12:36:27 +03:00
										 |  |  | 		if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt != nil { | 
					
						
							| 
									
										
										
										
											2017-07-14 19:39:53 +03:00
										 |  |  | 			t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// added tx | 
					
						
							|  |  |  | 	for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			t.Errorf("add %d: expected tx to be found", i) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-04-15 12:36:27 +03:00
										 |  |  | 		if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			t.Errorf("add %d: expected receipt to be found", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// shared tx | 
					
						
							|  |  |  | 	for i, tx := range (types.Transactions{postponed, swapped}) { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			t.Errorf("share %d: expected tx to be found", i) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-04-15 12:36:27 +03:00
										 |  |  | 		if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil { | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			t.Errorf("share %d: expected receipt to be found", i) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-08 12:12:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestLogReorgs(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db      = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 		// this code generates a log | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		code    = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	rmLogsCh := make(chan RemovedLogsEvent) | 
					
						
							|  |  |  | 	blockchain.SubscribeRemovedLogsEvent(rmLogsCh) | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 		if i == 1 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, code), signer, key1) | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("failed to create tx: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			gen.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	chain, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) | 
					
						
							| 
									
										
										
										
											2019-11-29 21:22:08 +08:00
										 |  |  | 	done := make(chan struct{}) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		ev := <-rmLogsCh | 
					
						
							|  |  |  | 		if len(ev.Logs) == 0 { | 
					
						
							|  |  |  | 			t.Error("expected logs") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		close(done) | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	timeout := time.NewTimer(1 * time.Second) | 
					
						
							| 
									
										
										
										
											2020-04-02 22:04:45 +08:00
										 |  |  | 	defer timeout.Stop() | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	select { | 
					
						
							| 
									
										
										
										
											2019-11-29 21:22:08 +08:00
										 |  |  | 	case <-done: | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	case <-timeout.C: | 
					
						
							|  |  |  | 		t.Fatal("Timeout. There is no RemovedLogsEvent has been sent.") | 
					
						
							| 
									
										
										
										
											2015-12-01 00:11:24 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | // This EVM code generates a log when the contract is created. | 
					
						
							|  |  |  | var logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This test checks that log events and RemovedLogsEvent are sent | 
					
						
							|  |  |  | // when the chain reorganizes. | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | func TestLogRebirth(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 		key1, _       = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		addr1         = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							|  |  |  | 		db            = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 		genesis       = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer        = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 		engine        = ethash.NewFaker() | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	// The event channels. | 
					
						
							|  |  |  | 	newLogCh := make(chan []*types.Log, 10) | 
					
						
							|  |  |  | 	rmLogsCh := make(chan RemovedLogsEvent, 10) | 
					
						
							|  |  |  | 	blockchain.SubscribeLogsEvent(newLogCh) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	blockchain.SubscribeRemovedLogsEvent(rmLogsCh) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	// This chain contains a single log. | 
					
						
							|  |  |  | 	chain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 		if i == 1 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("failed to create tx: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			gen.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	// Generate long reorg chain containing another log. Inserting the | 
					
						
							|  |  |  | 	// chain removes one log and adds one. | 
					
						
							|  |  |  | 	forkChain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 		if i == 1 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("failed to create tx: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			gen.AddTx(tx) | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 			gen.OffsetTime(-9) // higher block difficulty | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(forkChain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 1, 1) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	// This chain segment is rooted in the original chain, but doesn't contain any logs. | 
					
						
							|  |  |  | 	// When inserting it, the canonical chain switches away from forkChain and re-emits | 
					
						
							|  |  |  | 	// the log event for the old chain, as well as a RemovedLogsEvent for forkChain. | 
					
						
							|  |  |  | 	newBlocks, _ := GenerateChain(params.TestChainConfig, chain[len(chain)-1], engine, db, 1, func(i int, gen *BlockGen) {}) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	if _, err := blockchain.InsertChain(newBlocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 1, 1) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | // This test is a variation of TestLogRebirth. It verifies that log events are emitted | 
					
						
							|  |  |  | // when a side chain containing log events overtakes the canonical chain. | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | func TestSideLogRebirth(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 		key1, _       = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		addr1         = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							|  |  |  | 		db            = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 		genesis       = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer        = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	newLogCh := make(chan []*types.Log, 10) | 
					
						
							|  |  |  | 	rmLogsCh := make(chan RemovedLogsEvent, 10) | 
					
						
							|  |  |  | 	blockchain.SubscribeLogsEvent(newLogCh) | 
					
						
							|  |  |  | 	blockchain.SubscribeRemovedLogsEvent(rmLogsCh) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { | 
					
						
							|  |  |  | 		if i == 1 { | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 			gen.OffsetTime(-9) // higher block difficulty | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate side chain with lower difficulty | 
					
						
							|  |  |  | 	sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { | 
					
						
							|  |  |  | 		if i == 1 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("failed to create tx: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			gen.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(sideChain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	// Generate a new block based on side chain. | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	newBlocks, _ := GenerateChain(params.TestChainConfig, sideChain[len(sideChain)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(newBlocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert forked chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-28 10:06:49 +02:00
										 |  |  | 	checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) { | 
					
						
							|  |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(logsCh) != wantNew { | 
					
						
							|  |  |  | 		t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(rmLogsCh) != wantRemoved { | 
					
						
							|  |  |  | 		t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Drain events. | 
					
						
							|  |  |  | 	for i := 0; i < len(logsCh); i++ { | 
					
						
							|  |  |  | 		<-logsCh | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < len(rmLogsCh); i++ { | 
					
						
							|  |  |  | 		<-rmLogsCh | 
					
						
							| 
									
										
										
										
											2018-12-17 15:23:54 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | func TestReorgSideEvent(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db      = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config: params.TestChainConfig, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}, | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 	if _, err := blockchain.InsertChain(chain); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1) | 
					
						
							| 
									
										
										
										
											2016-03-31 17:43:41 +02:00
										 |  |  | 		if i == 2 { | 
					
						
							| 
									
										
										
										
											2017-09-14 10:59:05 +03:00
										 |  |  | 			gen.OffsetTime(-9) | 
					
						
							| 
									
										
										
										
											2016-03-31 17:43:41 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create tx: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		gen.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 	chainSideCh := make(chan ChainSideEvent, 64) | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	blockchain.SubscribeChainSideEvent(chainSideCh) | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 	if _, err := blockchain.InsertChain(replacementBlocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// first two block of the secondary chain are for a brief moment considered | 
					
						
							|  |  |  | 	// side chains because up to that point the first one is considered the | 
					
						
							|  |  |  | 	// heavier chain. | 
					
						
							|  |  |  | 	expectedSideHashes := map[common.Hash]bool{ | 
					
						
							|  |  |  | 		replacementBlocks[0].Hash(): true, | 
					
						
							|  |  |  | 		replacementBlocks[1].Hash(): true, | 
					
						
							|  |  |  | 		chain[0].Hash():             true, | 
					
						
							|  |  |  | 		chain[1].Hash():             true, | 
					
						
							|  |  |  | 		chain[2].Hash():             true, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const timeoutDura = 10 * time.Second | 
					
						
							|  |  |  | 	timeout := time.NewTimer(timeoutDura) | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 		case ev := <-chainSideCh: | 
					
						
							|  |  |  | 			block := ev.Block | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 			if _, ok := expectedSideHashes[block.Hash()]; !ok { | 
					
						
							|  |  |  | 				t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			i++ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if i == len(expectedSideHashes) { | 
					
						
							|  |  |  | 				timeout.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				break done | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			timeout.Reset(timeoutDura) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-timeout.C: | 
					
						
							|  |  |  | 			t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// make sure no more events are fired | 
					
						
							|  |  |  | 	select { | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	case e := <-chainSideCh: | 
					
						
							| 
									
										
										
										
											2016-03-15 11:08:18 -07:00
										 |  |  | 		t.Errorf("unexpected event fired: %v", e) | 
					
						
							| 
									
										
										
										
											2016-03-07 18:11:52 +01:00
										 |  |  | 	case <-time.After(250 * time.Millisecond): | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests if the canonical block can be fetched from the database during chain insertion. | 
					
						
							|  |  |  | func TestCanonicalBlockRetrieval(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	_, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create pristine chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer blockchain.Stop() | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 	chain, _ := GenerateChain(blockchain.chainConfig, blockchain.genesisBlock, ethash.NewFaker(), blockchain.db, 10, func(i int, gen *BlockGen) {}) | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	var pend sync.WaitGroup | 
					
						
							|  |  |  | 	pend.Add(len(chain)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 	for i := range chain { | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 		go func(block *types.Block) { | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 			defer pend.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 			// try to retrieve a block by its canonical hash and see if the block data can be retrieved. | 
					
						
							|  |  |  | 			for { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 				ch := rawdb.ReadCanonicalHash(blockchain.db, block.NumberU64()) | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 				if ch == (common.Hash{}) { | 
					
						
							|  |  |  | 					continue // busy wait for canonical hash to be written | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if ch != block.Hash() { | 
					
						
							| 
									
										
										
										
											2019-11-20 09:53:01 +01:00
										 |  |  | 					t.Errorf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) | 
					
						
							|  |  |  | 					return | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 				fb := rawdb.ReadBlock(blockchain.db, ch, block.NumberU64()) | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 				if fb == nil { | 
					
						
							| 
									
										
										
										
											2019-11-20 09:53:01 +01:00
										 |  |  | 					t.Errorf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) | 
					
						
							|  |  |  | 					return | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if fb.Hash() != block.Hash() { | 
					
						
							| 
									
										
										
										
											2019-11-20 09:53:01 +01:00
										 |  |  | 					t.Errorf("invalid block hash for block %d, want %s, got %s", block.NumberU64(), block.Hash().Hex(), fb.Hash().Hex()) | 
					
						
							|  |  |  | 					return | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}(chain[i]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:02:33 +02:00
										 |  |  | 		if _, err := blockchain.InsertChain(types.Blocks{chain[i]}); err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 			t.Fatalf("failed to insert block %d: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	pend.Wait() | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestEIP155Transition(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db         = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		key, _     = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address    = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 		funds      = big.NewInt(1000000000) | 
					
						
							|  |  |  | 		deleteAddr = common.Address{1} | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		gspec      = &Genesis{ | 
					
						
							| 
									
										
										
										
											2019-10-16 13:23:14 +02:00
										 |  |  | 			Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 			Alloc:  GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 		var ( | 
					
						
							|  |  |  | 			tx      *types.Transaction | 
					
						
							|  |  |  | 			err     error | 
					
						
							|  |  |  | 			basicTx = func(signer types.Signer) (*types.Transaction, error) { | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 				return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		switch i { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			tx, err = basicTx(types.HomesteadSigner{}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			tx, err = basicTx(types.HomesteadSigner{}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			tx, err = basicTx(types.LatestSigner(gspec.Config)) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		case 3: | 
					
						
							|  |  |  | 			tx, err = basicTx(types.HomesteadSigner{}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			tx, err = basicTx(types.LatestSigner(gspec.Config)) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	block := blockchain.GetBlockByNumber(1) | 
					
						
							|  |  |  | 	if block.Transactions()[0].Protected() { | 
					
						
							|  |  |  | 		t.Error("Expected block[0].txs[0] to not be replay protected") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block = blockchain.GetBlockByNumber(3) | 
					
						
							|  |  |  | 	if block.Transactions()[0].Protected() { | 
					
						
							|  |  |  | 		t.Error("Expected block[3].txs[0] to not be replay protected") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !block.Transactions()[1].Protected() { | 
					
						
							|  |  |  | 		t.Error("Expected block[3].txs[1] to be replay protected") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(blocks[4:]); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// generate an invalid chain id transaction | 
					
						
							| 
									
										
										
										
											2019-10-16 13:23:14 +02:00
										 |  |  | 	config := ¶ms.ChainConfig{ChainID: big.NewInt(2), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 		var ( | 
					
						
							|  |  |  | 			tx      *types.Transaction | 
					
						
							|  |  |  | 			err     error | 
					
						
							|  |  |  | 			basicTx = func(signer types.Signer) (*types.Transaction, error) { | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 				return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2018-07-30 11:30:09 +02:00
										 |  |  | 		if i == 0 { | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			tx, err = basicTx(types.LatestSigner(config)) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	_, err := blockchain.InsertChain(blocks) | 
					
						
							| 
									
										
										
										
											2021-05-18 01:10:28 +02:00
										 |  |  | 	if have, want := err, types.ErrInvalidChainId; !errors.Is(have, want) { | 
					
						
							|  |  |  | 		t.Errorf("have %v, want %v", have, want) | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestEIP161AccountRemoval(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db      = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 		funds   = big.NewInt(1000000000) | 
					
						
							|  |  |  | 		theAddr = common.Address{1} | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config: ¶ms.ChainConfig{ | 
					
						
							| 
									
										
										
										
											2018-06-05 03:31:34 -07:00
										 |  |  | 				ChainID:        big.NewInt(1), | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 				HomesteadBlock: new(big.Int), | 
					
						
							|  |  |  | 				EIP155Block:    new(big.Int), | 
					
						
							| 
									
										
										
										
											2019-10-16 13:23:14 +02:00
										 |  |  | 				EIP150Block:    new(big.Int), | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 				EIP158Block:    big.NewInt(2), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Alloc: GenesisAlloc{address: {Balance: funds}}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2017-08-07 15:47:25 +03:00
										 |  |  | 	defer blockchain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 20:37:50 +08:00
										 |  |  | 	blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		var ( | 
					
						
							|  |  |  | 			tx     *types.Transaction | 
					
						
							|  |  |  | 			err    error | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			signer = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		) | 
					
						
							|  |  |  | 		switch i { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 			tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		case 1: | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 			tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		case 2: | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 			tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		block.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// account must exist pre eip 161 | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	if st, _ := blockchain.State(); !st.Exist(theAddr) { | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 		t.Error("expected account to exist") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// account needs to be deleted post eip 161 | 
					
						
							|  |  |  | 	if _, err := blockchain.InsertChain(types.Blocks{blocks[1]}); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	if st, _ := blockchain.State(); st.Exist(theAddr) { | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		t.Error("account should not exist") | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-25 16:21:28 +08:00
										 |  |  | 	// account mustn't be created post eip 161 | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 	if _, err := blockchain.InsertChain(types.Blocks{blocks[2]}); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	if st, _ := blockchain.State(); st.Exist(theAddr) { | 
					
						
							| 
									
										
										
										
											2017-03-02 14:03:33 +01:00
										 |  |  | 		t.Error("account should not exist") | 
					
						
							| 
									
										
										
										
											2016-11-28 01:33:28 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This is a regression test (i.e. as weird as it is, don't delete it ever), which | 
					
						
							|  |  |  | // tests that under weird reorg conditions the blockchain and its internal header- | 
					
						
							|  |  |  | // chain return the same latest block/header. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // https://github.com/ethereum/go-ethereum/pull/15941 | 
					
						
							|  |  |  | func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { | 
					
						
							|  |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate a bunch of fork blocks, each side forking from the canonical chain | 
					
						
							|  |  |  | 	forks := make([]*types.Block, len(blocks)) | 
					
						
							|  |  |  | 	for i := 0; i < len(forks); i++ { | 
					
						
							|  |  |  | 		parent := genesis | 
					
						
							|  |  |  | 		if i > 0 { | 
					
						
							|  |  |  | 			parent = blocks[i-1] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) | 
					
						
							|  |  |  | 		forks[i] = fork[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the canonical and fork chain side by side, verifying the current block | 
					
						
							|  |  |  | 	// and current header consistency | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < len(blocks); i++ { | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(blocks[i : i+1]); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: failed to insert into chain: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:35:00 +03:00
										 |  |  | 			t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(forks[i : i+1]); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf(" fork %d: failed to insert into chain: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:35:00 +03:00
										 |  |  | 			t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) | 
					
						
							| 
									
										
										
										
											2018-01-22 14:07:47 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that importing small side forks doesn't leave junk in the trie database | 
					
						
							|  |  |  | // cache (which would eventually cause memory issues). | 
					
						
							|  |  |  | func TestTrieForkGC(t *testing.T) { | 
					
						
							|  |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate a bunch of fork blocks, each side forking from the canonical chain | 
					
						
							|  |  |  | 	forks := make([]*types.Block, len(blocks)) | 
					
						
							|  |  |  | 	for i := 0; i < len(forks); i++ { | 
					
						
							|  |  |  | 		parent := genesis | 
					
						
							|  |  |  | 		if i > 0 { | 
					
						
							|  |  |  | 			parent = blocks[i-1] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) | 
					
						
							|  |  |  | 		forks[i] = fork[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the canonical and fork chain side by side, forcing the trie cache to cache both | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < len(blocks); i++ { | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(blocks[i : i+1]); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: failed to insert into chain: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(forks[i : i+1]); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("fork %d: failed to insert into chain: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Dereference all the recent tries and ensure no past trie is left in | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	for i := 0; i < TriesInMemory; i++ { | 
					
						
							| 
									
										
										
										
											2018-06-21 12:28:05 +03:00
										 |  |  | 		chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) | 
					
						
							|  |  |  | 		chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if len(chain.stateCache.TrieDB().Nodes()) > 0 { | 
					
						
							|  |  |  | 		t.Fatalf("stale tries still alive after garbase collection") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that doing large reorgs works even if the state associated with the | 
					
						
							|  |  |  | // forking point is not available any more. | 
					
						
							|  |  |  | func TestLargeReorgTrieGC(t *testing.T) { | 
					
						
							|  |  |  | 	// Generate the original common chain segment and the two competing forks | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) | 
					
						
							|  |  |  | 	competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Import the shared chain and the original canonical one | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := chain.InsertChain(shared); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert shared chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := chain.InsertChain(original); err != nil { | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 		t.Fatalf("failed to insert original chain: %v", err) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that the state associated with the forking point is pruned away | 
					
						
							|  |  |  | 	if node, _ := chain.stateCache.TrieDB().Node(shared[len(shared)-1].Root()); node != nil { | 
					
						
							|  |  |  | 		t.Fatalf("common-but-old ancestor still cache") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the competitor chain without exceeding the canonical's TD and ensure | 
					
						
							|  |  |  | 	// we have not processed any of the blocks (protection against malicious blocks) | 
					
						
							|  |  |  | 	if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert competitor chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, block := range competitor[:len(competitor)-2] { | 
					
						
							|  |  |  | 		if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { | 
					
						
							|  |  |  | 			t.Fatalf("competitor %d: low TD chain became processed", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the head of the competitor chain, triggering the reorg and ensure we | 
					
						
							|  |  |  | 	// successfully reprocess all the stashed away blocks. | 
					
						
							|  |  |  | 	if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to finalize competitor chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	for i, block := range competitor[:len(competitor)-TriesInMemory] { | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { | 
					
						
							|  |  |  | 			t.Fatalf("competitor %d: competing chain state missing", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-07 23:20:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | func TestBlockchainRecovery(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 		funds   = big.NewInt(1000000000) | 
					
						
							|  |  |  | 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	height := uint64(1024) | 
					
						
							|  |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import the chain as a ancient-first node and ensure all pointers are updated | 
					
						
							|  |  |  | 	frdir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(frdir) | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	rawdb.WriteLastPivotNumber(ancientDb, blocks[len(blocks)-1].NumberU64()) // Force fast sync behavior | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	ancient.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Destroy head fast block manually | 
					
						
							|  |  |  | 	midBlock := blocks[len(blocks)/2] | 
					
						
							|  |  |  | 	rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Reopen broken blockchain again | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	defer ancient.Stop() | 
					
						
							|  |  |  | 	if num := ancient.CurrentBlock().NumberU64(); num != 0 { | 
					
						
							|  |  |  | 		t.Errorf("head block mismatch: have #%v, want #%v", num, 0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if num := ancient.CurrentFastBlock().NumberU64(); num != midBlock.NumberU64() { | 
					
						
							|  |  |  | 		t.Errorf("head fast-block mismatch: have #%v, want #%v", num, midBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if num := ancient.CurrentHeader().Number.Uint64(); num != midBlock.NumberU64() { | 
					
						
							|  |  |  | 		t.Errorf("head header mismatch: have #%v, want #%v", num, midBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestIncompleteAncientReceiptChainInsertion(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 		funds   = big.NewInt(1000000000) | 
					
						
							|  |  |  | 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	height := uint64(1024) | 
					
						
							|  |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import the chain as a ancient-first node and ensure all pointers are updated | 
					
						
							|  |  |  | 	frdir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(frdir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	defer ancient.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Abort ancient receipt chain insertion deliberately | 
					
						
							|  |  |  | 	ancient.terminateInsert = func(hash common.Hash, number uint64) bool { | 
					
						
							| 
									
										
										
										
											2019-05-16 14:30:11 +03:00
										 |  |  | 		return number == blocks[len(blocks)/2].NumberU64() | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	previousFastBlock := ancient.CurrentFastBlock() | 
					
						
							|  |  |  | 	if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err == nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ancient.CurrentFastBlock().NumberU64() != previousFastBlock.NumberU64() { | 
					
						
							|  |  |  | 		t.Fatalf("failed to rollback ancient data, want %d, have %d", previousFastBlock.NumberU64(), ancient.CurrentFastBlock().NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if frozen, err := ancient.db.Ancients(); err != nil || frozen != 1 { | 
					
						
							|  |  |  | 		t.Fatalf("failed to truncate ancient data") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ancient.terminateInsert = nil | 
					
						
							|  |  |  | 	if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert receipt %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ancient.CurrentFastBlock().NumberU64() != blocks[len(blocks)-1].NumberU64() { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert ancient recept chain after rollback") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | // Tests that importing a very large side fork, which is larger than the canon chain, | 
					
						
							|  |  |  | // but where the difficulty per block is kept low: this means that it will not | 
					
						
							|  |  |  | // overtake the 'canon' chain until after it's passed canon by about 200 blocks. | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // Details at: | 
					
						
							|  |  |  | //  - https://github.com/ethereum/go-ethereum/issues/18977 | 
					
						
							|  |  |  | //  - https://github.com/ethereum/go-ethereum/pull/18988 | 
					
						
							|  |  |  | func TestLowDiffLongChain(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// We must use a pretty long chain to ensure that the fork doesn't overtake us | 
					
						
							|  |  |  | 	// until after at least 128 blocks post tip | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TriesInMemory, func(i int, b *BlockGen) { | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		b.OffsetTime(-9) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Generate fork chain, starting from an early block | 
					
						
							|  |  |  | 	parent := blocks[10] | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*TriesInMemory, func(i int, b *BlockGen) { | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | 		b.SetCoinbase(common.Address{2}) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// And now import the fork | 
					
						
							|  |  |  | 	if i, err := chain.InsertChain(fork); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", i, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	head := chain.CurrentBlock() | 
					
						
							|  |  |  | 	if got := fork[len(fork)-1].Hash(); got != head.Hash() { | 
					
						
							|  |  |  | 		t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-08 11:11:31 +02:00
										 |  |  | 	// Sanity check that all the canonical numbers are present | 
					
						
							|  |  |  | 	header := chain.CurrentHeader() | 
					
						
							|  |  |  | 	for number := head.NumberU64(); number > 0; number-- { | 
					
						
							|  |  |  | 		if hash := chain.GetHeaderByNumber(number).Hash(); hash != header.Hash() { | 
					
						
							|  |  |  | 			t.Fatalf("header %d: canonical hash mismatch: have %x, want %x", number, hash, header.Hash()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		header = chain.GetHeader(header.ParentHash, number-1) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-04 11:54:39 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that importing a sidechain (S), where | 
					
						
							|  |  |  | // - S is sidechain, containing blocks [Sn...Sm] | 
					
						
							|  |  |  | // - C is canon chain, containing blocks [G..Cn..Cm] | 
					
						
							|  |  |  | // - A common ancestor is placed at prune-point + blocksBetweenCommonAncestorAndPruneblock | 
					
						
							|  |  |  | // - The sidechain S is prepended with numCanonBlocksInSidechain blocks from the canon chain | 
					
						
							|  |  |  | func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommonAncestorAndPruneblock int) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate and import the canonical chain | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	lastPrunedIndex := len(blocks) - TriesInMemory - 1 | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 	lastPrunedBlock := blocks[lastPrunedIndex] | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Verify pruning of lastPrunedBlock | 
					
						
							|  |  |  | 	if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { | 
					
						
							|  |  |  | 		t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Verify firstNonPrunedBlock is not pruned | 
					
						
							|  |  |  | 	if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { | 
					
						
							|  |  |  | 		t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Generate the sidechain | 
					
						
							|  |  |  | 	// First block should be a known block, block after should be a pruned block. So | 
					
						
							|  |  |  | 	// canon(pruned), side, side... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate fork chain, make it longer than canon | 
					
						
							|  |  |  | 	parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock | 
					
						
							|  |  |  | 	parent := blocks[parentIndex] | 
					
						
							| 
									
										
										
										
											2019-05-30 20:51:13 +02:00
										 |  |  | 	fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { | 
					
						
							| 
									
										
										
										
											2019-02-21 11:36:49 +01:00
										 |  |  | 		b.SetCoinbase(common.Address{2}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Prepend the parent(s) | 
					
						
							|  |  |  | 	var sidechain []*types.Block | 
					
						
							|  |  |  | 	for i := numCanonBlocksInSidechain; i > 0; i-- { | 
					
						
							|  |  |  | 		sidechain = append(sidechain, blocks[parentIndex+1-i]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sidechain = append(sidechain, fork...) | 
					
						
							|  |  |  | 	_, err = chain.InsertChain(sidechain) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Got error, %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	head := chain.CurrentBlock() | 
					
						
							|  |  |  | 	if got := fork[len(fork)-1].Hash(); got != head.Hash() { | 
					
						
							|  |  |  | 		t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that importing a sidechain (S), where | 
					
						
							|  |  |  | // - S is sidechain, containing blocks [Sn...Sm] | 
					
						
							|  |  |  | // - C is canon chain, containing blocks [G..Cn..Cm] | 
					
						
							|  |  |  | // - The common ancestor Cc is pruned | 
					
						
							|  |  |  | // - The first block in S: Sn, is == Cn | 
					
						
							|  |  |  | // That is: the sidechain for import contains some blocks already present in canon chain. | 
					
						
							|  |  |  | // So the blocks are | 
					
						
							|  |  |  | // [ Cn, Cn+1, Cc, Sn+3 ... Sm] | 
					
						
							|  |  |  | //   ^    ^    ^  pruned | 
					
						
							|  |  |  | func TestPrunedImportSide(t *testing.T) { | 
					
						
							|  |  |  | 	//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) | 
					
						
							|  |  |  | 	//glogger.Verbosity(3) | 
					
						
							|  |  |  | 	//log.Root().SetHandler(log.Handler(glogger)) | 
					
						
							|  |  |  | 	testSideImport(t, 3, 3) | 
					
						
							|  |  |  | 	testSideImport(t, 3, -3) | 
					
						
							|  |  |  | 	testSideImport(t, 10, 0) | 
					
						
							|  |  |  | 	testSideImport(t, 1, 10) | 
					
						
							|  |  |  | 	testSideImport(t, 1, -10) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | func TestInsertKnownHeaders(t *testing.T)      { testInsertKnownChainData(t, "headers") } | 
					
						
							|  |  |  | func TestInsertKnownReceiptChain(t *testing.T) { testInsertKnownChainData(t, "receipts") } | 
					
						
							|  |  |  | func TestInsertKnownBlocks(t *testing.T)       { testInsertKnownChainData(t, "blocks") } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testInsertKnownChainData(t *testing.T, typ string) { | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	blocks, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) | 
					
						
							|  |  |  | 	// A longer chain but total difficulty is lower. | 
					
						
							|  |  |  | 	blocks2, receipts2 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) | 
					
						
							|  |  |  | 	// A shorter chain but total difficulty is higher. | 
					
						
							|  |  |  | 	blocks3, receipts3 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 64, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		b.OffsetTime(-9) // A higher difficulty | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the shared chain and the original canonical one | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	dir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(dir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	defer os.RemoveAll(dir) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		inserter func(blocks []*types.Block, receipts []types.Receipts) error | 
					
						
							|  |  |  | 		asserter func(t *testing.T, block *types.Block) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if typ == "headers" { | 
					
						
							|  |  |  | 		inserter = func(blocks []*types.Block, receipts []types.Receipts) error { | 
					
						
							|  |  |  | 			headers := make([]*types.Header, 0, len(blocks)) | 
					
						
							|  |  |  | 			for _, block := range blocks { | 
					
						
							|  |  |  | 				headers = append(headers, block.Header()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			_, err := chain.InsertHeaderChain(headers, 1) | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		asserter = func(t *testing.T, block *types.Block) { | 
					
						
							|  |  |  | 			if chain.CurrentHeader().Hash() != block.Hash() { | 
					
						
							|  |  |  | 				t.Fatalf("current head header mismatch, have %v, want %v", chain.CurrentHeader().Hash().Hex(), block.Hash().Hex()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if typ == "receipts" { | 
					
						
							|  |  |  | 		inserter = func(blocks []*types.Block, receipts []types.Receipts) error { | 
					
						
							|  |  |  | 			headers := make([]*types.Header, 0, len(blocks)) | 
					
						
							|  |  |  | 			for _, block := range blocks { | 
					
						
							|  |  |  | 				headers = append(headers, block.Header()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			_, err := chain.InsertHeaderChain(headers, 1) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
											
												all: integrate the freezer with fast sync
* all: freezer style syncing
core, eth, les, light: clean up freezer relative APIs
core, eth, les, trie, ethdb, light: clean a bit
core, eth, les, light: add unit tests
core, light: rewrite setHead function
core, eth: fix downloader unit tests
core: add receipt chain insertion test
core: use constant instead of hardcoding table name
core: fix rollback
core: fix setHead
core/rawdb: remove canonical block first and then iterate side chain
core/rawdb, ethdb: add hasAncient interface
eth/downloader: calculate ancient limit via cht first
core, eth, ethdb: lots of fixes
* eth/downloader: print ancient disable log only for fast sync
											
										 
											2019-04-25 22:59:48 +08:00
										 |  |  | 			_, err = chain.InsertReceiptChain(blocks, receipts, 0) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		asserter = func(t *testing.T, block *types.Block) { | 
					
						
							|  |  |  | 			if chain.CurrentFastBlock().Hash() != block.Hash() { | 
					
						
							|  |  |  | 				t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		inserter = func(blocks []*types.Block, receipts []types.Receipts) error { | 
					
						
							|  |  |  | 			_, err := chain.InsertChain(blocks) | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		asserter = func(t *testing.T, block *types.Block) { | 
					
						
							|  |  |  | 			if chain.CurrentBlock().Hash() != block.Hash() { | 
					
						
							|  |  |  | 				t.Fatalf("current head block mismatch, have %v, want %v", chain.CurrentBlock().Hash().Hex(), block.Hash().Hex()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := inserter(blocks, receipts); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Reimport the chain data again. All the imported | 
					
						
							|  |  |  | 	// chain data are regarded "known" data. | 
					
						
							|  |  |  | 	if err := inserter(blocks, receipts); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	asserter(t, blocks[len(blocks)-1]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import a long canonical chain with some known data as prefix. | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	rollback := blocks[len(blocks)/2].NumberU64() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chain.SetHead(rollback - 1) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 	if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	asserter(t, blocks2[len(blocks2)-1]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import a heavier shorter but higher total difficulty chain with some known data as prefix. | 
					
						
							|  |  |  | 	if err := inserter(append(blocks, blocks3...), append(receipts, receipts3...)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	asserter(t, blocks3[len(blocks3)-1]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import a longer but lower total difficulty chain with some known data as prefix. | 
					
						
							|  |  |  | 	if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// The head shouldn't change. | 
					
						
							|  |  |  | 	asserter(t, blocks3[len(blocks3)-1]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	// Rollback the heavier chain and re-insert the longer chain again | 
					
						
							| 
									
										
										
										
											2020-08-20 13:01:24 +03:00
										 |  |  | 	chain.SetHead(rollback - 1) | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert chain data: %v", err) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
											
												core, cmd, vendor: fixes and database inspection tool (#15)
* core, eth: some fixes for freezer
* vendor, core/rawdb, cmd/geth: add db inspector
* core, cmd/utils: check ancient store path forceily
* cmd/geth, common, core/rawdb: a few fixes
* cmd/geth: support windows file rename and fix rename error
* core: support ancient plugin
* core, cmd: streaming file copy
* cmd, consensus, core, tests: keep genesis in leveldb
* core: write txlookup during ancient init
* core: bump database version
											
										 
											2019-05-14 22:07:44 +08:00
										 |  |  | 	asserter(t, blocks2[len(blocks2)-1]) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | // getLongAndShortChains returns two chains, | 
					
						
							|  |  |  | // A is longer, B is heavier | 
					
						
							|  |  |  | func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, error) { | 
					
						
							|  |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate and import the canonical chain, | 
					
						
							|  |  |  | 	// Offset the time, to keep the difficulty low | 
					
						
							|  |  |  | 	longChain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 80, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-05-07 14:26:00 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate fork chain, make it shorter than canon, with common ancestor pretty early | 
					
						
							|  |  |  | 	parentIndex := 3 | 
					
						
							|  |  |  | 	parent := longChain[parentIndex] | 
					
						
							|  |  |  | 	heavyChain, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 75, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{2}) | 
					
						
							|  |  |  | 		b.OffsetTime(-9) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Verify that the test is sane | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		longerTd  = new(big.Int) | 
					
						
							|  |  |  | 		shorterTd = new(big.Int) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for index, b := range longChain { | 
					
						
							|  |  |  | 		longerTd.Add(longerTd, b.Difficulty()) | 
					
						
							|  |  |  | 		if index <= parentIndex { | 
					
						
							|  |  |  | 			shorterTd.Add(shorterTd, b.Difficulty()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, b := range heavyChain { | 
					
						
							|  |  |  | 		shorterTd.Add(shorterTd, b.Difficulty()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if shorterTd.Cmp(longerTd) <= 0 { | 
					
						
							|  |  |  | 		return nil, nil, nil, fmt.Errorf("Test is moot, heavyChain td (%v) must be larger than canon td (%v)", shorterTd, longerTd) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	longerNum := longChain[len(longChain)-1].NumberU64() | 
					
						
							|  |  |  | 	shorterNum := heavyChain[len(heavyChain)-1].NumberU64() | 
					
						
							|  |  |  | 	if shorterNum >= longerNum { | 
					
						
							|  |  |  | 		return nil, nil, nil, fmt.Errorf("Test is moot, heavyChain num (%v) must be lower than canon num (%v)", shorterNum, longerNum) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return chain, longChain, heavyChain, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestReorgToShorterRemovesCanonMapping tests that if we | 
					
						
							|  |  |  | // 1. Have a chain [0 ... N .. X] | 
					
						
							|  |  |  | // 2. Reorg to shorter but heavier chain [0 ... N ... Y] | 
					
						
							|  |  |  | // 3. Then there should be no canon mapping for the block at height X | 
					
						
							|  |  |  | func TestReorgToShorterRemovesCanonMapping(t *testing.T) { | 
					
						
							|  |  |  | 	chain, canonblocks, sideblocks, err := getLongAndShortChains() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(canonblocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	canonNum := chain.CurrentBlock().NumberU64() | 
					
						
							|  |  |  | 	_, err = chain.InsertChain(sideblocks) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Got error, %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	head := chain.CurrentBlock() | 
					
						
							|  |  |  | 	if got := sideblocks[len(sideblocks)-1].Hash(); got != head.Hash() { | 
					
						
							|  |  |  | 		t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// We have now inserted a sidechain. | 
					
						
							|  |  |  | 	if blockByNum := chain.GetBlockByNumber(canonNum); blockByNum != nil { | 
					
						
							|  |  |  | 		t.Errorf("expected block to be gone: %v", blockByNum.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if headerByNum := chain.GetHeaderByNumber(canonNum); headerByNum != nil { | 
					
						
							|  |  |  | 		t.Errorf("expected header to be gone: %v", headerByNum.Number.Uint64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestReorgToShorterRemovesCanonMappingHeaderChain is the same scenario | 
					
						
							|  |  |  | // as TestReorgToShorterRemovesCanonMapping, but applied on headerchain | 
					
						
							|  |  |  | // imports -- that is, for fast sync | 
					
						
							|  |  |  | func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { | 
					
						
							|  |  |  | 	chain, canonblocks, sideblocks, err := getLongAndShortChains() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Convert into headers | 
					
						
							|  |  |  | 	canonHeaders := make([]*types.Header, len(canonblocks)) | 
					
						
							|  |  |  | 	for i, block := range canonblocks { | 
					
						
							|  |  |  | 		canonHeaders[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertHeaderChain(canonHeaders, 0); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("header %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	canonNum := chain.CurrentHeader().Number.Uint64() | 
					
						
							|  |  |  | 	sideHeaders := make([]*types.Header, len(sideblocks)) | 
					
						
							|  |  |  | 	for i, block := range sideblocks { | 
					
						
							|  |  |  | 		sideHeaders[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertHeaderChain(sideHeaders, 0); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("header %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	head := chain.CurrentHeader() | 
					
						
							|  |  |  | 	if got := sideblocks[len(sideblocks)-1].Hash(); got != head.Hash() { | 
					
						
							|  |  |  | 		t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// We have now inserted a sidechain. | 
					
						
							|  |  |  | 	if blockByNum := chain.GetBlockByNumber(canonNum); blockByNum != nil { | 
					
						
							|  |  |  | 		t.Errorf("expected block to be gone: %v", blockByNum.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if headerByNum := chain.GetHeaderByNumber(canonNum); headerByNum != nil { | 
					
						
							|  |  |  | 		t.Errorf("expected header to be gone: %v", headerByNum.Number.Uint64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | func TestTransactionIndices(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(100000000000000000) | 
					
						
							|  |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config:  params.TestChainConfig, | 
					
						
							|  |  |  | 			Alloc:   GenesisAlloc{address: {Balance: funds}}, | 
					
						
							|  |  |  | 			BaseFee: big.NewInt(params.InitialBaseFee), | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	height := uint64(128) | 
					
						
							|  |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		block.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	blocks2, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), gendb, 10, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	check := func(tail *uint64, chain *BlockChain) { | 
					
						
							|  |  |  | 		stored := rawdb.ReadTxIndexTail(chain.db) | 
					
						
							|  |  |  | 		if tail == nil && stored != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Oldest indexded block mismatch, want nil, have %d", *stored) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tail != nil && *stored != *tail { | 
					
						
							|  |  |  | 			t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tail != nil { | 
					
						
							|  |  |  | 			for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ { | 
					
						
							|  |  |  | 				block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) | 
					
						
							|  |  |  | 				if block.Transactions().Len() == 0 { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for _, tx := range block.Transactions() { | 
					
						
							|  |  |  | 					if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index == nil { | 
					
						
							|  |  |  | 						t.Fatalf("Miss transaction indice, number %d hash %s", i, tx.Hash().Hex()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for i := uint64(0); i < *tail; i++ { | 
					
						
							|  |  |  | 				block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) | 
					
						
							|  |  |  | 				if block.Transactions().Len() == 0 { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for _, tx := range block.Transactions() { | 
					
						
							|  |  |  | 					if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index != nil { | 
					
						
							|  |  |  | 						t.Fatalf("Transaction indice should be deleted, number %d hash %s", i, tx.Hash().Hex()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	frdir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(frdir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import all blocks into ancient db | 
					
						
							|  |  |  | 	l := uint64(0) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertHeaderChain(headers, 0); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertReceiptChain(blocks, receipts, 128); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	chain.Stop() | 
					
						
							|  |  |  | 	ancientDb.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Init block chain with external ancients, check all needed indices has been indexed. | 
					
						
							|  |  |  | 	limit := []uint64{0, 32, 64, 128} | 
					
						
							|  |  |  | 	for _, l := range limit { | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 		ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		gspec.MustCommit(ancientDb) | 
					
						
							|  |  |  | 		chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		time.Sleep(50 * time.Millisecond) // Wait for indices initialisation | 
					
						
							|  |  |  | 		var tail uint64 | 
					
						
							|  |  |  | 		if l != 0 { | 
					
						
							|  |  |  | 			tail = uint64(128) - l + 1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		check(&tail, chain) | 
					
						
							|  |  |  | 		chain.Stop() | 
					
						
							|  |  |  | 		ancientDb.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Reconstruct a block chain which only reserves HEAD-64 tx indices | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */} | 
					
						
							|  |  |  | 	tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} | 
					
						
							|  |  |  | 	for i, l := range limit { | 
					
						
							|  |  |  | 		chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		chain.InsertChain(blocks2[i : i+1]) // Feed chain a higher block to trigger indices updater. | 
					
						
							|  |  |  | 		time.Sleep(50 * time.Millisecond)   // Wait for indices initialisation | 
					
						
							|  |  |  | 		check(&tails[i], chain) | 
					
						
							|  |  |  | 		chain.Stop() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestSkipStaleTxIndicesInFastSync(t *testing.T) { | 
					
						
							|  |  |  | 	// Configure and generate a sample block chain | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		gendb   = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(100000000000000000) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(gendb) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		signer  = types.LatestSigner(gspec.Config) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	height := uint64(128) | 
					
						
							|  |  |  | 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		block.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	check := func(tail *uint64, chain *BlockChain) { | 
					
						
							|  |  |  | 		stored := rawdb.ReadTxIndexTail(chain.db) | 
					
						
							|  |  |  | 		if tail == nil && stored != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Oldest indexded block mismatch, want nil, have %d", *stored) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tail != nil && *stored != *tail { | 
					
						
							|  |  |  | 			t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tail != nil { | 
					
						
							|  |  |  | 			for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ { | 
					
						
							|  |  |  | 				block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) | 
					
						
							|  |  |  | 				if block.Transactions().Len() == 0 { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for _, tx := range block.Transactions() { | 
					
						
							|  |  |  | 					if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index == nil { | 
					
						
							|  |  |  | 						t.Fatalf("Miss transaction indice, number %d hash %s", i, tx.Hash().Hex()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for i := uint64(0); i < *tail; i++ { | 
					
						
							|  |  |  | 				block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) | 
					
						
							|  |  |  | 				if block.Transactions().Len() == 0 { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for _, tx := range block.Transactions() { | 
					
						
							|  |  |  | 					if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index != nil { | 
					
						
							|  |  |  | 						t.Fatalf("Transaction indice should be deleted, number %d hash %s", i, tx.Hash().Hex()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frdir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.Remove(frdir) | 
					
						
							| 
									
										
										
										
											2021-03-23 02:06:30 +08:00
										 |  |  | 	ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temp freezer db: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gspec.MustCommit(ancientDb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import all blocks into ancient db, only HEAD-32 indices are kept. | 
					
						
							|  |  |  | 	l := uint64(32) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	headers := make([]*types.Header, len(blocks)) | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		headers[i] = block.Header() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertHeaderChain(headers, 0); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to insert header %d: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// The indices before ancient-N(32) should be ignored. After that all blocks should be indexed. | 
					
						
							|  |  |  | 	if n, err := chain.InsertReceiptChain(blocks, receipts, 64); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tail := uint64(32) | 
					
						
							|  |  |  | 	check(&tail, chain) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | // Benchmarks large blocks with value transfers to non-existing accounts | 
					
						
							|  |  |  | func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		signer          = types.HomesteadSigner{} | 
					
						
							|  |  |  | 		testBankKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) | 
					
						
							|  |  |  | 		bankFunds       = big.NewInt(100000000000000000) | 
					
						
							|  |  |  | 		gspec           = Genesis{ | 
					
						
							|  |  |  | 			Config: params.TestChainConfig, | 
					
						
							|  |  |  | 			Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 				testBankAddress: {Balance: bankFunds}, | 
					
						
							|  |  |  | 				common.HexToAddress("0xc0de"): { | 
					
						
							|  |  |  | 					Code:    []byte{0x60, 0x01, 0x50}, | 
					
						
							|  |  |  | 					Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				}, // push 1, pop | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			GasLimit: 100e6, // 100 M | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// Generate the original common chain segment and the two competing forks | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blockGenerator := func(i int, block *BlockGen) { | 
					
						
							|  |  |  | 		block.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		for txi := 0; txi < numTxs; txi++ { | 
					
						
							|  |  |  | 			uniq := uint64(i*numTxs + txi) | 
					
						
							|  |  |  | 			recipient := recipientFn(uniq) | 
					
						
							|  |  |  | 			tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				b.Error(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			block.AddTx(tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator) | 
					
						
							|  |  |  | 	b.StopTimer() | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		// Import the shared chain and the original canonical one | 
					
						
							|  |  |  | 		diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 		chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-05-08 19:30:36 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			b.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b.StartTimer() | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(shared); err != nil { | 
					
						
							|  |  |  | 			b.Fatalf("failed to insert shared chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b.StopTimer() | 
					
						
							|  |  |  | 		if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { | 
					
						
							|  |  |  | 			b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		numTxs    = 1000 | 
					
						
							|  |  |  | 		numBlocks = 1 | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	recipientFn := func(nonce uint64) common.Address { | 
					
						
							|  |  |  | 		return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dataFn := func(nonce uint64) []byte { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		numTxs    = 1000 | 
					
						
							|  |  |  | 		numBlocks = 1 | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	b.StopTimer() | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	recipientFn := func(nonce uint64) common.Address { | 
					
						
							|  |  |  | 		return common.BigToAddress(big.NewInt(0).SetUint64(1337)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dataFn := func(nonce uint64) []byte { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkBlockChain_1x1000Executions(b *testing.B) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		numTxs    = 1000 | 
					
						
							|  |  |  | 		numBlocks = 1 | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	b.StopTimer() | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	recipientFn := func(nonce uint64) common.Address { | 
					
						
							|  |  |  | 		return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dataFn := func(nonce uint64) []byte { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-21 09:17:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that importing a some old blocks, where all blocks are before the | 
					
						
							|  |  |  | // pruning point. | 
					
						
							|  |  |  | // This internally leads to a sidechain import, since the blocks trigger an | 
					
						
							|  |  |  | // ErrPrunedAncestor error. | 
					
						
							|  |  |  | // This may e.g. happen if | 
					
						
							|  |  |  | //   1. Downloader rollbacks a batch of inserted blocks and exits | 
					
						
							|  |  |  | //   2. Downloader starts to sync again | 
					
						
							|  |  |  | //   3. The blocks fetched are all known and canonical blocks | 
					
						
							|  |  |  | func TestSideImportPrunedBlocks(t *testing.T) { | 
					
						
							|  |  |  | 	// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) | 
					
						
							| 
									
										
										
										
											2019-08-21 09:17:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate and import the canonical chain | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-08-21 09:17:19 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lastPrunedIndex := len(blocks) - TriesInMemory - 1 | 
					
						
							|  |  |  | 	lastPrunedBlock := blocks[lastPrunedIndex] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify pruning of lastPrunedBlock | 
					
						
							|  |  |  | 	if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { | 
					
						
							|  |  |  | 		t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] | 
					
						
							|  |  |  | 	// Verify firstNonPrunedBlock is not pruned | 
					
						
							|  |  |  | 	if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { | 
					
						
							|  |  |  | 		t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Now re-import some old blocks | 
					
						
							|  |  |  | 	blockToReimport := blocks[5:8] | 
					
						
							|  |  |  | 	_, err = chain.InsertChain(blockToReimport) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Errorf("Got error, %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestDeleteCreateRevert tests a weird state transition corner case that we hit | 
					
						
							|  |  |  | // while changing the internals of statedb. The workflow is that a contract is | 
					
						
							|  |  |  | // self destructed, then in a followup transaction (but same block) it's created | 
					
						
							|  |  |  | // again and the transaction reverted. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The original statedb implementation flushed dirty objects to the tries after | 
					
						
							|  |  |  | // each transaction, so this works ok. The rework accumulated writes in memory | 
					
						
							|  |  |  | // first, but the journal wiped the entire state object on create-revert. | 
					
						
							|  |  |  | func TestDeleteCreateRevert(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") | 
					
						
							|  |  |  | 		bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(100000000000000000) | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config: params.TestChainConfig, | 
					
						
							|  |  |  | 			Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 				address: {Balance: funds}, | 
					
						
							|  |  |  | 				// The address 0xAAAAA selfdestructs if called | 
					
						
							|  |  |  | 				aa: { | 
					
						
							|  |  |  | 					// Code needs to just selfdestruct | 
					
						
							| 
									
										
										
										
											2020-03-03 15:52:00 +02:00
										 |  |  | 					Code:    []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)}, | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 					Nonce:   1, | 
					
						
							|  |  |  | 					Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				// The address 0xBBBB send 1 wei to 0xAAAA, then reverts | 
					
						
							|  |  |  | 				bb: { | 
					
						
							|  |  |  | 					Code: []byte{ | 
					
						
							|  |  |  | 						byte(vm.PC),          // [0] | 
					
						
							|  |  |  | 						byte(vm.DUP1),        // [0,0] | 
					
						
							|  |  |  | 						byte(vm.DUP1),        // [0,0,0] | 
					
						
							|  |  |  | 						byte(vm.DUP1),        // [0,0,0,0] | 
					
						
							|  |  |  | 						byte(vm.PUSH1), 0x01, // [0,0,0,0,1] (value) | 
					
						
							|  |  |  | 						byte(vm.PUSH2), 0xaa, 0xaa, // [0,0,0,0,1, 0xaaaa] | 
					
						
							|  |  |  | 						byte(vm.GAS), | 
					
						
							|  |  |  | 						byte(vm.CALL), | 
					
						
							|  |  |  | 						byte(vm.REVERT), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					Balance: big.NewInt(1), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		// One transaction to AAAA | 
					
						
							|  |  |  | 		tx, _ := types.SignTx(types.NewTransaction(0, aa, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 		// One transaction to BBBB | 
					
						
							|  |  |  | 		tx, _ = types.SignTx(types.NewTransaction(1, bb, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-09-16 11:39:41 +03:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | // TestDeleteRecreateSlots tests a state-transition that contains both deletion | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | // and recreation of contract state. | 
					
						
							|  |  |  | // Contract A exists, has slots 1 and 2 set | 
					
						
							|  |  |  | // Tx 1: Selfdestruct A | 
					
						
							|  |  |  | // Tx 2: Re-create A, set slots 3 and 4 | 
					
						
							|  |  |  | // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, | 
					
						
							|  |  |  | // and then the new slots exist | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | func TestDeleteRecreateSlots(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		key, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address   = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds     = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 		bb        = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | 
					
						
							| 
									
										
										
										
											2020-03-03 15:52:00 +02:00
										 |  |  | 		aaStorage = make(map[common.Hash]common.Hash)          // Initial storage in AA | 
					
						
							|  |  |  | 		aaCode    = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	// Populate two slots | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("01")] = common.HexToHash("01") | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("02")] = common.HexToHash("02") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The bb-code needs to CREATE2 the aa contract. It consists of | 
					
						
							|  |  |  | 	// both initcode and deployment code | 
					
						
							|  |  |  | 	// initcode: | 
					
						
							|  |  |  | 	// 1. Set slots 3=3, 4=4, | 
					
						
							|  |  |  | 	// 2. Return aaCode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initCode := []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x3, // value | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x3, // location | 
					
						
							|  |  |  | 		byte(vm.SSTORE),     // Set slot[3] = 1 | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x4, // value | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x4, // location | 
					
						
							|  |  |  | 		byte(vm.SSTORE), // Set slot[4] = 1 | 
					
						
							|  |  |  | 		// Slots are set, now return the code | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		byte(vm.PUSH2), byte(vm.PC), byte(vm.SELFDESTRUCT), // Push code on stack | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 		byte(vm.PUSH1), 0x0, // memory start on stack | 
					
						
							|  |  |  | 		byte(vm.MSTORE), | 
					
						
							|  |  |  | 		// Code is now in memory. | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x2, // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(32 - 2), // offset | 
					
						
							|  |  |  | 		byte(vm.RETURN), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if l := len(initCode); l > 32 { | 
					
						
							|  |  |  | 		t.Fatalf("init code is too long for a pushx, need a more elaborate deployer") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bbCode := []byte{ | 
					
						
							|  |  |  | 		// Push initcode onto stack | 
					
						
							|  |  |  | 		byte(vm.PUSH1) + byte(len(initCode)-1)} | 
					
						
							|  |  |  | 	bbCode = append(bbCode, initCode...) | 
					
						
							|  |  |  | 	bbCode = append(bbCode, []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x0, // memory start on stack | 
					
						
							|  |  |  | 		byte(vm.MSTORE), | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // salt | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(len(initCode)), // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(32 - len(initCode)), // offset | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // endowment | 
					
						
							|  |  |  | 		byte(vm.CREATE2), | 
					
						
							|  |  |  | 	}...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 	initHash := crypto.Keccak256Hash(initCode) | 
					
						
							|  |  |  | 	aa := crypto.CreateAddress2(bb, [32]byte{}, initHash[:]) | 
					
						
							|  |  |  | 	t.Logf("Destination address: %x\n", aa) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 	gspec := &Genesis{ | 
					
						
							|  |  |  | 		Config: params.TestChainConfig, | 
					
						
							|  |  |  | 		Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 			address: {Balance: funds}, | 
					
						
							|  |  |  | 			// The address 0xAAAAA selfdestructs if called | 
					
						
							|  |  |  | 			aa: { | 
					
						
							|  |  |  | 				// Code needs to just selfdestruct | 
					
						
							|  |  |  | 				Code:    aaCode, | 
					
						
							|  |  |  | 				Nonce:   1, | 
					
						
							|  |  |  | 				Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				Storage: aaStorage, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			// The contract BB recreates AA | 
					
						
							|  |  |  | 			bb: { | 
					
						
							|  |  |  | 				Code:    bbCode, | 
					
						
							|  |  |  | 				Balance: big.NewInt(1), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		// One transaction to AA, to kill it | 
					
						
							|  |  |  | 		tx, _ := types.SignTx(types.NewTransaction(0, aa, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 		// One transaction to BB, to recreate AA | 
					
						
							|  |  |  | 		tx, _ = types.SignTx(types.NewTransaction(1, bb, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ | 
					
						
							|  |  |  | 		Debug:  true, | 
					
						
							|  |  |  | 		Tracer: vm.NewJSONLogger(nil, os.Stdout), | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 	}, nil, nil) | 
					
						
							| 
									
										
										
										
											2020-03-02 13:46:56 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	statedb, _ := chain.State() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If all is correct, then slot 1 and 2 are zero | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 		t.Errorf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 		t.Errorf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Also, 3 and 4 should be set | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("03")), common.HexToHash("03"); got != exp { | 
					
						
							|  |  |  | 		t.Fatalf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("04")), common.HexToHash("04"); got != exp { | 
					
						
							|  |  |  | 		t.Fatalf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestDeleteRecreateAccount tests a state-transition that contains deletion of a | 
					
						
							|  |  |  | // contract with storage, and a recreate of the same contract via a | 
					
						
							|  |  |  | // regular value-transfer | 
					
						
							|  |  |  | // Expected outcome is that _all_ slots are cleared from A | 
					
						
							|  |  |  | func TestDeleteRecreateAccount(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		aa        = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f43") | 
					
						
							| 
									
										
										
										
											2020-03-03 15:52:00 +02:00
										 |  |  | 		aaStorage = make(map[common.Hash]common.Hash)          // Initial storage in AA | 
					
						
							|  |  |  | 		aaCode    = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	// Populate two slots | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("01")] = common.HexToHash("01") | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("02")] = common.HexToHash("02") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gspec := &Genesis{ | 
					
						
							|  |  |  | 		Config: params.TestChainConfig, | 
					
						
							|  |  |  | 		Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 			address: {Balance: funds}, | 
					
						
							|  |  |  | 			// The address 0xAAAAA selfdestructs if called | 
					
						
							|  |  |  | 			aa: { | 
					
						
							|  |  |  | 				// Code needs to just selfdestruct | 
					
						
							|  |  |  | 				Code:    aaCode, | 
					
						
							|  |  |  | 				Nonce:   1, | 
					
						
							|  |  |  | 				Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				Storage: aaStorage, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		// One transaction to AA, to kill it | 
					
						
							|  |  |  | 		tx, _ := types.SignTx(types.NewTransaction(0, aa, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 		// One transaction to AA, to recreate it (but without storage | 
					
						
							|  |  |  | 		tx, _ = types.SignTx(types.NewTransaction(1, aa, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(1), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ | 
					
						
							|  |  |  | 		Debug:  true, | 
					
						
							|  |  |  | 		Tracer: vm.NewJSONLogger(nil, os.Stdout), | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 	}, nil, nil) | 
					
						
							| 
									
										
										
										
											2020-03-02 14:06:44 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	statedb, _ := chain.State() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If all is correct, then both slots are zero | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 		t.Errorf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 		t.Errorf("got %x exp %x", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestDeleteRecreateSlotsAcrossManyBlocks tests multiple state-transition that contains both deletion | 
					
						
							|  |  |  | // and recreation of contract state. | 
					
						
							|  |  |  | // Contract A exists, has slots 1 and 2 set | 
					
						
							|  |  |  | // Tx 1: Selfdestruct A | 
					
						
							|  |  |  | // Tx 2: Re-create A, set slots 3 and 4 | 
					
						
							|  |  |  | // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, | 
					
						
							|  |  |  | // and then the new slots exist | 
					
						
							|  |  |  | func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address   = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds     = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		bb        = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | 
					
						
							|  |  |  | 		aaStorage = make(map[common.Hash]common.Hash)          // Initial storage in AA | 
					
						
							|  |  |  | 		aaCode    = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// Populate two slots | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("01")] = common.HexToHash("01") | 
					
						
							|  |  |  | 	aaStorage[common.HexToHash("02")] = common.HexToHash("02") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The bb-code needs to CREATE2 the aa contract. It consists of | 
					
						
							|  |  |  | 	// both initcode and deployment code | 
					
						
							|  |  |  | 	// initcode: | 
					
						
							|  |  |  | 	// 1. Set slots 3=blocknum+1, 4=4, | 
					
						
							|  |  |  | 	// 2. Return aaCode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initCode := []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x1, // | 
					
						
							|  |  |  | 		byte(vm.NUMBER),     // value = number + 1 | 
					
						
							|  |  |  | 		byte(vm.ADD),        // | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x3, // location | 
					
						
							|  |  |  | 		byte(vm.SSTORE),     // Set slot[3] = number + 1 | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x4, // value | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x4, // location | 
					
						
							|  |  |  | 		byte(vm.SSTORE), // Set slot[4] = 4 | 
					
						
							|  |  |  | 		// Slots are set, now return the code | 
					
						
							|  |  |  | 		byte(vm.PUSH2), byte(vm.PC), byte(vm.SELFDESTRUCT), // Push code on stack | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x0, // memory start on stack | 
					
						
							|  |  |  | 		byte(vm.MSTORE), | 
					
						
							|  |  |  | 		// Code is now in memory. | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x2, // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(32 - 2), // offset | 
					
						
							|  |  |  | 		byte(vm.RETURN), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if l := len(initCode); l > 32 { | 
					
						
							|  |  |  | 		t.Fatalf("init code is too long for a pushx, need a more elaborate deployer") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bbCode := []byte{ | 
					
						
							|  |  |  | 		// Push initcode onto stack | 
					
						
							|  |  |  | 		byte(vm.PUSH1) + byte(len(initCode)-1)} | 
					
						
							|  |  |  | 	bbCode = append(bbCode, initCode...) | 
					
						
							|  |  |  | 	bbCode = append(bbCode, []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x0, // memory start on stack | 
					
						
							|  |  |  | 		byte(vm.MSTORE), | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // salt | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(len(initCode)), // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(32 - len(initCode)), // offset | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // endowment | 
					
						
							|  |  |  | 		byte(vm.CREATE2), | 
					
						
							|  |  |  | 	}...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initHash := crypto.Keccak256Hash(initCode) | 
					
						
							|  |  |  | 	aa := crypto.CreateAddress2(bb, [32]byte{}, initHash[:]) | 
					
						
							|  |  |  | 	t.Logf("Destination address: %x\n", aa) | 
					
						
							|  |  |  | 	gspec := &Genesis{ | 
					
						
							|  |  |  | 		Config: params.TestChainConfig, | 
					
						
							|  |  |  | 		Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 			address: {Balance: funds}, | 
					
						
							|  |  |  | 			// The address 0xAAAAA selfdestructs if called | 
					
						
							|  |  |  | 			aa: { | 
					
						
							|  |  |  | 				// Code needs to just selfdestruct | 
					
						
							|  |  |  | 				Code:    aaCode, | 
					
						
							|  |  |  | 				Nonce:   1, | 
					
						
							|  |  |  | 				Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				Storage: aaStorage, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			// The contract BB recreates AA | 
					
						
							|  |  |  | 			bb: { | 
					
						
							|  |  |  | 				Code:    bbCode, | 
					
						
							|  |  |  | 				Balance: big.NewInt(1), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 	var nonce uint64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type expectation struct { | 
					
						
							|  |  |  | 		exist    bool | 
					
						
							|  |  |  | 		blocknum int | 
					
						
							|  |  |  | 		values   map[int]int | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var current = &expectation{ | 
					
						
							|  |  |  | 		exist:    true, // exists in genesis | 
					
						
							|  |  |  | 		blocknum: 0, | 
					
						
							|  |  |  | 		values:   map[int]int{1: 1, 2: 2}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var expectations []*expectation | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	var newDestruct = func(e *expectation, b *BlockGen) *types.Transaction { | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		tx, _ := types.SignTx(types.NewTransaction(nonce, aa, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		nonce++ | 
					
						
							|  |  |  | 		if e.exist { | 
					
						
							|  |  |  | 			e.exist = false | 
					
						
							|  |  |  | 			e.values = nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		t.Logf("block %d; adding destruct\n", e.blocknum) | 
					
						
							|  |  |  | 		return tx | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	var newResurrect = func(e *expectation, b *BlockGen) *types.Transaction { | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		tx, _ := types.SignTx(types.NewTransaction(nonce, bb, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		nonce++ | 
					
						
							|  |  |  | 		if !e.exist { | 
					
						
							|  |  |  | 			e.exist = true | 
					
						
							|  |  |  | 			e.values = map[int]int{3: e.blocknum + 1, 4: 4} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		t.Logf("block %d; adding resurrect\n", e.blocknum) | 
					
						
							|  |  |  | 		return tx | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 150, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		var exp = new(expectation) | 
					
						
							|  |  |  | 		exp.blocknum = i + 1 | 
					
						
							|  |  |  | 		exp.values = make(map[int]int) | 
					
						
							|  |  |  | 		for k, v := range current.values { | 
					
						
							|  |  |  | 			exp.values[k] = v | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		exp.exist = current.exist | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		if i%2 == 0 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			b.AddTx(newDestruct(exp, b)) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if i%3 == 0 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			b.AddTx(newResurrect(exp, b)) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if i%5 == 0 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			b.AddTx(newDestruct(exp, b)) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if i%7 == 0 { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			b.AddTx(newResurrect(exp, b)) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		expectations = append(expectations, exp) | 
					
						
							|  |  |  | 		current = exp | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ | 
					
						
							|  |  |  | 		//Debug:  true, | 
					
						
							|  |  |  | 		//Tracer: vm.NewJSONLogger(nil, os.Stdout), | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 	}, nil, nil) | 
					
						
							| 
									
										
										
										
											2020-03-04 13:39:27 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var asHash = func(num int) common.Hash { | 
					
						
							|  |  |  | 		return common.BytesToHash([]byte{byte(num)}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, block := range blocks { | 
					
						
							|  |  |  | 		blockNum := i + 1 | 
					
						
							|  |  |  | 		if n, err := chain.InsertChain([]*types.Block{block}); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		statedb, _ := chain.State() | 
					
						
							|  |  |  | 		// If all is correct, then slot 1 and 2 are zero | 
					
						
							|  |  |  | 		if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 			t.Errorf("block %d, got %x exp %x", blockNum, got, exp) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { | 
					
						
							|  |  |  | 			t.Errorf("block %d, got %x exp %x", blockNum, got, exp) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		exp := expectations[i] | 
					
						
							|  |  |  | 		if exp.exist { | 
					
						
							|  |  |  | 			if !statedb.Exist(aa) { | 
					
						
							|  |  |  | 				t.Fatalf("block %d, expected %v to exist, it did not", blockNum, aa) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for slot, val := range exp.values { | 
					
						
							|  |  |  | 				if gotValue, expValue := statedb.GetState(aa, asHash(slot)), asHash(val); gotValue != expValue { | 
					
						
							|  |  |  | 					t.Fatalf("block %d, slot %d, got %x exp %x", blockNum, slot, gotValue, expValue) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if statedb.Exist(aa) { | 
					
						
							|  |  |  | 				t.Fatalf("block %d, expected %v to not exist, it did", blockNum, aa) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-06 13:05:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestInitThenFailCreateContract tests a pretty notorious case that happened | 
					
						
							|  |  |  | // on mainnet over blocks 7338108, 7338110 and 7338115. | 
					
						
							|  |  |  | // - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated | 
					
						
							|  |  |  | //   with 0.001 ether (thus created but no code) | 
					
						
							|  |  |  | // - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on | 
					
						
							|  |  |  | //   the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the | 
					
						
							|  |  |  | //   deployment fails due to OOG during initcode execution | 
					
						
							|  |  |  | // - Block 7338115: another tx checks the balance of | 
					
						
							|  |  |  | //   e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as | 
					
						
							|  |  |  | //   zero. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The problem being that the snapshotter maintains a destructset, and adds items | 
					
						
							|  |  |  | // to the destructset in case something is created "onto" an existing item. | 
					
						
							|  |  |  | // We need to either roll back the snapDestructs, or not place it into snapDestructs | 
					
						
							|  |  |  | // in the first place. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | func TestInitThenFailCreateContract(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2020-03-06 13:05:44 +01:00
										 |  |  | 		bb      = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The bb-code needs to CREATE2 the aa contract. It consists of | 
					
						
							|  |  |  | 	// both initcode and deployment code | 
					
						
							|  |  |  | 	// initcode: | 
					
						
							|  |  |  | 	// 1. If blocknum < 1, error out (e.g invalid opcode) | 
					
						
							|  |  |  | 	// 2. else, return a snippet of code | 
					
						
							|  |  |  | 	initCode := []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x1, // y (2) | 
					
						
							|  |  |  | 		byte(vm.NUMBER), // x (number) | 
					
						
							|  |  |  | 		byte(vm.GT),     // x > y? | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(0x8), | 
					
						
							|  |  |  | 		byte(vm.JUMPI), // jump to label if number > 2 | 
					
						
							|  |  |  | 		byte(0xFE),     // illegal opcode | 
					
						
							|  |  |  | 		byte(vm.JUMPDEST), | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x2, // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x0, // offset | 
					
						
							|  |  |  | 		byte(vm.RETURN), // return 2 bytes of zero-code | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if l := len(initCode); l > 32 { | 
					
						
							|  |  |  | 		t.Fatalf("init code is too long for a pushx, need a more elaborate deployer") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bbCode := []byte{ | 
					
						
							|  |  |  | 		// Push initcode onto stack | 
					
						
							|  |  |  | 		byte(vm.PUSH1) + byte(len(initCode)-1)} | 
					
						
							|  |  |  | 	bbCode = append(bbCode, initCode...) | 
					
						
							|  |  |  | 	bbCode = append(bbCode, []byte{ | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x0, // memory start on stack | 
					
						
							|  |  |  | 		byte(vm.MSTORE), | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // salt | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(len(initCode)), // size | 
					
						
							|  |  |  | 		byte(vm.PUSH1), byte(32 - len(initCode)), // offset | 
					
						
							|  |  |  | 		byte(vm.PUSH1), 0x00, // endowment | 
					
						
							|  |  |  | 		byte(vm.CREATE2), | 
					
						
							|  |  |  | 	}...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initHash := crypto.Keccak256Hash(initCode) | 
					
						
							|  |  |  | 	aa := crypto.CreateAddress2(bb, [32]byte{}, initHash[:]) | 
					
						
							|  |  |  | 	t.Logf("Destination address: %x\n", aa) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gspec := &Genesis{ | 
					
						
							|  |  |  | 		Config: params.TestChainConfig, | 
					
						
							|  |  |  | 		Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 			address: {Balance: funds}, | 
					
						
							|  |  |  | 			// The address aa has some funds | 
					
						
							|  |  |  | 			aa: {Balance: big.NewInt(100000)}, | 
					
						
							|  |  |  | 			// The contract BB tries to create code onto AA | 
					
						
							|  |  |  | 			bb: { | 
					
						
							|  |  |  | 				Code:    bbCode, | 
					
						
							|  |  |  | 				Balance: big.NewInt(1), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 	nonce := uint64(0) | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 4, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 		// One transaction to BB | 
					
						
							|  |  |  | 		tx, _ := types.SignTx(types.NewTransaction(nonce, bb, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) | 
					
						
							| 
									
										
										
										
											2020-03-06 13:05:44 +01:00
										 |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 		nonce++ | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ | 
					
						
							|  |  |  | 		//Debug:  true, | 
					
						
							|  |  |  | 		//Tracer: vm.NewJSONLogger(nil, os.Stdout), | 
					
						
							| 
									
										
										
										
											2020-05-12 07:46:10 +02:00
										 |  |  | 	}, nil, nil) | 
					
						
							| 
									
										
										
										
											2020-03-06 13:05:44 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	statedb, _ := chain.State() | 
					
						
							|  |  |  | 	if got, exp := statedb.GetBalance(aa), big.NewInt(100000); got.Cmp(exp) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("Genesis err, got %v exp %v", got, exp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// First block tries to create, but fails | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		block := blocks[0] | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain([]*types.Block{blocks[0]}); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		statedb, _ = chain.State() | 
					
						
							|  |  |  | 		if got, exp := statedb.GetBalance(aa), big.NewInt(100000); got.Cmp(exp) != 0 { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: got %v exp %v", block.NumberU64(), got, exp) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Import the rest of the blocks | 
					
						
							|  |  |  | 	for _, block := range blocks[1:] { | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain([]*types.Block{block}); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestEIP2718Transition tests that an EIP-2718 transaction will be accepted | 
					
						
							|  |  |  | // after the fork block has passed. This is verified by sending an EIP-2930 | 
					
						
							|  |  |  | // access list transaction, which specifies a single slot access, and then | 
					
						
							|  |  |  | // checking that the gas usage of a hot SLOAD and a cold SLOAD are calculated | 
					
						
							|  |  |  | // correctly. | 
					
						
							|  |  |  | func TestEIP2718Transition(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		address = crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		funds   = big.NewInt(1000000000000000) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		gspec   = &Genesis{ | 
					
						
							| 
									
										
										
										
											2021-05-06 11:07:42 +02:00
										 |  |  | 			Config: params.TestChainConfig, | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 				address: {Balance: funds}, | 
					
						
							|  |  |  | 				// The address 0xAAAA sloads 0x00 and 0x01 | 
					
						
							|  |  |  | 				aa: { | 
					
						
							|  |  |  | 					Code: []byte{ | 
					
						
							|  |  |  | 						byte(vm.PC), | 
					
						
							|  |  |  | 						byte(vm.PC), | 
					
						
							|  |  |  | 						byte(vm.SLOAD), | 
					
						
							|  |  |  | 						byte(vm.SLOAD), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					Nonce:   0, | 
					
						
							|  |  |  | 					Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		genesis = gspec.MustCommit(db) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// One transaction to 0xAAAA | 
					
						
							|  |  |  | 		signer := types.LatestSigner(gspec.Config) | 
					
						
							|  |  |  | 		tx, _ := types.SignNewTx(key, signer, &types.AccessListTx{ | 
					
						
							|  |  |  | 			ChainID:  gspec.Config.ChainID, | 
					
						
							|  |  |  | 			Nonce:    0, | 
					
						
							|  |  |  | 			To:       &aa, | 
					
						
							|  |  |  | 			Gas:      30000, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 			GasPrice: b.header.BaseFee, | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 			AccessList: types.AccessList{{ | 
					
						
							|  |  |  | 				Address:     aa, | 
					
						
							|  |  |  | 				StorageKeys: []common.Hash{{0}}, | 
					
						
							|  |  |  | 			}}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import the canonical chain | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block := chain.GetBlockByNumber(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Expected gas is intrinsic + 2 * pc + hot load + cold load, since only one load is in the access list | 
					
						
							| 
									
										
										
										
											2021-05-07 08:25:32 +02:00
										 |  |  | 	expected := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas + | 
					
						
							|  |  |  | 		vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	if block.GasUsed() != expected { | 
					
						
							|  |  |  | 		t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestEIP1559Transition tests the following: | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | // 1. A transaction whose gasFeeCap is greater than the baseFee is valid. | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | // 2. Gas accounting for access lists on EIP-1559 transactions is correct. | 
					
						
							|  |  |  | // 3. Only the transaction's tip will be received by the coinbase. | 
					
						
							|  |  |  | // 4. The transaction sender pays for both the tip and baseFee. | 
					
						
							|  |  |  | // 5. The coinbase receives only the partially realized tip when | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | //    gasFeeCap - gasTipCap < baseFee. | 
					
						
							|  |  |  | // 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | func TestEIP1559Transition(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Generate a canonical chain to act as the main dataset | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 		db     = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// A sender who makes transactions, has some funds | 
					
						
							|  |  |  | 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") | 
					
						
							|  |  |  | 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | 
					
						
							|  |  |  | 		addr2   = crypto.PubkeyToAddress(key2.PublicKey) | 
					
						
							|  |  |  | 		funds   = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) | 
					
						
							|  |  |  | 		gspec   = &Genesis{ | 
					
						
							|  |  |  | 			Config: params.AllEthashProtocolChanges, | 
					
						
							|  |  |  | 			Alloc: GenesisAlloc{ | 
					
						
							|  |  |  | 				addr1: {Balance: funds}, | 
					
						
							|  |  |  | 				addr2: {Balance: funds}, | 
					
						
							|  |  |  | 				// The address 0xAAAA sloads 0x00 and 0x01 | 
					
						
							|  |  |  | 				aa: { | 
					
						
							|  |  |  | 					Code: []byte{ | 
					
						
							|  |  |  | 						byte(vm.PC), | 
					
						
							|  |  |  | 						byte(vm.PC), | 
					
						
							|  |  |  | 						byte(vm.SLOAD), | 
					
						
							|  |  |  | 						byte(vm.SLOAD), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					Nonce:   0, | 
					
						
							|  |  |  | 					Balance: big.NewInt(0), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gspec.Config.BerlinBlock = common.Big0 | 
					
						
							|  |  |  | 	gspec.Config.LondonBlock = common.Big0 | 
					
						
							|  |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							|  |  |  | 	signer := types.LatestSigner(gspec.Config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{1}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// One transaction to 0xAAAA | 
					
						
							|  |  |  | 		accesses := types.AccessList{types.AccessTuple{ | 
					
						
							|  |  |  | 			Address:     aa, | 
					
						
							|  |  |  | 			StorageKeys: []common.Hash{{0}}, | 
					
						
							|  |  |  | 		}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		txdata := &types.DynamicFeeTx{ | 
					
						
							|  |  |  | 			ChainID:    gspec.Config.ChainID, | 
					
						
							|  |  |  | 			Nonce:      0, | 
					
						
							|  |  |  | 			To:         &aa, | 
					
						
							|  |  |  | 			Gas:        30000, | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | 			GasFeeCap:  newGwei(5), | 
					
						
							|  |  |  | 			GasTipCap:  big.NewInt(2), | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | 			AccessList: accesses, | 
					
						
							|  |  |  | 			Data:       []byte{}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tx := types.NewTx(txdata) | 
					
						
							|  |  |  | 		tx, _ = types.SignTx(tx, signer, key1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	diskdb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	gspec.MustCommit(diskdb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create tester chain: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block := chain.GetBlockByNumber(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage. | 
					
						
							|  |  |  | 	expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas + | 
					
						
							|  |  |  | 		vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929 | 
					
						
							|  |  |  | 	if block.GasUsed() != expectedGas { | 
					
						
							|  |  |  | 		t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	state, _ := chain.State() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3: Ensure that miner received only the tx's tip. | 
					
						
							|  |  |  | 	actual := state.GetBalance(block.Coinbase()) | 
					
						
							|  |  |  | 	expected := new(big.Int).Add( | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | 		new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()), | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | 		ethash.ConstantinopleBlockReward, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if actual.Cmp(expected) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee). | 
					
						
							|  |  |  | 	actual = new(big.Int).Sub(funds, state.GetBalance(addr1)) | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | 	expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64())) | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | 	if actual.Cmp(expected) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blocks, _ = GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *BlockGen) { | 
					
						
							|  |  |  | 		b.SetCoinbase(common.Address{2}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		txdata := &types.LegacyTx{ | 
					
						
							|  |  |  | 			Nonce:    0, | 
					
						
							|  |  |  | 			To:       &aa, | 
					
						
							|  |  |  | 			Gas:      30000, | 
					
						
							|  |  |  | 			GasPrice: newGwei(5), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tx := types.NewTx(txdata) | 
					
						
							|  |  |  | 		tx, _ = types.SignTx(tx, signer, key2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b.AddTx(tx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if n, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block = chain.GetBlockByNumber(2) | 
					
						
							|  |  |  | 	state, _ = chain.State() | 
					
						
							| 
									
										
										
										
											2021-06-08 13:05:41 +03:00
										 |  |  | 	effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64() | 
					
						
							| 
									
										
										
										
											2021-05-17 15:13:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 6+5: Ensure that miner received only the tx's effective tip. | 
					
						
							|  |  |  | 	actual = state.GetBalance(block.Coinbase()) | 
					
						
							|  |  |  | 	expected = new(big.Int).Add( | 
					
						
							|  |  |  | 		new(big.Int).SetUint64(block.GasUsed()*effectiveTip), | 
					
						
							|  |  |  | 		ethash.ConstantinopleBlockReward, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if actual.Cmp(expected) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee). | 
					
						
							|  |  |  | 	actual = new(big.Int).Sub(funds, state.GetBalance(addr2)) | 
					
						
							|  |  |  | 	expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64())) | 
					
						
							|  |  |  | 	if actual.Cmp(expected) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |