Skip to content

Commit

Permalink
feat: add recover node buffer list for pathdb (bnb-chain#126)
Browse files Browse the repository at this point in the history
Co-authored-by: VM <[email protected]>
Co-authored-by: Owen <[email protected]>
  • Loading branch information
3 people authored Oct 16, 2024
1 parent 5bad8fe commit 5a039c4
Show file tree
Hide file tree
Showing 33 changed files with 785 additions and 174 deletions.
4 changes: 2 additions & 2 deletions cmd/geth/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func initGenesis(ctx *cli.Context) error {
}
defer chaindb.Close()

triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle(), true)
defer triedb.Close()

_, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
Expand Down Expand Up @@ -582,7 +582,7 @@ func dump(ctx *cli.Context) error {
if err != nil {
return err
}
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false, false) // always enable preimage lookup
defer triedb.Close()

state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
Expand Down
2 changes: 1 addition & 1 deletion cmd/geth/dbcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ func dbDumpTrie(ctx *cli.Context) error {

db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false, false)
defer triedb.Close()

var (
Expand Down
10 changes: 5 additions & 5 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func verifyState(ctx *cli.Context) error {
log.Error("Failed to load head block")
return errors.New("no head block")
}
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false, false)
defer triedb.Close()

snapConfig := snapshot.Config{
Expand Down Expand Up @@ -299,7 +299,7 @@ func traverseState(ctx *cli.Context) error {
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()

triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false, false)
defer triedb.Close()

headBlock := rawdb.ReadHeadBlock(chaindb)
Expand Down Expand Up @@ -408,7 +408,7 @@ func traverseRawState(ctx *cli.Context) error {
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()

triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false, false)
defer triedb.Close()

headBlock := rawdb.ReadHeadBlock(chaindb)
Expand Down Expand Up @@ -573,7 +573,7 @@ func dumpState(ctx *cli.Context) error {
return err
}
defer db.Close()
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false, false)
defer triedb.Close()

snapConfig := snapshot.Config{
Expand Down Expand Up @@ -655,7 +655,7 @@ func snapshotExportPreimages(ctx *cli.Context) error {
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()

triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false)
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, false, true, false, false)
defer triedb.Close()

var root common.Hash
Expand Down
8 changes: 5 additions & 3 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/core/txpool/bundlepool"
"math"
"math/big"
"net"
Expand All @@ -35,6 +34,7 @@ import (
"strings"
"time"

"github.com/ethereum/go-ethereum/core/txpool/bundlepool"
pcsclite "github.com/gballet/go-libpcsclite"
gopsutil "github.com/shirou/gopsutil/mem"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -325,7 +325,7 @@ var (
PathDBNodeBufferTypeFlag = &cli.StringFlag{
Name: "pathdb.nodebuffer",
Usage: "Type of trienodebuffer to cache trie nodes in disklayer('list', 'sync', or 'async')",
Value: "async",
Value: "list",
Category: flags.StateCategory,
}
ProposeBlockIntervalFlag = &cli.Uint64Flag{
Expand Down Expand Up @@ -2508,7 +2508,8 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
}

// MakeTrieDatabase constructs a trie database based on the configured scheme.
func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, preimage bool, readOnly bool, isVerkle bool) *triedb.Database {
func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, preimage bool, readOnly bool, isVerkle bool,
useBase bool) *triedb.Database {
config := &triedb.Config{
Preimages: preimage,
IsVerkle: isVerkle,
Expand All @@ -2529,6 +2530,7 @@ func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, p
} else {
config.PathDB = pathdb.Defaults
}
config.PathDB.UseBase = useBase
config.PathDB.JournalFilePath = fmt.Sprintf("%s/%s", stack.ResolvePath("chaindata"), eth.JournalFileName)
return triedb.NewDatabase(disk, config)
}
5 changes: 3 additions & 2 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,9 @@ type CacheConfig struct {
KeepProofBlockSpan uint64 // Block span of keep proof
SnapshotNoBuild bool // Whether the background generation is allowed
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
JournalFilePath string
JournalFile bool
JournalFilePath string // The file path to journal pathdb diff layers
JournalFile bool // Whether to enable journal file
UseBase bool // Flag if just use base for nodebufferlist

TrieCommitInterval uint64 // Define a block height interval, commit trie every TrieCommitInterval block height.
}
Expand Down
5 changes: 3 additions & 2 deletions core/blockchain_repair_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {

func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
// It's hard to follow the test case, visualize the input
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
// fmt.Println(tt.dump(true))

// Create a temporary persistent database
Expand Down Expand Up @@ -1787,6 +1787,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
TrieTimeLimit: 5 * time.Minute,
SnapshotLimit: 0, // Disable snapshot by default
StateScheme: scheme,
UseBase: true,
}
)
defer engine.Close()
Expand Down Expand Up @@ -1904,7 +1905,7 @@ func TestIssue23496(t *testing.T) {

func testIssue23496(t *testing.T, scheme string) {
// It's hard to follow the test case, visualize the input
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))

// Create a temporary persistent database
datadir := t.TempDir()
Expand Down
4 changes: 3 additions & 1 deletion core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ func TestVerkleGenesisCommit(t *testing.T) {
}

db := rawdb.NewMemoryDatabase()
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
pathConfig := pathdb.Defaults
pathConfig.UseBase = true
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathConfig})
block := genesis.MustCommit(db, triedb)
if !bytes.Equal(block.Root().Bytes(), expected) {
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
Expand Down
46 changes: 38 additions & 8 deletions core/rawdb/accessors_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,43 +224,73 @@ func ReadStateStorageHistory(db ethdb.AncientReaderOp, id uint64) []byte {
return blob
}

// ReadStateTrieNodesHistory retrieves the trie nodes corresponding to the specified
// state history. Compute the position of state history in freezer by minus one
// since the id of first state history starts from one(zero for initial state).
func ReadStateTrieNodesHistory(db ethdb.AncientReaderOp, id uint64) []byte {
blob, err := db.Ancient(stateHistoryTrieNodesData, id-1)
if err != nil {
return nil
}
return blob
}

// ReadStateHistory retrieves the state history from database with provided id.
// Compute the position of state history in freezer by minus one since the id
// of first state history starts from one(zero for initial state).
func ReadStateHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []byte, []byte, []byte, error) {
func ReadStateHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []byte, []byte, []byte, []byte, error) {
meta, err := db.Ancient(stateHistoryMeta, id-1)
if err != nil {
return nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, err
}
accountIndex, err := db.Ancient(stateHistoryAccountIndex, id-1)
if err != nil {
return nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, err
}
storageIndex, err := db.Ancient(stateHistoryStorageIndex, id-1)
if err != nil {
return nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, err
}
accountData, err := db.Ancient(stateHistoryAccountData, id-1)
if err != nil {
return nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, err
}
storageData, err := db.Ancient(stateHistoryStorageData, id-1)
if err != nil {
return nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, err
}
trieNodesData, err := db.Ancient(stateHistoryStorageData, id-1)
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
return meta, accountIndex, storageIndex, accountData, storageData, nil
return meta, accountIndex, storageIndex, accountData, storageData, trieNodesData, nil
}

// WriteStateHistory writes the provided state history to database. Compute the
// position of state history in freezer by minus one since the id of first state
// history starts from one(zero for initial state).
func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte, accounts []byte, storages []byte) {
func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte,
accounts []byte, storages []byte) {
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
op.AppendRaw(stateHistoryMeta, id-1, meta)
op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex)
op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex)
op.AppendRaw(stateHistoryAccountData, id-1, accounts)
op.AppendRaw(stateHistoryStorageData, id-1, storages)
return nil
})
}

// WriteStateHistoryWithTrieNodes writes the provided state history to database.
func WriteStateHistoryWithTrieNodes(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte,
accounts []byte, storages []byte, trieNodes []byte) {
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
op.AppendRaw(stateHistoryMeta, id-1, meta)
op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex)
op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex)
op.AppendRaw(stateHistoryAccountData, id-1, accounts)
op.AppendRaw(stateHistoryStorageData, id-1, storages)
op.AppendRaw(stateHistoryTrieNodesData, id-1, trieNodes)
return nil
})
}
29 changes: 15 additions & 14 deletions core/rawdb/ancient_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,21 @@ const (
stateHistoryTableSize = 2 * 1000 * 1000 * 1000

// stateHistoryAccountIndex indicates the name of the freezer state history table.
stateHistoryMeta = "history.meta"
stateHistoryAccountIndex = "account.index"
stateHistoryStorageIndex = "storage.index"
stateHistoryAccountData = "account.data"
stateHistoryStorageData = "storage.data"
stateHistoryMeta = "history.meta"
stateHistoryAccountIndex = "account.index"
stateHistoryStorageIndex = "storage.index"
stateHistoryAccountData = "account.data"
stateHistoryStorageData = "storage.data"
stateHistoryTrieNodesData = "trienodes.data"
)

var stateFreezerNoSnappy = map[string]bool{
stateHistoryMeta: true,
stateHistoryAccountIndex: false,
stateHistoryStorageIndex: false,
stateHistoryAccountData: false,
stateHistoryStorageData: false,
stateHistoryMeta: true,
stateHistoryAccountIndex: false,
stateHistoryStorageIndex: false,
stateHistoryAccountData: false,
stateHistoryStorageData: false,
stateHistoryTrieNodesData: false,
}

const (
Expand All @@ -79,18 +81,17 @@ var (
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
StateFreezerName = "state" // the folder name of reverse diff ancient store.
ProofFreezerName = "proof" // the folder name of propose withdraw proof store.

)

// freezers the collections of all builtin freezers.
var freezers = []string{ChainFreezerName, StateFreezerName, ProofFreezerName}

// NewStateFreezer initializes the freezer for state history.
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
func NewStateFreezer(ancientDir string, readOnly, writeTrieNode bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, writeTrieNode, stateHistoryTableSize, stateFreezerNoSnappy)
}

// NewProofFreezer initializes the freezer for propose withdraw proof.
func NewProofFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, ProofFreezerName), "eth/db/proof", readOnly, stateHistoryTableSize, proofFreezerNoSnappy)
return NewResettableFreezer(filepath.Join(ancientDir, ProofFreezerName), "eth/db/proof", readOnly, false, stateHistoryTableSize, proofFreezerNoSnappy)
}
45 changes: 44 additions & 1 deletion core/rawdb/ancient_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package rawdb

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)

type tableSize struct {
Expand Down Expand Up @@ -96,7 +99,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
if err != nil {
return nil, err
}
f, err := NewStateFreezer(datadir, true)
f, err := NewStateFreezer(datadir, true, DetectTrieNodesFile(datadir))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -167,3 +170,43 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
table.dumpIndexStdout(start, end)
return nil
}

// DetectTrieNodesFile detects whether trie nodes data exists
func DetectTrieNodesFile(ancientDir string) bool {
trieNodesFilePath := filepath.Join(ancientDir, StateFreezerName, fmt.Sprintf("%s.%s",
stateHistoryTrieNodesData, "cidx"))
return common.FileExist(trieNodesFilePath)
}

// DeleteTrieNodesFile deletes all trie nodes data in state directory
func DeleteTrieNodesFile(ancientDir string) error {
statePath := filepath.Join(ancientDir, StateFreezerName)
dir, err := os.Open(statePath)
if err != nil {
return err
}
defer dir.Close()

names, err := dir.Readdirnames(0)
if err != nil {
return err
}

for _, name := range names {
filePath := filepath.Join(statePath, name)
fileInfo, err := os.Stat(filePath)
if err != nil {
return err
}

if !fileInfo.IsDir() && strings.Contains(filepath.Base(filePath), stateHistoryTrieNodesData) {
err = os.Remove(filePath)
if err != nil {
return err
}
log.Info(fmt.Sprintf("Delete %s file", filePath))
}
}

return nil
}
8 changes: 6 additions & 2 deletions core/rawdb/freezer.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ type Freezer struct {
// NewChainFreezer is a small utility method around NewFreezer that sets the
// default parameters for the chain storage.
func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) {
return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
return NewFreezer(datadir, namespace, readonly, false, freezerTableSize, chainFreezerNoSnappy)
}

// NewFreezer creates a freezer instance for maintaining immutable ordered
// data according to the given parameters.
//
// The 'tables' argument defines the data tables. If the value of a map
// entry is true, snappy compression is disabled for the table.
func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*Freezer, error) {
func NewFreezer(datadir string, namespace string, readonly, writeTrieNode bool, maxTableSize uint32, tables map[string]bool) (*Freezer, error) {
// Create the initial freezer object
var (
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
Expand Down Expand Up @@ -126,6 +126,10 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui

// Create the tables.
for name, disableSnappy := range tables {
if name == stateHistoryTrieNodesData && !writeTrieNode {
log.Info("Not create trie node data")
continue
}
table, err := newTable(datadir, name, readMeter, writeMeter, sizeGauge, maxTableSize, disableSnappy, readonly)
if err != nil {
for _, table := range freezer.tables {
Expand Down
Loading

0 comments on commit 5a039c4

Please sign in to comment.