Skip to content

Commit

Permalink
fix(snap): fix a snap sync issue (#195)
Browse files Browse the repository at this point in the history
* fix snap sync bug

* fix snap sync bug

* feat(snap): add more comments

---------

Co-authored-by: maskpp <[email protected]>
  • Loading branch information
davidtaikocha and mask-pp authored Mar 26, 2024
1 parent d81e682 commit 4951b7b
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 105 deletions.
29 changes: 16 additions & 13 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1005,14 +1005,13 @@ func (bc *BlockChain) Stop() {
if !bc.cacheConfig.TrieDirtyDisabled {
triedb := bc.triedb

maxOffset := uint64(TriesInMemory - 1)
// CHANGE(taiko): If Taiko is enabled, we need to set the max offset based on the finalized block.
// CHANGE(taiko): If Taiko flag is enabled, we need to set the max offset based on the finalized block.
var maxOffset uint64 = TriesInMemory - 1
if bc.chainConfig.Taiko {
if header := bc.CurrentFinalBlock(); header != nil {
maxOffset = bc.CurrentBlock().Number.Uint64() - header.Number.Uint64()
} else {
maxOffset = bc.CurrentBlock().Number.Uint64()
log.Debug("Finalized block not found, using default trie gc limit")
maxOffset = TriesInMemory*2 - 1
header, curBlock := bc.CurrentFinalBlock(), bc.CurrentBlock()
if header != nil && curBlock != nil {
maxOffset += curBlock.Number.Uint64() - header.Number.Uint64()
}
}
for _, offset := range []uint64{0, 1, maxOffset} {
Expand Down Expand Up @@ -1406,20 +1405,24 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
bc.triedb.Cap(limit - ethdb.IdealBatchSize)
}
// Find the next state trie we need to commit
chosen := current - TriesInMemory
// CHANGE(taiko): If Taiko is enabled, we need to set the max offset based on the finalized block.
var chosen uint64
if bc.chainConfig.Taiko {
if header := bc.CurrentFinalBlock(); header != nil {
chosen = header.Number.Uint64() - 1
if header := bc.CurrentFinalBlock(); header != nil && header.Number.Uint64() > TriesInMemory*2 {
chosen = header.Number.Uint64() - TriesInMemory*2
} else {
chosen = 0
log.Debug("Finalized block not found, using chosen number for trie gc")
}
} else {
chosen = current - TriesInMemory
}
flushInterval := time.Duration(bc.flushInterval.Load())
// CHANGE(taiko): If chosen is 0, we don't need to flush the trie.
needFlush := bc.gcproc > flushInterval
if bc.chainConfig.Taiko {
needFlush = bc.gcproc > flushInterval && chosen > 0
}
// If we exceeded time allowance, flush an entire trie to disk
if chosen > 0 && bc.gcproc > flushInterval { // CHANGE(taiko): If chosen is 0, we don't need to flush the trie.
if needFlush {
// If the header is missing (canonical chain behind), we're reorging a low
// diff sidechain. Suspend committing until this operation is completed.
header := bc.GetHeaderByNumber(chosen)
Expand Down
196 changes: 104 additions & 92 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2116,98 +2116,6 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
}
}

func testTaikoPruningFinalize(t *testing.T, n int, finalizedNumber uint64, stop bool) {
// Generate a canonical chain to act as the main dataset
chainConfig := *params.TestChainConfig
balance := big.NewInt(math.MaxInt64)
balance.Mul(balance, big.NewInt(int64(1000)))
var (
engine = beacon.New(ethash.NewFaker())
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
nonce = uint64(0)

gspec = &Genesis{
Config: &chainConfig,
Alloc: types.GenesisAlloc{addr: {Balance: balance}},
BaseFee: big.NewInt(params.InitialBaseFee),
}
signer = types.LatestSigner(gspec.Config)
mergeBlock = math.MaxInt32
)
// Generate and import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
//defer chain.Stop()
chain.chainConfig.Taiko = true

_, blocks, _ := GenerateChainWithGenesis(gspec, engine, n, func(i int, gen *BlockGen) {
to := common.HexToAddress("deadbeef")
baseTx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainConfig.ChainID,
Nonce: nonce,
To: &to,
Value: big.NewInt(100),
Gas: 21000,
GasTipCap: big.NewInt(100000),
GasFeeCap: big.NewInt(100000),
AccessList: nil,
Data: nil,
})
_ = baseTx.MarkAsAnchor()
tx, err := types.SignTx(baseTx, signer, key)
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
gen.AddTx(tx)
if int(gen.header.Number.Uint64()) >= mergeBlock {
gen.SetPoS()
}
nonce++
})

for i := 0; i < n; i++ {
block := blocks[i]
if n, err := chain.InsertChain([]*types.Block{block}); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
if block.Number().Uint64() == finalizedNumber {
// Set the finalized block header.
chain.SetFinalized(block.Header())
}
}

// Stop chain.
if stop {
chain.Stop()
} else {
defer chain.Stop()
}

var firstNonPrunedBlock *types.Block
for i := 0; i < n; i++ {
block := blocks[i]
if chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
firstNonPrunedBlock = block
break
}
}

assert.NotEmpty(t, firstNonPrunedBlock)
assert.Equal(t, finalizedNumber, firstNonPrunedBlock.NumberU64())
}

func TestTaikoPruningFinalize(t *testing.T) {
testTaikoPruningFinalize(t, 2*TriesInMemory, TriesInMemory/2, false)
testTaikoPruningFinalize(t, 2*TriesInMemory, TriesInMemory/2, true)
testTaikoPruningFinalize(t, 2*TriesInMemory, 2*TriesInMemory-1, false)
testTaikoPruningFinalize(t, 2*TriesInMemory, 2*TriesInMemory-1, true)
testTaikoPruningFinalize(t, 8000, 100, true)
testTaikoPruningFinalize(t, 8000, 100, false)
}

// Tests that importing a sidechain (S), where
// - S is sidechain, containing blocks [Sn...Sm]
// - C is canon chain, containing blocks [G..Cn..Cm]
Expand Down Expand Up @@ -4419,3 +4327,107 @@ func TestEIP3651(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
}

func testTaikoPruningFinalize(t *testing.T, n int, finalizedNumber uint64, stop bool) {
// Generate a canonical chain to act as the main dataset
chainConfig := *params.TestChainConfig
balance := big.NewInt(math.MaxInt64)
balance.Mul(balance, big.NewInt(int64(1000)))
var (
engine = beacon.New(ethash.NewFaker())
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
nonce = uint64(0)

gspec = &Genesis{
Config: &chainConfig,
Alloc: types.GenesisAlloc{addr: {Balance: balance}},
BaseFee: big.NewInt(params.InitialBaseFee),
}
signer = types.LatestSigner(gspec.Config)
mergeBlock = math.MaxInt32
)
// Generate and import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
chain.chainConfig.Taiko = true

_, blocks, _ := GenerateChainWithGenesis(gspec, engine, n, func(i int, gen *BlockGen) {
to := common.HexToAddress("taiko")
baseTx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainConfig.ChainID,
Nonce: nonce,
To: &to,
Value: big.NewInt(100),
Gas: 21000,
GasTipCap: big.NewInt(100000),
GasFeeCap: big.NewInt(100000),
AccessList: nil,
Data: nil,
})
_ = baseTx.MarkAsAnchor()
tx, err := types.SignTx(baseTx, signer, key)
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
gen.AddTx(tx)
if int(gen.header.Number.Uint64()) >= mergeBlock {
gen.SetPoS()
}
nonce++
})

for i := 0; i < n; i++ {
block := blocks[i]
if n, err := chain.InsertChain([]*types.Block{block}); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
if finalizedNumber > 0 && block.Number().Uint64() == finalizedNumber {
// Set the finalized block header.
chain.SetFinalized(block.Header())
}
}

// Stop chain.
if stop {
chain.Stop()
} else {
defer chain.Stop()
}

var firstNonPrunedBlock *types.Block
for i := 0; i < n; i++ {
block := blocks[i]
if chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
firstNonPrunedBlock = block
break
}
}

