Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add recover node buffer list for pathdb #126

Merged
merged 5 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading