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()
}
// 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)