diff --git a/chain/chain_manager.go b/chain/chain_manager.go index 11e16fa7d2..335e68b5cc 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -196,7 +196,6 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block { } } } - return nil } @@ -229,7 +228,8 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) { return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) } - parentTd := parent.BlockInfo().TD + //parentTd := parent.BlockInfo().TD + parentTd := self.BlockInfo(parent).TD uncleDiff := new(big.Int) for _, uncle := range block.Uncles { @@ -246,8 +246,20 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) { func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo { bi := types.BlockInfo{} data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + if len(data) == 0 { + if bc.workingChain != nil { + // Check the temp chain + for e := bc.workingChain.Front(); e != nil; e = e.Next() { + l := e.Value.(*link) + b := l.Block + if bytes.Compare(b.Hash(), block.Hash()) == 0 { + bi = types.BlockInfo{Number: b.Number.Uint64(), Hash: b.Hash(), Parent: b.PrevHash, TD: l.Td} + return bi + } + } + } + } bi.RlpDecode(data) - return bi } @@ -275,8 +287,10 @@ func (self *ChainManager) InsertChain(chain *BlockChain, call func(*types.Block, for e := chain.Front(); e != nil; e = e.Next() { link := e.Value.(*link) - self.add(link.Block) + // must set TD before adding as + // add calls writeBlockInfo which writes the most recent TD self.SetTotalDifficulty(link.Td) + self.add(link.Block) call(link.Block, link.Messages) } diff --git a/chain/chain_manager_test.go b/chain/chain_manager_test.go index 1849c48f5e..2745553ea7 100644 --- a/chain/chain_manager_test.go +++ b/chain/chain_manager_test.go @@ -16,22 +16,15 @@ import ( "github.com/ethereum/go-ethereum/wire" ) -// In these tests, TD = block.Number -var TD *big.Int - func init() { + initDB() +} + +func initDB() { ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") ethutil.Config.Db, _ = ethdb.NewMemDatabase() } -type fakeproc struct { -} - -func (self fakeproc) ProcessWithParent(a, b *types.Block) (*big.Int, state.Messages, error) { - TD = new(big.Int).Add(TD, big.NewInt(1)) - return TD, nil, nil -} - // So we can generate blocks easily type fakePow struct{} @@ -56,61 +49,120 @@ func (e *fakeEth) ClientIdentity() wire.ClientIdentity { return n func (e *fakeEth) Db() ethutil.Database { return nil } func (e *fakeEth) EventMux() *event.TypeMux { return nil } -func makechain(cman *ChainManager, max int) *BlockChain { - blocks := make(types.Blocks, max) - for i := 0; i < max; i++ { - addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) - block := cman.NewBlock(addr) - if i != 0 { - cman.CurrentBlock = blocks[i-1] - } - blocks[i] = block - } - return NewChain(blocks) +func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { + block := types.CreateBlock( + parent.Root(), + parent.Hash(), + addr, + ethutil.BigPow(2, 32), + nil, + "") + block.MinGasPrice = big.NewInt(10000000000000) + block.Difficulty = CalcDifficulty(block, parent) + block.Number = new(big.Int).Add(parent.Number, ethutil.Big1) + block.GasLimit = block.CalcGasLimit(parent) + return block } -func makechain2(bman *BlockManager, max int) *BlockChain { - parent := bman.bc.CurrentBlock +// Actually make a block by simulating what miner would do +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) + cbase.SetGasPool(block.CalcGasLimit(parent)) + receipts, txs, _, _, _ := bman.ProcessTransactions(cbase, block.State(), block, block, types.Transactions{}) + block.SetTransactions(txs) + block.SetReceipts(receipts) + bman.AccumelateRewards(block.State(), block, parent) + block.State().Update() + return block +} + +// Make a chain with real blocks +// Runs ProcessWithParent to get proper state roots +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++ { - addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) - block := bman.bc.NewBlock(addr) - cbase := block.State().GetOrNewStateObject(addr) - cbase.SetGasPool(block.CalcGasLimit(parent)) - receipts, txs, _, _, _ := bman.ProcessTransactions(cbase, block.State(), block, block, types.Transactions{}) - block.SetTransactions(txs) - block.SetReceipts(receipts) - - bman.AccumelateRewards(block.State(), block, parent) - - block.State().Update() - lchain := NewChain(types.Blocks{block}) - _, err := bman.bc.TestChain(lchain) - if err != nil { - fmt.Println("failed to run test chain!:", err) - } - bman.bc.InsertChain(lchain, func(block *types.Block, _ state.Messages) {}) - + 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}) + bman.bc.workingChain.Back().Value.(*link).Td = td + td, _, _ = bman.bc.processor.ProcessWithParent(block, parent) blocks[i] = block parent = block } - return NewChain(blocks) + lchain := NewChain(blocks) + return lchain +} + +// Make a new canonical chain 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) + + _, err := bman.bc.TestChain(lchain) + if err != nil { + return nil, err + } + bman.bc.InsertChain(lchain, func(block *types.Block, _ state.Messages) {}) + return bman, nil +} + +// new chain manager without setLastBlock +func newChainManager() *ChainManager { + bc := &ChainManager{} + bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis)) + bc.Reset() + return bc +} + +func TestExtendCanonical(t *testing.T) { + initDB() + // make first chain starting from genesis + bman, err := newCanonical(5) + if err != nil { + 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) + } + + if td2.Cmp(bman.bc.TD) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", bman.bc.TD) + } } func TestShorterFork(t *testing.T) { - cman := NewChainManager() - bman := &BlockManager{bc: cman, Pow: fakePow{}, eth: &fakeEth{}} - bman.bc.SetProcessor(bman) + initDB() + // make first chain starting from genesis + bman, err := newCanonical(5) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } - makechain2(bman, 5) - - cman2 := NewChainManager() - cman2.Reset() // so we don't end up with last block of cman1 - bman2 := &BlockManager{bc: cman2, Pow: fakePow{}, eth: &fakeEth{}} + // 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) - chainB := makechain2(bman2, 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) @@ -122,76 +174,88 @@ func TestShorterFork(t *testing.T) { } func TestLongerFork(t *testing.T) { - cman := NewChainManager() - cman.SetProcessor(fakeproc{}) - - TD = big.NewInt(1) - chainA := makechain(cman, 5) - - TD = big.NewInt(1) - chainB := makechain(cman, 10) - - td, err := cman.TestChain(chainA) + initDB() + // make first chain starting from genesis + bman, err := newCanonical(5) if err != nil { - t.Error("unable to create new TD from chainA:", err) + t.Fatal("Could not make new canonical chain:", err) } - cman.TD = td - _, err = cman.TestChain(chainB) + // 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) } + + if td.Cmp(bman.bc.TD) <= 0 { + t.Error("expected chainB to have higher difficulty. Got", td, "expected more than", bman.bc.TD) + } } func TestEqualFork(t *testing.T) { - cman := NewChainManager() - cman.SetProcessor(fakeproc{}) - - TD = big.NewInt(1) - chainA := makechain(cman, 5) - - TD = big.NewInt(2) - chainB := makechain(cman, 5) - - td, err := cman.TestChain(chainA) + initDB() + bman, err := newCanonical(5) if err != nil { - t.Error("unable to create new TD from chainA:", err) + t.Fatal("Could not make new canonical chain:", err) } - cman.TD = td - _, err = cman.TestChain(chainB) - if err != nil { + 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) } + + if td.Cmp(bman.bc.TD) != 0 { + t.Error("expected chainB to have equal difficulty. Got", td, "expected less than", bman.bc.TD) + } } func TestBrokenChain(t *testing.T) { - cman := NewChainManager() - cman.SetProcessor(fakeproc{}) + initDB() + bman, err := newCanonical(5) + if err != nil { + t.Fatal("Could not make new canonical chain:", err) + } - TD = big.NewInt(1) - chain := makechain(cman, 5) - chain.Remove(chain.Front()) + bman2 := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} + bman2.bc.SetProcessor(bman2) + parent := bman2.bc.CurrentBlock - _, err := cman.TestChain(chain) + chainB := makechain(bman2, parent, 5) + chainB.Remove(chainB.Front()) + + _, err = bman.bc.TestChain(chainB) if err == nil { t.Error("expected broken chain to return error") } } func BenchmarkChainTesting(b *testing.B) { + initDB() const chainlen = 1000 - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - ethutil.Config.Db, _ = ethdb.NewMemDatabase() + bman, err := newCanonical(5) + if err != nil { + b.Fatal("Could not make new canonical chain:", err) + } - cman := NewChainManager() - cman.SetProcessor(fakeproc{}) + bman2 := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} + bman2.bc.SetProcessor(bman2) + parent := bman2.bc.CurrentBlock - TD = big.NewInt(1) - chain := makechain(cman, chainlen) + chain := makechain(bman2, parent, chainlen) stime := time.Now() - cman.TestChain(chain) + bman.bc.TestChain(chain) fmt.Println(chainlen, "took", time.Since(stime)) }