use real ProcessWithParent for all chain manager tests. passing

This commit is contained in:
Ethan Buchman 2014-11-23 11:18:18 -05:00
parent 6ef0f67b9f
commit 24523b893d
2 changed files with 175 additions and 97 deletions

View file

@ -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)
}

View file

@ -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
blocks := make(types.Blocks, max)
for i := 0; i < max; i++ {
// 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 := bman.bc.NewBlock(addr)
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()
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) {})
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++ {
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))
}