Skip to content

Commit

Permalink
core/rawdb: optimize write block with sidecars
Browse files Browse the repository at this point in the history
  • Loading branch information
buddh0 committed Mar 21, 2024
1 parent 2313e2c commit 2c188b2
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 162 deletions.
17 changes: 12 additions & 5 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1408,12 +1408,19 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
writeSize int64
err error
)
if !bc.chainConfig.IsCancun(last.Number(), last.Time()) {
log.Info("WriteAncientBlocks", "startAt", blockChain[0].Number(), "last", last.Number())
writeSize, err = rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, td)
} else {
writeSize, err = rawdb.WriteAncientBlocksAfterCancun(bc.db, bc.chainConfig, blockChain, receiptChain, td)
if bc.chainConfig.IsCancun(last.Number(), last.Time()) {
for _, block := range blockChain {
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
// try reset empty blob ancient table
if err := rawdb.TryResetEmptyBlobAncientTable(bc.db, block.NumberU64()); err != nil {
return 0, err
}
break
}
}
}
writeSize, err = rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, td)

if err != nil {
log.Error("Error importing chain data to ancients", "err", err)
return 0, err
Expand Down
148 changes: 8 additions & 140 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -823,123 +823,6 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
})
}

// WriteAncientBlocksAfterCancun writes entire block data into ancient store and returns the total written size.
func WriteAncientBlocksAfterCancun(db ethdb.AncientStore, config *params.ChainConfig, blocks []*types.Block, receipts []types.Receipts, td *big.Int) (int64, error) {
if len(blocks) == 0 {
return 0, nil
}

cancunIndex := -1
for i, block := range blocks {
if config.IsCancun(block.Number(), block.Time()) {
cancunIndex = i
break
}
}
log.Info("WriteAncientBlocksAfterCancun", "startAt", blocks[0].Number(), "cancunIndex", cancunIndex, "len", len(blocks))
if cancunIndex < 0 {
return WriteAncientBlocks(db, blocks, receipts, td)
}

// if there has pre-cancun and post-cancun blocks, write them separately
var (
tdSum = new(big.Int).Set(td)
stReceipts []*types.ReceiptForStorage
)

// write pre-cancun blocks
preBlocks := blocks[:cancunIndex]
preReceipts := receipts[:cancunIndex]
preSize, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
for i, block := range preBlocks {
// Convert receipts to storage format and sum up total difficulty.
stReceipts = stReceipts[:0]
for _, receipt := range preReceipts[i] {
stReceipts = append(stReceipts, (*types.ReceiptForStorage)(receipt))
}
header := block.Header()
if i > 0 {
tdSum.Add(tdSum, header.Difficulty)
}
if err := writeAncientBlock(op, block, header, stReceipts, tdSum); err != nil {
return err
}
}
return nil
})
if err != nil {
return preSize, err
}

// write post-cancun blocks
postBlocks := blocks[cancunIndex:]
postReceipts := receipts[cancunIndex:]
// try reset empty blob ancient table
if err := ResetEmptyBlobAncientTable(db, postBlocks[0].NumberU64()); err != nil {
return 0, err
}
postSize, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
for i, block := range postBlocks {
// Convert receipts to storage format and sum up total difficulty.
stReceipts = stReceipts[:0]
for _, receipt := range postReceipts[i] {
stReceipts = append(stReceipts, (*types.ReceiptForStorage)(receipt))
}
header := block.Header()
if i > 0 {
tdSum.Add(tdSum, header.Difficulty)
}
if err := writeAncientBlockWithSidecar(op, block, header, stReceipts, tdSum, block.Sidecars()); err != nil {
return err
}
}
return nil
})
return preSize + postSize, err
}

// WriteAncientBlocksWithSidecars writes entire block data into ancient store and returns the total written size.
// Attention: The caller must set blobs after cancun
func WriteAncientBlocksWithSidecars(db ethdb.AncientStore, blocks []*types.Block, receipts []types.Receipts, td *big.Int, sidecars []types.BlobSidecars) (int64, error) {
if len(blocks) == 0 {
return 0, nil
}

// do some sanity check
if len(blocks) != len(sidecars) {
return 0, fmt.Errorf("the sidecars len is different with blocks, %v:%v", len(sidecars), len(blocks))
}
if len(blocks) != len(receipts) {
return 0, fmt.Errorf("the receipts len is different with blocks, %v:%v", len(receipts), len(blocks))
}
// try reset empty blob ancient table
if err := ResetEmptyBlobAncientTable(db, blocks[0].NumberU64()); err != nil {
return 0, err
}

var (
tdSum = new(big.Int).Set(td)
stReceipts []*types.ReceiptForStorage
)
return db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
for i, block := range blocks {
// Convert receipts to storage format and sum up total difficulty.
stReceipts = stReceipts[:0]
for _, receipt := range receipts[i] {
stReceipts = append(stReceipts, (*types.ReceiptForStorage)(receipt))
}
header := block.Header()
if i > 0 {
tdSum.Add(tdSum, header.Difficulty)
}
if err := writeAncientBlockWithSidecar(op, block, header, stReceipts, tdSum, sidecars[i]); err != nil {
return err
}
}
return nil
})
}

// ReadBlobSidecarsRLP retrieves all the transaction blobs belonging to a block in RLP encoding.
func ReadBlobSidecarsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte
Expand Down Expand Up @@ -983,8 +866,8 @@ func WriteBlobSidecars(db ethdb.KeyValueWriter, hash common.Hash, number uint64,
}
}

// DeleteBlobSidecars removes all blob data associated with a block hash.
func DeleteBlobSidecars(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
// deleteBlobSidecars removes all blob data associated with a block hash.
func deleteBlobSidecars(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
if err := db.Delete(blockBlobSidecarsKey(number, hash)); err != nil {
log.Crit("Failed to delete block blobs", "err", err)
}
Expand All @@ -1007,25 +890,10 @@ func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *type
if err := op.Append(ChainFreezerDifficultyTable, num, td); err != nil {
return fmt.Errorf("can't append block %d total difficulty: %v", num, err)
}
return nil
}

func writeAncientSidecar(op ethdb.AncientWriteOp, num uint64, blobs types.BlobSidecars) error {
if err := op.Append(ChainFreezerBlobSidecarTable, num, blobs); err != nil {
return fmt.Errorf("can't append block %d blobs: %v", num, err)
}
return nil
}

// writeAncientBlockWithSidecar writes entire block data into ancient store and returns the total written size.
// Attention: The caller must set blobs after cancun
func writeAncientBlockWithSidecar(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, td *big.Int, sidecars types.BlobSidecars) error {
num := block.NumberU64()
if err := writeAncientBlock(op, block, header, receipts, td); err != nil {
return err
}
if err := writeAncientSidecar(op, num, sidecars); err != nil {
return err
if len(block.Sidecars()) > 0 {
if err := op.Append(ChainFreezerBlobSidecarTable, num, block.Sidecars()); err != nil {
return fmt.Errorf("can't append block %d blobs: %v", num, err)
}
}
return nil
}
Expand All @@ -1036,7 +904,7 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
DeleteBlobSidecars(db, hash, number) // it is safe to delete non-exist blob
deleteBlobSidecars(db, hash, number) // it is safe to delete non-exist blob
}

// DeleteBlockWithoutNumber removes all block data associated with a hash, except
Expand All @@ -1046,7 +914,7 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
deleteHeaderWithoutNumber(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
DeleteBlobSidecars(db, hash, number)
deleteBlobSidecars(db, hash, number)
}

const badBlockToKeep = 10
Expand Down
8 changes: 5 additions & 3 deletions core/rawdb/accessors_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ func TestBlockBlobSidecarsStorage(t *testing.T) {
}
}

DeleteBlobSidecars(db, blkHash, 0)
deleteBlobSidecars(db, blkHash, 0)
if bs := ReadRawBlobSidecars(db, blkHash, 0); len(bs) != 0 {
t.Fatalf("deleted sidecars returned: %v", bs)
}
Expand Down Expand Up @@ -686,8 +686,10 @@ func BenchmarkWriteAncientBlocks(b *testing.B) {

blocks := allBlocks[i : i+length]
receipts := batchReceipts[:length]
sidecars := batchSidecars[:length]
writeSize, err := WriteAncientBlocksWithSidecars(db, blocks, receipts, td, sidecars)
for j := 0; j < length; j++ {
blocks[i+j].WithSidecars(batchSidecars[j])
}
writeSize, err := WriteAncientBlocks(db, blocks, receipts, td)
if err != nil {
b.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions core/rawdb/chain_freezer.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func (f *chainFreezer) freezeRangeWithBlobs(nfdb *nofreezedb, number, limit uint
return preHashes, err
}

if err = ResetEmptyBlobAncientTable(f, cancunNumber); err != nil {
if err = TryResetEmptyBlobAncientTable(f, cancunNumber); err != nil {
return preHashes, err
}
// freeze post cancun
Expand Down Expand Up @@ -437,6 +437,6 @@ func isCancun(env *ethdb.FreezerEnv, num *big.Int, time uint64) bool {
return env.ChainCfg.IsCancun(num, time)
}

func ResetEmptyBlobAncientTable(db ethdb.AncientStore, next uint64) error {
func TryResetEmptyBlobAncientTable(db ethdb.AncientStore, next uint64) error {
return db.ResetTable(ChainFreezerBlobSidecarTable, next, next, true)
}
17 changes: 5 additions & 12 deletions core/state/pruner/pruner.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,18 +455,11 @@ func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace str
}
// if there has blobs, it needs to back up too.
blobs := rawdb.ReadRawBlobSidecars(chainDb, blockHash, blockNumber)
if blobs != nil {
// Write into new ancient_back db.
if _, err := rawdb.WriteAncientBlocksWithSidecars(frdbBack, []*types.Block{block}, []types.Receipts{receipts}, td, []types.BlobSidecars{blobs}); err != nil {
log.Error("failed to write new ancient", "error", err)
return err
}
} else {
// Write into new ancient_back db.
if _, err := rawdb.WriteAncientBlocks(frdbBack, []*types.Block{block}, []types.Receipts{receipts}, td); err != nil {
log.Error("failed to write new ancient", "error", err)
return err
}
block.WithSidecars(blobs)
// Write into new ancient_back db.
if _, err := rawdb.WriteAncientBlocks(frdbBack, []*types.Block{block}, []types.Receipts{receipts}, td); err != nil {
log.Error("failed to write new ancient", "error", err)
return err
}
// Print the log every 5s for better trace.
if common.PrettyDuration(time.Since(start)) > common.PrettyDuration(5*time.Second) {
Expand Down
9 changes: 9 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,15 @@ func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
}

// IsOnCancun returns whether currentBlockTime is either equal to the Cancun fork time or greater firstly.
func (c *ChainConfig) IsOnCancun(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool {
lastBlockNumber := new(big.Int)
if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 {
lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1))
}
return !c.IsCancun(lastBlockNumber, lastBlockTime) && c.IsCancun(currentBlockNumber, currentBlockTime)
}

// IsPrague returns whether num is either equal to the Prague fork time or greater.
func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
Expand Down

0 comments on commit 2c188b2

Please sign in to comment.