core: fix canonical hash marker update (#24996)
* core: fix reorg * core: revert change for memory efficiency * core: revert changes
This commit is contained in:
parent
8c0c0434c9
commit
f9806dc872
@ -2071,8 +2071,14 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
|||||||
for _, tx := range types.HashDifference(deletedTxs, addedTxs) {
|
for _, tx := range types.HashDifference(deletedTxs, addedTxs) {
|
||||||
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
|
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
|
||||||
}
|
}
|
||||||
// Delete any canonical number assignments above the new head
|
|
||||||
number := bc.CurrentBlock().NumberU64()
|
// Delete all hash markers that are not part of the new canonical chain.
|
||||||
|
// Because the reorg function does not handle new chain head, all hash
|
||||||
|
// markers greater than or equal to new chain head should be deleted.
|
||||||
|
number := commonBlock.NumberU64()
|
||||||
|
if len(newChain) > 1 {
|
||||||
|
number = newChain[1].NumberU64()
|
||||||
|
}
|
||||||
for i := number + 1; ; i++ {
|
for i := number + 1; ; i++ {
|
||||||
hash := rawdb.ReadCanonicalHash(bc.db, i)
|
hash := rawdb.ReadCanonicalHash(bc.db, i)
|
||||||
if hash == (common.Hash{}) {
|
if hash == (common.Hash{}) {
|
||||||
|
@ -3758,3 +3758,112 @@ func TestSetCanonical(t *testing.T) {
|
|||||||
chain.SetCanonical(canon[TriesInMemory-1])
|
chain.SetCanonical(canon[TriesInMemory-1])
|
||||||
verify(canon[TriesInMemory-1])
|
verify(canon[TriesInMemory-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted
|
||||||
|
// correctly in case reorg is called.
|
||||||
|
func TestCanonicalHashMarker(t *testing.T) {
|
||||||
|
var cases = []struct {
|
||||||
|
forkA int
|
||||||
|
forkB int
|
||||||
|
}{
|
||||||
|
// ForkA: 10 blocks
|
||||||
|
// ForkB: 1 blocks
|
||||||
|
//
|
||||||
|
// reorged:
|
||||||
|
// markers [2, 10] should be deleted
|
||||||
|
// markers [1] should be updated
|
||||||
|
{10, 1},
|
||||||
|
|
||||||
|
// ForkA: 10 blocks
|
||||||
|
// ForkB: 2 blocks
|
||||||
|
//
|
||||||
|
// reorged:
|
||||||
|
// markers [3, 10] should be deleted
|
||||||
|
// markers [1, 2] should be updated
|
||||||
|
{10, 2},
|
||||||
|
|
||||||
|
// ForkA: 10 blocks
|
||||||
|
// ForkB: 10 blocks
|
||||||
|
//
|
||||||
|
// reorged:
|
||||||
|
// markers [1, 10] should be updated
|
||||||
|
{10, 10},
|
||||||
|
|
||||||
|
// ForkA: 10 blocks
|
||||||
|
// ForkB: 11 blocks
|
||||||
|
//
|
||||||
|
// reorged:
|
||||||
|
// markers [1, 11] should be updated
|
||||||
|
{10, 11},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
gspec = &Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{},
|
||||||
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
)
|
||||||
|
forkA, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkA, func(i int, gen *BlockGen) {})
|
||||||
|
forkB, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkB, func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
|
// Initialize test chain
|
||||||
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
|
gspec.MustCommit(diskdb)
|
||||||
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
// Insert forkA and forkB, the canonical should on forkA still
|
||||||
|
if n, err := chain.InsertChain(forkA); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
if n, err := chain.InsertChain(forkB); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
verify := func(head *types.Block) {
|
||||||
|
if chain.CurrentBlock().Hash() != head.Hash() {
|
||||||
|
t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash())
|
||||||
|
}
|
||||||
|
if chain.CurrentFastBlock().Hash() != head.Hash() {
|
||||||
|
t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash())
|
||||||
|
}
|
||||||
|
if chain.CurrentHeader().Hash() != head.Hash() {
|
||||||
|
t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash())
|
||||||
|
}
|
||||||
|
if !chain.HasState(head.Root()) {
|
||||||
|
t.Fatalf("Lost block state %v %x", head.Number(), head.Hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch canonical chain to forkB if necessary
|
||||||
|
if len(forkA) < len(forkB) {
|
||||||
|
verify(forkB[len(forkB)-1])
|
||||||
|
} else {
|
||||||
|
verify(forkA[len(forkA)-1])
|
||||||
|
chain.SetCanonical(forkB[len(forkB)-1])
|
||||||
|
verify(forkB[len(forkB)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all hash markers are updated correctly
|
||||||
|
for i := 0; i < len(forkB); i++ {
|
||||||
|
block := forkB[i]
|
||||||
|
hash := chain.GetCanonicalHash(block.NumberU64())
|
||||||
|
if hash != block.Hash() {
|
||||||
|
t.Fatalf("Unexpected canonical hash %d", block.NumberU64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.forkA > c.forkB {
|
||||||
|
for i := uint64(c.forkB) + 1; i <= uint64(c.forkA); i++ {
|
||||||
|
hash := chain.GetCanonicalHash(i)
|
||||||
|
if hash != (common.Hash{}) {
|
||||||
|
t.Fatalf("Unexpected canonical hash %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user