diff --git a/chain/chain_manager_test.go b/chain/chain_manager_test.go index 2745553ea7..3d745b3a2f 100644 --- a/chain/chain_manager_test.go +++ b/chain/chain_manager_test.go @@ -20,6 +20,7 @@ func init() { initDB() } +// Called from each Test to re-init the DB func initDB() { ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") ethutil.Config.Db, _ = ethdb.NewMemDatabase() @@ -49,6 +50,7 @@ func (e *fakeEth) ClientIdentity() wire.ClientIdentity { return n func (e *fakeEth) Db() ethutil.Database { return nil } func (e *fakeEth) EventMux() *event.TypeMux { return nil } +// Create new block from coinbase and parent func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { block := types.CreateBlock( parent.Root(), @@ -65,7 +67,7 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { } // Actually make a block by simulating what miner would do -func makeblock(bman *BlockManager, parent *types.Block, i int) *types.Block { +func makeBlock(bman *BlockManager, parent *types.Block, i int) *types.Block { addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) block := newBlockFromParent(addr, parent) cbase := block.State().GetOrNewStateObject(addr) @@ -80,13 +82,13 @@ func makeblock(bman *BlockManager, parent *types.Block, i int) *types.Block { // Make a chain with real blocks // Runs ProcessWithParent to get proper state roots -func makechain(bman *BlockManager, parent *types.Block, max int) *BlockChain { +func makeChain(bman *BlockManager, parent *types.Block, max int) *BlockChain { bman.bc.CurrentBlock = parent bman.bc.LastBlockHash = parent.Hash() blocks := make(types.Blocks, max) var td *big.Int for i := 0; i < max; i++ { - block := makeblock(bman, parent, i) + block := makeBlock(bman, parent, i) // add the parent and its difficulty to the working chain // so ProcessWithParent can access it bman.bc.workingChain = NewChain(types.Blocks{parent}) @@ -99,13 +101,14 @@ func makechain(bman *BlockManager, parent *types.Block, max int) *BlockChain { return lchain } -// Make a new canonical chain by running TestChain and InsertChain -// on result of makechain +// Make a new canonical chain n block long +// by running TestChain and InsertChain +// on result of makeChain func newCanonical(n int) (*BlockManager, error) { bman := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} bman.bc.SetProcessor(bman) parent := bman.bc.CurrentBlock - lchain := makechain(bman, parent, 5) + lchain := makeChain(bman, parent, n) _, err := bman.bc.TestChain(lchain) if err != nil { @@ -115,14 +118,41 @@ func newCanonical(n int) (*BlockManager, error) { return bman, nil } -// new chain manager without setLastBlock -func newChainManager() *ChainManager { +// Create a new chain manager starting from given block +// Effectively a fork factory +func newChainManager(block *types.Block) *ChainManager { bc := &ChainManager{} bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis)) - bc.Reset() + if block == nil { + bc.Reset() + } else { + bc.CurrentBlock = block + bc.SetTotalDifficulty(ethutil.Big("0")) + bc.TD = block.BlockInfo().TD + } return bc } +// Test fork of length N starting from block i +func testFork(t *testing.T, bman *BlockManager, i, N int, f func(td1, td2 *big.Int)) { + var b *types.Block = nil + if i > 0 { + b = bman.bc.GetBlockByNumber(uint64(i)) + } + bman2 := &BlockManager{bc: newChainManager(b), Pow: fakePow{}, eth: &fakeEth{}} + bman2.bc.SetProcessor(bman2) + parent := bman2.bc.CurrentBlock + chainB := makeChain(bman2, parent, N) + // test second chain against first + td2, err := bman.bc.TestChain(chainB) + if err != nil && !IsTDError(err) { + t.Error("expected chainB not to give errors:", err) + } + // Compare difficulties + f(bman.bc.TD, td2) +} + +// Test basic extension of canonical chain with new blocks func TestExtendCanonical(t *testing.T) { initDB() // make first chain starting from genesis @@ -131,95 +161,94 @@ func TestExtendCanonical(t *testing.T) { t.Fatal("Could not make new canonical chain:", err) } - // make second chain starting from end of first chain - bman2 := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} - bman2.bc.SetProcessor(bman2) - parent := bman.bc.CurrentBlock - chainB := makechain(bman2, parent, 3) - - // test second chain against first - td2, err := bman.bc.TestChain(chainB) - if err != nil && !IsTDError(err) { - t.Error("expected chainB not to give errors:", err) + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) + } } - if td2.Cmp(bman.bc.TD) <= 0 { - t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", bman.bc.TD) - } + // Start fork from current height (5) + testFork(t, bman, 5, 1, f) + testFork(t, bman, 5, 2, f) + testFork(t, bman, 5, 5, f) + testFork(t, bman, 5, 10, f) } +// Test a fork with less TD than the canonical chain func TestShorterFork(t *testing.T) { initDB() // make first chain starting from genesis - bman, err := newCanonical(5) + bman, err := newCanonical(10) if err != nil { t.Fatal("Could not make new canonical chain:", err) } - // make second, shorter chain, starting from genesis - bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} - bman2.bc.SetProcessor(bman2) - parent := bman2.bc.CurrentBlock - chainB := makechain(bman2, parent, 3) - - // test second chain against first - td2, err := bman.bc.TestChain(chainB) - if err != nil && !IsTDError(err) { - t.Error("expected chainB not to give errors:", err) + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) >= 0 { + t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1) + } } - if td2.Cmp(bman.bc.TD) >= 0 { - t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", bman.bc.TD) - } + // Sum of numbers must be less than 10 + // for this to be a shorter fork + testFork(t, bman, 0, 3, f) + testFork(t, bman, 0, 7, f) + testFork(t, bman, 1, 3, f) + testFork(t, bman, 1, 7, f) + testFork(t, bman, 5, 3, f) + testFork(t, bman, 5, 4, f) } +// Test a fork with more TD than canonical chain func TestLongerFork(t *testing.T) { initDB() // make first chain starting from genesis - bman, err := newCanonical(5) + bman, err := newCanonical(10) if err != nil { t.Fatal("Could not make new canonical chain:", err) } - // make second, longer chain, starting from genesis - bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} - bman2.bc.SetProcessor(bman2) - parent := bman2.bc.CurrentBlock - chainB := makechain(bman2, parent, 10) - - td, err := bman.bc.TestChain(chainB) - if err != nil { - t.Error("expected chainB not to give errors:", err) + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) + } } - if td.Cmp(bman.bc.TD) <= 0 { - t.Error("expected chainB to have higher difficulty. Got", td, "expected more than", bman.bc.TD) - } + // Sum of numbers must be greater than 10 + // for this to be a longer fork + testFork(t, bman, 0, 11, f) + testFork(t, bman, 0, 15, f) + testFork(t, bman, 1, 10, f) + testFork(t, bman, 1, 12, f) + testFork(t, bman, 5, 6, f) + testFork(t, bman, 5, 8, f) } +// Test a fork with equal TD to canonical chain func TestEqualFork(t *testing.T) { initDB() - bman, err := newCanonical(5) + bman, err := newCanonical(10) if err != nil { t.Fatal("Could not make new canonical chain:", err) } - bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} - bman2.bc.SetProcessor(bman2) - parent := bman2.bc.CurrentBlock - - chainB := makechain(bman2, parent, 5) - - td, err := bman.bc.TestChain(chainB) - if err != nil && !IsTDError(err) { - t.Error("expected chainB not to give errors:", err) + f := func(td1, td2 *big.Int) { + if td2.Cmp(td1) != 0 { + t.Error("expected chainB to have equal difficulty. Got", td2, "expected less than", td1) + } } - if td.Cmp(bman.bc.TD) != 0 { - t.Error("expected chainB to have equal difficulty. Got", td, "expected less than", bman.bc.TD) - } + // Sum of numbers must be equal to 10 + // for this to be an equal fork + testFork(t, bman, 0, 10, f) + testFork(t, bman, 1, 9, f) + testFork(t, bman, 2, 8, f) + testFork(t, bman, 5, 5, f) + testFork(t, bman, 6, 4, f) + testFork(t, bman, 9, 1, f) } +// Test a broken chain (no common ancestor) func TestBrokenChain(t *testing.T) { initDB() bman, err := newCanonical(5) @@ -231,7 +260,7 @@ func TestBrokenChain(t *testing.T) { bman2.bc.SetProcessor(bman2) parent := bman2.bc.CurrentBlock - chainB := makechain(bman2, parent, 5) + chainB := makeChain(bman2, parent, 5) chainB.Remove(chainB.Front()) _, err = bman.bc.TestChain(chainB) @@ -253,7 +282,7 @@ func BenchmarkChainTesting(b *testing.B) { bman2.bc.SetProcessor(bman2) parent := bman2.bc.CurrentBlock - chain := makechain(bman2, parent, chainlen) + chain := makeChain(bman2, parent, chainlen) stime := time.Now() bman.bc.TestChain(chain)