assert.True(t, firstNonPrunedBlock != nil)

if finalizedNumber == 0 || finalizedNumber <= TriesInMemory*2 {
assert.Equal(t, uint64(1), firstNonPrunedBlock.Number().Uint64())
} else {
assert.Equal(t, (finalizedNumber - TriesInMemory*2 + 1), firstNonPrunedBlock.Number().Uint64())
}
}

func TestTaikoPruningFinalize(t *testing.T) {
testTaikoPruningFinalize(t, 3*TriesInMemory, 0, false)
testTaikoPruningFinalize(t, 3*TriesInMemory, 0, true)

testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory/2, false)
testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory/2, true)

testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2, false)
testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2, true)

testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2+1, false)
testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2+1, true)

testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2+10, false)
testTaikoPruningFinalize(t, 3*TriesInMemory, TriesInMemory*2+10, true)
}
1 change: 1 addition & 0 deletions params/taiko_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var networkIDToChainConfig = map[*big.Int]*ChainConfig{
EldfellNetworkID: TaikoChainConfig,
JolnirNetworkID: TaikoChainConfig,
KatlaNetworkID: TaikoChainConfig,
HeklaNetworkID: TaikoChainConfig,
MainnetChainConfig.ChainID: MainnetChainConfig,
SepoliaChainConfig.ChainID: SepoliaChainConfig,
GoerliChainConfig.ChainID: GoerliChainConfig,
Expand Down

0 comments on commit 4951b7b

Please sign in to comment.