mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core: add test for sidechain imports of long chains, where hash lookup is not on canon chain
This commit is contained in:
parent
7aa5ec37d2
commit
54e16f8679
2 changed files with 97 additions and 1 deletions
|
|
@ -2363,3 +2363,95 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestImportlongSidechainWithBlockhash200 imports a canonical chain of 500 blocks,
|
||||||
|
// and then finds out about a longer sidechain which forked off at block 200 (300 blocks ago).
|
||||||
|
// It will then import the sidechain, and execute the transactions.
|
||||||
|
// Now, at block 450, there is a transaction which executes BLOCKHASH(205), and stores
|
||||||
|
// the result in slot(0).
|
||||||
|
// This test is meant to ensure that the hashbuffer-based GetAncestorHash correctly
|
||||||
|
// handles non-canon lookups
|
||||||
|
func TestImportlongSidechainWithBlockhash200(t *testing.T) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
// A sender who makes transactions, has some funds
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
funds = big.NewInt(1000000000)
|
||||||
|
gspec = &Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
address: {Balance: funds},
|
||||||
|
// The address 0xAAAAA stores BLOCKHASH in slot zero
|
||||||
|
aa: {
|
||||||
|
// Push
|
||||||
|
Code: []byte{
|
||||||
|
byte(vm.PUSH1), byte(205), // [205]
|
||||||
|
byte(vm.BLOCKHASH), // [ bh(205) ]
|
||||||
|
byte(vm.PUSH1), byte(0), // [bh(205), 0] ; location
|
||||||
|
byte(vm.SSTORE), // []
|
||||||
|
},
|
||||||
|
Nonce: 1,
|
||||||
|
Balance: big.NewInt(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
|
)
|
||||||
|
|
||||||
|
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 500, func(i int, b *BlockGen) {
|
||||||
|
b.SetCoinbase(common.Address{1})
|
||||||
|
})
|
||||||
|
// Import the canonical chain
|
||||||
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
|
gspec.MustCommit(diskdb)
|
||||||
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create initial chain: %v", err)
|
||||||
|
}
|
||||||
|
if n, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
// Ok, the canon chain is done. Now generate the competing chain. In order to be able to
|
||||||
|
// do so, we need to do it in two steps, so we can call b.AddTxWithChain, and have the
|
||||||
|
// sidechain blocks be in the chain already
|
||||||
|
forkBlockNum := 200
|
||||||
|
// Add 200 sideblocks
|
||||||
|
sideblocks1, _ := GenerateChain(params.TestChainConfig, blocks[forkBlockNum], engine, db, 248, func(i int, b *BlockGen) {
|
||||||
|
b.SetCoinbase(common.Address{2})
|
||||||
|
})
|
||||||
|
if n, err := chain.InsertChain(sideblocks1); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
// Add another 150 blocks
|
||||||
|
sideblocks2, _ := GenerateChain(params.TestChainConfig, sideblocks1[len(sideblocks1)-1], engine, db, 150, func(i int, b *BlockGen) {
|
||||||
|
b.SetCoinbase(common.Address{2})
|
||||||
|
if i == 0 {
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(0, aa,
|
||||||
|
big.NewInt(0), 50000, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||||
|
b.AddTxWithChain(chain, tx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if n, err := chain.InsertChain(sideblocks2); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
if got, exp := chain.CurrentBlock().Hash(), sideblocks2[len(sideblocks2)-1].Hash(); got != exp {
|
||||||
|
t.Fatalf("error, exp %x got %x", got, exp)
|
||||||
|
}
|
||||||
|
statedb, err := chain.State()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get state: %v", err)
|
||||||
|
}
|
||||||
|
val := statedb.GetState(aa, common.Hash{})
|
||||||
|
// Check canon
|
||||||
|
if got, exp := val, chain.GetCanonicalHash(205); got != exp {
|
||||||
|
t.Fatalf("wrong hash, got %x exp %x", got, exp)
|
||||||
|
}
|
||||||
|
// Sanity check against the sideblocks
|
||||||
|
if got, exp := val, sideblocks1[3].Hash(); got != exp {
|
||||||
|
t.Fatalf("wrong hash, got %x exp %x", got, exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -546,7 +546,11 @@ func (hc *HeaderChain) GetAncestorHash(ref *types.Header, target uint64) common.
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
maxNonCanonLookups = uint64(100)
|
// The maxNonCanonLookups _must_ be above 256, since this method is used
|
||||||
|
// when importing sidechains. If we are importing a very long sidechain,
|
||||||
|
// then we _might_ have to look back up to 256 blocks in order to execute
|
||||||
|
// the BLOCKHASH opcode, regardless if it's canon or not
|
||||||
|
maxNonCanonLookups = uint64(260)
|
||||||
)
|
)
|
||||||
if hashHistoryTail, _ := hc.hashHistory.Oldest(); hashHistoryTail <= target {
|
if hashHistoryTail, _ := hc.hashHistory.Oldest(); hashHistoryTail <= target {
|
||||||
// Iterate the chain until we hit the target or we hit a ancestor
|
// Iterate the chain until we hit the target or we hit a ancestor
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue