test forks from arbitrary heights

This commit is contained in:
Ethan Buchman 2014-11-29 15:26:43 -05:00
parent 24523b893d
commit f6914301d3

View file

@ -20,6 +20,7 @@ func init() {
initDB() initDB()
} }
// Called from each Test to re-init the DB
func initDB() { func initDB() {
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
ethutil.Config.Db, _ = ethdb.NewMemDatabase() 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) Db() ethutil.Database { return nil }
func (e *fakeEth) EventMux() *event.TypeMux { 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 { func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
block := types.CreateBlock( block := types.CreateBlock(
parent.Root(), 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 // 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) addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
block := newBlockFromParent(addr, parent) block := newBlockFromParent(addr, parent)
cbase := block.State().GetOrNewStateObject(addr) 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 // Make a chain with real blocks
// Runs ProcessWithParent to get proper state roots // 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.CurrentBlock = parent
bman.bc.LastBlockHash = parent.Hash() bman.bc.LastBlockHash = parent.Hash()
blocks := make(types.Blocks, max) blocks := make(types.Blocks, max)
var td *big.Int var td *big.Int
for i := 0; i < max; i++ { 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 // add the parent and its difficulty to the working chain
// so ProcessWithParent can access it // so ProcessWithParent can access it
bman.bc.workingChain = NewChain(types.Blocks{parent}) bman.bc.workingChain = NewChain(types.Blocks{parent})
@ -99,13 +101,14 @@ func makechain(bman *BlockManager, parent *types.Block, max int) *BlockChain {
return lchain return lchain
} }
// Make a new canonical chain by running TestChain and InsertChain // Make a new canonical chain n block long
// on result of makechain // by running TestChain and InsertChain
// on result of makeChain
func newCanonical(n int) (*BlockManager, error) { func newCanonical(n int) (*BlockManager, error) {
bman := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} bman := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}}
bman.bc.SetProcessor(bman) bman.bc.SetProcessor(bman)
parent := bman.bc.CurrentBlock parent := bman.bc.CurrentBlock
lchain := makechain(bman, parent, 5) lchain := makeChain(bman, parent, n)
_, err := bman.bc.TestChain(lchain) _, err := bman.bc.TestChain(lchain)
if err != nil { if err != nil {
@ -115,14 +118,41 @@ func newCanonical(n int) (*BlockManager, error) {
return bman, nil return bman, nil
} }
// new chain manager without setLastBlock // Create a new chain manager starting from given block
func newChainManager() *ChainManager { // Effectively a fork factory
func newChainManager(block *types.Block) *ChainManager {
bc := &ChainManager{} bc := &ChainManager{}
bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis)) 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 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) { func TestExtendCanonical(t *testing.T) {
initDB() initDB()
// make first chain starting from genesis // make first chain starting from genesis
@ -131,95 +161,94 @@ func TestExtendCanonical(t *testing.T) {
t.Fatal("Could not make new canonical chain:", err) t.Fatal("Could not make new canonical chain:", err)
} }
// make second chain starting from end of first chain f := func(td1, td2 *big.Int) {
bman2 := &BlockManager{bc: NewChainManager(), Pow: fakePow{}, eth: &fakeEth{}} if td2.Cmp(td1) <= 0 {
bman2.bc.SetProcessor(bman2) t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
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 { // Start fork from current height (5)
t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", bman.bc.TD) 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) { func TestShorterFork(t *testing.T) {
initDB() initDB()
// make first chain starting from genesis // make first chain starting from genesis
bman, err := newCanonical(5) bman, err := newCanonical(10)
if err != nil { if err != nil {
t.Fatal("Could not make new canonical chain:", err) t.Fatal("Could not make new canonical chain:", err)
} }
// make second, shorter chain, starting from genesis f := func(td1, td2 *big.Int) {
bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} if td2.Cmp(td1) >= 0 {
bman2.bc.SetProcessor(bman2) t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
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)
} }
if td2.Cmp(bman.bc.TD) >= 0 { // Sum of numbers must be less than 10
t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", bman.bc.TD) // 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) { func TestLongerFork(t *testing.T) {
initDB() initDB()
// make first chain starting from genesis // make first chain starting from genesis
bman, err := newCanonical(5) bman, err := newCanonical(10)
if err != nil { if err != nil {
t.Fatal("Could not make new canonical chain:", err) t.Fatal("Could not make new canonical chain:", err)
} }
// make second, longer chain, starting from genesis f := func(td1, td2 *big.Int) {
bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} if td2.Cmp(td1) <= 0 {
bman2.bc.SetProcessor(bman2) t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
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 { // Sum of numbers must be greater than 10
t.Error("expected chainB to have higher difficulty. Got", td, "expected more than", bman.bc.TD) // 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) { func TestEqualFork(t *testing.T) {
initDB() initDB()
bman, err := newCanonical(5) bman, err := newCanonical(10)
if err != nil { if err != nil {
t.Fatal("Could not make new canonical chain:", err) t.Fatal("Could not make new canonical chain:", err)
} }
bman2 := &BlockManager{bc: newChainManager(), Pow: fakePow{}, eth: &fakeEth{}} f := func(td1, td2 *big.Int) {
bman2.bc.SetProcessor(bman2) if td2.Cmp(td1) != 0 {
parent := bman2.bc.CurrentBlock t.Error("expected chainB to have equal difficulty. Got", td2, "expected less than", td1)
}
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 { // Sum of numbers must be equal to 10
t.Error("expected chainB to have equal difficulty. Got", td, "expected less than", bman.bc.TD) // 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) { func TestBrokenChain(t *testing.T) {
initDB() initDB()
bman, err := newCanonical(5) bman, err := newCanonical(5)
@ -231,7 +260,7 @@ func TestBrokenChain(t *testing.T) {
bman2.bc.SetProcessor(bman2) bman2.bc.SetProcessor(bman2)
parent := bman2.bc.CurrentBlock parent := bman2.bc.CurrentBlock
chainB := makechain(bman2, parent, 5) chainB := makeChain(bman2, parent, 5)
chainB.Remove(chainB.Front()) chainB.Remove(chainB.Front())
_, err = bman.bc.TestChain(chainB) _, err = bman.bc.TestChain(chainB)
@ -253,7 +282,7 @@ func BenchmarkChainTesting(b *testing.B) {
bman2.bc.SetProcessor(bman2) bman2.bc.SetProcessor(bman2)
parent := bman2.bc.CurrentBlock parent := bman2.bc.CurrentBlock
chain := makechain(bman2, parent, chainlen) chain := makeChain(bman2, parent, chainlen)
stime := time.Now() stime := time.Now()
bman.bc.TestChain(chain) bman.bc.TestChain(chain)