core/rawdb: remove BAL from chain freezer

This commit is contained in:
jonny rhea 2026-03-23 14:10:47 -05:00
parent 50e5b7b60a
commit 34a09b1aaf
6 changed files with 14 additions and 142 deletions

View file

@ -1476,7 +1476,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Ensure genesis is in the ancient store
if blockChain[0].NumberU64() == 1 {
if frozen, _ := bc.db.Ancients(); frozen == 0 {
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []rlp.RawValue{rlp.EmptyList}, nil)
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []rlp.RawValue{rlp.EmptyList})
if err != nil {
log.Error("Error writing genesis to ancients", "err", err)
return 0, err
@ -1486,7 +1486,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
}
}
// Write all chain data to ancients.
writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, nil)
writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain)
if err != nil {
log.Error("Error importing chain data to ancients", "err", err)
return 0, err
@ -2907,7 +2907,7 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e
first = headers[0].Number.Uint64()
)
if first == 1 && frozen == 0 {
_, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []rlp.RawValue{rlp.EmptyList}, nil)
_, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []rlp.RawValue{rlp.EmptyList})
if err != nil {
log.Error("Error writing genesis to ancients", "err", err)
return 0, err

View file

@ -611,41 +611,9 @@ func HasAccessList(db ethdb.Reader, hash common.Hash, number uint64) bool {
return len(ReadAccessListRLP(db, hash, number)) > 0
}
// ReadAccessListRLP retrieves the RLP-encoded block access list for a block.
// ReadAccessListRLP retrieves the RLP-encoded block access list for a block from KV.
func ReadAccessListRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte
err := db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
if isCanon(reader, number, hash) {
data, _ = reader.Ancient(ChainFreezerBALTable, number)
return nil
}
data, _ = db.Get(balKey(number, hash))
return nil
})
if err != nil {
log.Crit("error reading from ancient store", "err", err)
}
return data
}
// ReadCanonicalAccessListRLP retrieves the BAL RLP for the canonical block at number.
// Optionally takes the block hash to avoid looking it up.
func ReadCanonicalAccessListRLP(db ethdb.Reader, number uint64, hash *common.Hash) rlp.RawValue {
var data []byte
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
data, _ = reader.Ancient(ChainFreezerBALTable, number)
if len(data) > 0 {
return nil
}
// BAL is not in ancients, read from db by hash and number.
if hash != nil {
data, _ = db.Get(balKey(number, *hash))
} else {
hashBytes, _ := db.Get(headerHashKey(number))
data, _ = db.Get(balKey(number, common.BytesToHash(hashBytes)))
}
return nil
})
data, _ := db.Get(balKey(number, hash))
return data
}
@ -760,15 +728,11 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
}
// WriteAncientBlocks writes entire block data into ancient store and returns the total written size.
func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts []rlp.RawValue, bals []rlp.RawValue) (int64, error) {
func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts []rlp.RawValue) (int64, error) {
return db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
for i, block := range blocks {
header := block.Header()
var bal rlp.RawValue
if bals != nil {
bal = bals[i]
}
if err := writeAncientBlock(op, block, header, receipts[i], bal); err != nil {
if err := writeAncientBlock(op, block, header, receipts[i]); err != nil {
return err
}
}
@ -776,7 +740,7 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
})
}
func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts rlp.RawValue, bal rlp.RawValue) error {
func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts rlp.RawValue) error {
num := block.NumberU64()
if err := op.AppendRaw(ChainFreezerHashTable, num, block.Hash().Bytes()); err != nil {
return fmt.Errorf("can't add block %d hash: %v", num, err)
@ -790,9 +754,6 @@ func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *type
if err := op.Append(ChainFreezerReceiptTable, num, receipts); err != nil {
return fmt.Errorf("can't append block %d receipts: %v", num, err)
}
if err := op.AppendRaw(ChainFreezerBALTable, num, bal); err != nil {
return fmt.Errorf("can't append block %d BAL: %v", num, err)
}
return nil
}
@ -815,9 +776,6 @@ func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header) (i
if err := op.AppendRaw(ChainFreezerReceiptTable, num, nil); err != nil {
return fmt.Errorf("can't append block %d receipts: %v", num, err)
}
if err := op.AppendRaw(ChainFreezerBALTable, num, nil); err != nil {
return fmt.Errorf("can't append block %d BAL: %v", num, err)
}
}
return nil
})
@ -826,7 +784,6 @@ func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header) (i
// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
DeleteAccessList(db, hash, number)
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
}
@ -835,7 +792,6 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
// the hash to number mapping.
func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
DeleteAccessList(db, hash, number)
deleteHeaderWithoutNumber(db, hash, number)
DeleteBody(db, hash, number)
}

View file

@ -433,7 +433,7 @@ func TestAncientStorage(t *testing.T) {
}
// Write and verify the header in the database
WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil}), nil)
WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil}))
if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 {
t.Fatalf("no header returned")
@ -563,7 +563,7 @@ func BenchmarkWriteAncientBlocks(b *testing.B) {
blocks := allBlocks[i : i+length]
receipts := batchReceipts[:length]
writeSize, err := WriteAncientBlocks(db, blocks, types.EncodeBlockReceiptLists(receipts), nil)
writeSize, err := WriteAncientBlocks(db, blocks, types.EncodeBlockReceiptLists(receipts))
if err != nil {
b.Fatal(err)
}
@ -868,7 +868,7 @@ func TestHeadersRLPStorage(t *testing.T) {
}
receipts := make([]types.Receipts, 100)
// Write first half to ancients
WriteAncientBlocks(db, chain[:50], types.EncodeBlockReceiptLists(receipts[:50]), nil)
WriteAncientBlocks(db, chain[:50], types.EncodeBlockReceiptLists(receipts[:50]))
// Write second half to db
for i := 50; i < 100; i++ {
WriteCanonicalHash(db, chain[i].Hash(), chain[i].NumberU64())
@ -977,80 +977,4 @@ func TestBALStorage(t *testing.T) {
}
}
// TestBALFreezer tests that BALs are frozen alongside other block data
// and can be read from the freezer.
func TestBALFreezer(t *testing.T) {
frdir := t.TempDir()
db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: frdir})
if err != nil {
t.Fatalf("failed to create database with ancient backend: %v", err)
}
defer db.Close()
// Create a test block.
block := types.NewBlockWithHeader(&types.Header{
Number: big.NewInt(0),
Extra: []byte("test block"),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
})
hash, number := block.Hash(), block.NumberU64()
// Verify no BAL exists before writing.
if blob := ReadAccessListRLP(db, hash, number); len(blob) > 0 {
t.Fatalf("non existent BAL returned")
}
// Write a BAL to KV first, then freeze.
balRLP, testBAL := makeTestBAL(t)
// Freeze via WriteAncientBlocks.
WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil}), []rlp.RawValue{balRLP})
// Verify the BAL can be read from the freezer.
if blob := ReadAccessListRLP(db, hash, number); len(blob) == 0 {
t.Fatal("no BAL returned from freezer")
}
if b := ReadAccessList(db, hash, number); b == nil {
t.Fatal("ReadAccessList returned nil from freezer")
} else if b.Hash() != testBAL.Hash() {
t.Fatalf("frozen BAL hash mismatch: got %x, want %x", b.Hash(), testBAL.Hash())
}
// Verify ReadCanonicalAccessListRLP works.
if blob := ReadCanonicalAccessListRLP(db, number, &hash); len(blob) == 0 {
t.Fatal("ReadCanonicalAccessListRLP returned empty for frozen block")
}
}
// TestBALEmptyFreezer tests that pre-EIP-8189 blocks without BALs have empty
// freezer entries.
func TestBALEmptyFreezer(t *testing.T) {
frdir := t.TempDir()
db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: frdir})
if err != nil {
t.Fatalf("failed to create database with ancient backend: %v", err)
}
defer db.Close()
// Create and freeze a block with no BAL.
block := types.NewBlockWithHeader(&types.Header{
Number: big.NewInt(0),
Extra: []byte("no bal block"),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
})
hash, number := block.Hash(), block.NumberU64()
WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil}), nil)
// HasAccessList should return false for a block with an empty freezer entry.
if HasAccessList(db, hash, number) {
t.Fatal("HasAccessList returned true for block with no BAL")
}
if b := ReadAccessList(db, hash, number); b != nil {
t.Fatalf("ReadAccessList returned non-nil for block with no BAL: %v", b)
}
}

View file

@ -35,9 +35,6 @@ const (
// ChainFreezerReceiptTable indicates the name of the freezer receipts table.
ChainFreezerReceiptTable = "receipts"
// ChainFreezerBALTable indicates the name of the freezer block access list table.
ChainFreezerBALTable = "bals"
)
// chainFreezerTableConfigs configures the settings for tables in the chain freezer.
@ -49,7 +46,6 @@ var chainFreezerTableConfigs = map[string]freezerTableConfig{
ChainFreezerHashTable: {noSnappy: true, prunable: false},
ChainFreezerBodiesTable: {noSnappy: false, prunable: true},
ChainFreezerReceiptTable: {noSnappy: false, prunable: true},
ChainFreezerBALTable: {noSnappy: false, prunable: true},
}
// freezerTableConfig contains the settings for a freezer table.

View file

@ -327,7 +327,6 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
if len(receipts) == 0 {
return fmt.Errorf("block receipts missing, can't freeze block %d", number)
}
bal := ReadAccessListRLP(nfdb, hash, number)
// Write to the batch.
if err := op.AppendRaw(ChainFreezerHashTable, number, hash[:]); err != nil {
return fmt.Errorf("can't write hash to Freezer: %v", err)
@ -341,9 +340,6 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
if err := op.AppendRaw(ChainFreezerReceiptTable, number, receipts); err != nil {
return fmt.Errorf("can't write receipts to Freezer: %v", err)
}
if err := op.AppendRaw(ChainFreezerBALTable, number, bal); err != nil {
return fmt.Errorf("can't write BAL to Freezer: %v", err)
}
hashes = append(hashes, hash)
}
return nil

View file

@ -117,7 +117,7 @@ func TestTxIndexer(t *testing.T) {
}
for _, c := range cases {
db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{})
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), types.EncodeBlockReceiptLists(append([]types.Receipts{{}}, receipts...)), nil)
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), types.EncodeBlockReceiptLists(append([]types.Receipts{{}}, receipts...)))
// Index the initial blocks from ancient store
indexer := &txIndexer{
@ -237,7 +237,7 @@ func TestTxIndexerRepair(t *testing.T) {
for _, c := range cases {
db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{})
encReceipts := types.EncodeBlockReceiptLists(append([]types.Receipts{{}}, receipts...))
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), encReceipts, nil)
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), encReceipts)
// Index the initial blocks from ancient store
indexer := &txIndexer{
@ -428,7 +428,7 @@ func TestTxIndexerReport(t *testing.T) {
for _, c := range cases {
db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{})
encReceipts := types.EncodeBlockReceiptLists(append([]types.Receipts{{}}, receipts...))
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), encReceipts, nil)
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), encReceipts)
// Index the initial blocks from ancient store
indexer := &txIndexer{