Martin Holst Swende 6 năm trước cách đây
mục cha
commit
da1efdae0c
2 tập tin đã thay đổi với 104 bổ sung1 xóa
  1. 48 0
      core/blockchain_test.go
  2. 56 1
      core/chain_makers.go

+ 48 - 0
core/blockchain_test.go

@@ -1483,3 +1483,51 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
 
 	benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
 }
+
+// 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.
+func TestLargeOldSidechainWithALowTdChain(t *testing.T) {
+
+	// Generate a canonical chain to act as the main dataset
+	engine := ethash.NewFaker()
+
+	db := ethdb.NewMemDatabase()
+	genesis := new(Genesis).MustCommit(db)
+	// We must use a pretty long chain to ensure that the fork
+	// doesn't overtake us until after at least 128 blocks post tip
+	blocks, _ := generateChain(params.TestChainConfig, genesis, engine, db, 6*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }, makeHeaderWithLargeDifficulty)
+
+	// Import the canonical chain
+	diskdb := ethdb.NewMemDatabase()
+	new(Genesis).MustCommit(diskdb)
+
+	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
+	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)
+		}
+	}
+	// Dereference all the recent tries and ensure no past trie is left in
+	for i := 0; i < triesInMemory; i++ {
+		chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root())
+	}
+
+	// Generate fork chain, starting from an early block
+	parent := blocks[10]
+	fork, _ := generateChain(params.TestChainConfig, parent, engine, db, 256+6*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }, makeHeaderWithSmallDifficulty)
+
+	// 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)
+	}
+	td := chain.GetTd(head.Hash(), head.NumberU64())
+	fmt.Printf("td %v", td)
+}

+ 56 - 1
core/chain_makers.go

@@ -48,6 +48,8 @@ type BlockGen struct {
 	engine consensus.Engine
 }
 
+type headerGenFn func(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header
+
 // SetCoinbase sets the coinbase of the generated block.
 // It can be called at most once.
 func (b *BlockGen) SetCoinbase(addr common.Address) {
@@ -170,6 +172,10 @@ func (b *BlockGen) OffsetTime(seconds int64) {
 // values. Inserting them into BlockChain requires use of FakePow or
 // a similar non-validating proof of work implementation.
 func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
+	return generateChain(config, parent, engine, db, n, gen, makeHeader)
+}
+
+func generateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen), headerGen headerGenFn) ([]*types.Block, []types.Receipts) {
 	if config == nil {
 		config = params.TestChainConfig
 	}
@@ -177,7 +183,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
 	chainreader := &fakeChainReader{config: config}
 	genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
 		b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
-		b.header = makeHeader(chainreader, parent, statedb, b.engine)
+		//b.header = makeHeader(chainreader, parent, statedb, b.engine)
+		b.header = headerGen(chainreader, parent, statedb, b.engine)
 
 		// Mutate the state and block according to any hard-fork specs
 		if daoBlock := config.DAOForkBlock; daoBlock != nil {
@@ -248,6 +255,54 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
 	}
 }
 
+func makeHeaderWithLargeDifficulty(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
+	var time *big.Int
+	if parent.Time() == nil {
+		time = big.NewInt(1)
+	} else {
+		time = new(big.Int).Add(parent.Time(), big.NewInt(1)) // block time is fixed at 10 seconds
+	}
+
+	return &types.Header{
+		Root:       state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
+		ParentHash: parent.Hash(),
+		Coinbase:   parent.Coinbase(),
+		Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{
+			Number:     parent.Number(),
+			Time:       new(big.Int).Sub(time, big.NewInt(1)),
+			Difficulty: parent.Difficulty(),
+			UncleHash:  parent.UncleHash(),
+		}),
+		GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
+		Number:   new(big.Int).Add(parent.Number(), common.Big1),
+		Time:     time,
+	}
+}
+
+func makeHeaderWithSmallDifficulty(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
+	var time *big.Int
+	if parent.Time() == nil {
+		time = big.NewInt(30)
+	} else {
+		time = new(big.Int).Add(parent.Time(), big.NewInt(30)) // block time is fixed at 10 seconds
+	}
+
+	return &types.Header{
+		Root:       state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
+		ParentHash: parent.Hash(),
+		Coinbase:   parent.Coinbase(),
+		Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{
+			Number:     parent.Number(),
+			Time:       new(big.Int).Sub(time, big.NewInt(30)),
+			Difficulty: parent.Difficulty(),
+			UncleHash:  parent.UncleHash(),
+		}),
+		GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
+		Number:   new(big.Int).Add(parent.Number(), common.Big1),
+		Time:     time,
+	}
+}
+
 // makeHeaderChain creates a deterministic chain of headers rooted at parent.
 func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header {
 	blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed)