mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
test forks from arbitrary heights
This commit is contained in:
parent
24523b893d
commit
f6914301d3
1 changed files with 93 additions and 64 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue