diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go
index cb975054c1..c29f0bcfcc 100644
--- a/cmd/evm/internal/t8ntool/execution.go
+++ b/cmd/evm/internal/t8ntool/execution.go
@@ -36,7 +36,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
- "github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
)
@@ -356,7 +356,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
}
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
- sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
+ config := dbconfig.HashDefaults
+ config.Preimages = true
+
+ sdb := state.NewDatabaseWithConfig(db, &config)
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
for addr, a := range accounts {
statedb.SetCode(addr, a.Code)
diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go
index b8e8b542b7..e9a408c357 100644
--- a/cmd/evm/runner.go
+++ b/cmd/evm/runner.go
@@ -39,7 +39,7 @@ import (
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/urfave/cli/v2"
)
@@ -148,10 +148,9 @@ func runCmd(ctx *cli.Context) error {
}
db := rawdb.NewMemoryDatabase()
- triedb := triedb.NewDatabase(db, &triedb.Config{
- Preimages: preimages,
- HashDB: hashdb.Defaults,
- })
+ config := dbconfig.HashDefaults
+ config.Preimages = preimages
+ triedb := triedb.NewDatabase(db, &config)
defer triedb.Close()
genesis := genesisConfig.MustCommit(db, triedb)
sdb := state.NewDatabaseWithNodeDB(db, triedb)
diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go
index 192c850868..85379a5a13 100644
--- a/cmd/geth/snapshot.go
+++ b/cmd/geth/snapshot.go
@@ -428,7 +428,7 @@ func traverseRawState(ctx *cli.Context) error {
log.Error("Failed to open iterator", "root", root, "err", err)
return err
}
- reader, err := triedb.Reader(root)
+ reader, err := triedb.NodeReader(root)
if err != nil {
log.Error("State is non-existent", "root", root)
return nil
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index b38f33b8dd..7c3145bebe 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -70,6 +70,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
"github.com/ethereum/go-ethereum/triedb/hashdb"
"github.com/ethereum/go-ethereum/triedb/pathdb"
@@ -2193,6 +2194,7 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
}
// MakeTrieDatabase constructs a trie database based on the configured scheme.
+// Don't forget to call db.Close afterwards to prevent memory leak.
func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool, isVerkle bool) *triedb.Database {
config := &triedb.Config{
Preimages: preimage,
@@ -2206,13 +2208,20 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
// Read-only mode is not implemented in hash mode,
// ignore the parameter silently. TODO(rjl493456442)
// please config it if read mode is implemented.
- config.HashDB = hashdb.Defaults
+ config.HashDB = &hashdb.Config{
+ CleanCacheSize: 16 * 1024 * 1024,
+ ChildResolver: trie.MerkleResolver,
+ }
return triedb.NewDatabase(disk, config)
}
+ config.PathDB = &pathdb.Config{
+ StateHistory: params.FullImmutabilityThreshold,
+ CleanCacheSize: pathdb.DefaultCleanSize,
+ DirtyCacheSize: pathdb.DefaultBufferSize,
+ TrieOpener: trie.NewMerkleOpener,
+ }
if readOnly {
- config.PathDB = pathdb.ReadOnly
- } else {
- config.PathDB = pathdb.Defaults
+ config.PathDB.ReadOnly = true
}
return triedb.NewDatabase(disk, config)
}
diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go
index 9b7f1797d8..1beffda622 100644
--- a/cmd/utils/history_test.go
+++ b/cmd/utils/history_test.go
@@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
var (
@@ -171,7 +172,7 @@ func TestHistoryImportAndExport(t *testing.T) {
db2.Close()
})
- genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults))
+ genesis.MustCommit(db2, triedb.NewDatabase(db, &dbconfig.HashDefaults))
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("unable to initialize chain: %v", err)
diff --git a/core/blockchain.go b/core/blockchain.go
index 9bd7fdcd95..bf4810be03 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -47,6 +47,7 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
"github.com/ethereum/go-ethereum/triedb/hashdb"
"github.com/ethereum/go-ethereum/triedb/pathdb"
@@ -151,6 +152,7 @@ func (c *CacheConfig) triedbConfig() *triedb.Config {
if c.StateScheme == rawdb.HashScheme {
config.HashDB = &hashdb.Config{
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
+ ChildResolver: trie.MerkleResolver,
}
}
if c.StateScheme == rawdb.PathScheme {
@@ -158,6 +160,7 @@ func (c *CacheConfig) triedbConfig() *triedb.Config {
StateHistory: c.StateHistory,
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024,
+ TrieOpener: trie.NewMerkleOpener,
}
}
return config
diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go
index b96ee12c99..8fc0a1ddbc 100644
--- a/core/blockchain_sethead_test.go
+++ b/core/blockchain_sethead_test.go
@@ -35,8 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
// rewindTest is a test case for chain rollback upon user request.
@@ -2033,13 +2032,13 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
}
// Reopen the trie database without persisting in-memory dirty nodes.
chain.triedb.Close()
- dbconfig := &triedb.Config{}
+ var dbconf triedb.Config
if scheme == rawdb.PathScheme {
- dbconfig.PathDB = pathdb.Defaults
+ dbconf = dbconfig.PathDefaults
} else {
- dbconfig.HashDB = hashdb.Defaults
+ dbconf = dbconfig.HashDefaults
}
- chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
+ chain.triedb = triedb.NewDatabase(chain.db, &dbconf)
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb)
// Force run a freeze cycle
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 733030fd1c..cf3d0374bc 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
)
@@ -362,7 +363,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
}
// Forcibly use hash-based state scheme for retaining all nodes in disk.
- triedb := triedb.NewDatabase(db, triedb.HashDefaults)
+ triedb := triedb.NewDatabase(db, &dbconfig.HashDefaults)
defer triedb.Close()
for i := 0; i < n; i++ {
@@ -407,7 +408,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
// then generate chain on top.
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
db := rawdb.NewMemoryDatabase()
- triedb := triedb.NewDatabase(db, triedb.HashDefaults)
+ triedb := triedb.NewDatabase(db, &dbconfig.HashDefaults)
defer triedb.Close()
_, err := genesis.Commit(db, triedb)
if err != nil {
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index b46b898afb..746cbf59c9 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
func TestGeneratePOSChain(t *testing.T) {
@@ -81,7 +82,7 @@ func TestGeneratePOSChain(t *testing.T) {
Storage: storage,
Code: common.Hex2Bytes("600154600354"),
}
- genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, triedb.HashDefaults))
+ genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, &dbconfig.HashDefaults))
genchain, genreceipts := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
gen.SetParentBeaconRoot(common.Hash{byte(i + 1)})
@@ -204,7 +205,7 @@ func ExampleGenerateChain() {
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
}
- genesis := gspec.MustCommit(genDb, triedb.NewDatabase(genDb, triedb.HashDefaults))
+ genesis := gspec.MustCommit(genDb, triedb.NewDatabase(genDb, &dbconfig.HashDefaults))
// This call generates a chain of 5 blocks. The function runs for
// each block and adds different features to gen based on the
diff --git a/core/genesis.go b/core/genesis.go
index 3f1fde8dfc..683dad741a 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -37,7 +37,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
)
@@ -117,16 +117,16 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
// If a genesis-time verkle trie is requested, create a trie config
// with the verkle trie enabled so that the tree can be initialized
// as such.
- var config *triedb.Config
+ var config triedb.Config
if isVerkle {
- config = &triedb.Config{
- PathDB: pathdb.Defaults,
- IsVerkle: true,
- }
+ config = dbconfig.PathDefaults
+ config.IsVerkle = true
+ } else {
+ config = dbconfig.HashDefaults
}
// Create an ephemeral in-memory database for computing hash,
// all the derived states will be discarded to not pollute disk.
- db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
+ db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &config)
statedb, err := state.New(types.EmptyRootHash, db, nil)
if err != nil {
return common.Hash{}, err
diff --git a/core/genesis_test.go b/core/genesis_test.go
index 61be0bd252..3db53815a7 100644
--- a/core/genesis_test.go
+++ b/core/genesis_test.go
@@ -32,14 +32,14 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
func TestInvalidCliqueConfig(t *testing.T) {
block := DefaultGoerliGenesisBlock()
block.ExtraData = []byte{}
db := rawdb.NewMemoryDatabase()
- if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil {
+ if _, err := block.Commit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults)); err == nil {
t.Fatal("Expected error on invalid clique config")
}
}
@@ -189,7 +189,7 @@ func TestGenesisHashes(t *testing.T) {
} {
// Test via MustCommit
db := rawdb.NewMemoryDatabase()
- if have := c.genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)).Hash(); have != c.want {
+ if have := c.genesis.MustCommit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults)).Hash(); have != c.want {
t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
}
// Test via ToBlock
@@ -207,7 +207,7 @@ func TestGenesis_Commit(t *testing.T) {
}
db := rawdb.NewMemoryDatabase()
- genesisBlock := genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
+ genesisBlock := genesis.MustCommit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults))
if genesis.Difficulty != nil {
t.Fatalf("assumption wrong")
@@ -259,9 +259,9 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
func newDbConfig(scheme string) *triedb.Config {
if scheme == rawdb.HashScheme {
- return triedb.HashDefaults
+ return &dbconfig.HashDefaults
}
- return &triedb.Config{PathDB: pathdb.Defaults}
+ return &dbconfig.PathDefaults
}
func TestVerkleGenesisCommit(t *testing.T) {
@@ -311,7 +311,10 @@ func TestVerkleGenesisCommit(t *testing.T) {
}
db := rawdb.NewMemoryDatabase()
- triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
+
+ config := dbconfig.PathDefaults
+ config.IsVerkle = true
+ triedb := triedb.NewDatabase(db, &config)
block := genesis.MustCommit(db, triedb)
if !bytes.Equal(block.Root().Bytes(), expected) {
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
diff --git a/core/headerchain_test.go b/core/headerchain_test.go
index 25d9bfffcb..e342287d6c 100644
--- a/core/headerchain_test.go
+++ b/core/headerchain_test.go
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
func verifyUnbrokenCanonchain(hc *HeaderChain) error {
@@ -73,7 +74,7 @@ func TestHeaderInsertion(t *testing.T) {
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
)
- gspec.Commit(db, triedb.NewDatabase(db, nil))
+ gspec.Commit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults))
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
if err != nil {
t.Fatal(err)
diff --git a/core/state/database.go b/core/state/database.go
index 7520923eef..7758d52590 100644
--- a/core/state/database.go
+++ b/core/state/database.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
const (
@@ -145,7 +146,7 @@ type Trie interface {
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
// historical state in memory, use the NewDatabaseWithConfig constructor.
func NewDatabase(db ethdb.Database) Database {
- return NewDatabaseWithConfig(db, nil)
+ return NewDatabaseWithConfig(db, &dbconfig.HashDefaults)
}
// NewDatabaseWithConfig creates a backing store for state. The returned database
diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go
index 59c580daca..740c81c060 100644
--- a/core/state/pruner/pruner.go
+++ b/core/state/pruner/pruner.go
@@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
const (
@@ -87,7 +88,7 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
return nil, errors.New("failed to load head block")
}
// Offline pruning is only supported in legacy hash based scheme.
- triedb := triedb.NewDatabase(db, triedb.HashDefaults)
+ triedb := triedb.NewDatabase(db, &dbconfig.HashDefaults)
snapconfig := snapshot.Config{
CacheSize: 256,
@@ -367,7 +368,7 @@ func RecoverPruning(datadir string, db ethdb.Database) error {
AsyncBuild: false,
}
// Offline pruning is only supported in legacy hash based scheme.
- triedb := triedb.NewDatabase(db, triedb.HashDefaults)
+ triedb := triedb.NewDatabase(db, &dbconfig.HashDefaults)
snaptree, err := snapshot.New(snapconfig, db, triedb, headBlock.Root())
if err != nil {
return err // The relevant snapshot(s) might not exist
@@ -410,7 +411,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
if genesis == nil {
return errors.New("missing genesis block")
}
- t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), triedb.NewDatabase(db, triedb.HashDefaults))
+ t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), triedb.NewDatabase(db, &dbconfig.HashDefaults))
if err != nil {
return err
}
@@ -434,7 +435,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
}
if acc.Root != types.EmptyRootHash {
id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root)
- storageTrie, err := trie.NewStateTrie(id, triedb.NewDatabase(db, triedb.HashDefaults))
+ storageTrie, err := trie.NewStateTrie(id, triedb.NewDatabase(db, &dbconfig.HashDefaults))
if err != nil {
return err
}
diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go
index 8de4b134d3..a3305f4f81 100644
--- a/core/state/snapshot/generate.go
+++ b/core/state/snapshot/generate.go
@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
var (
@@ -354,7 +355,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
var resolver trie.NodeResolver
if len(result.keys) > 0 {
mdb := rawdb.NewMemoryDatabase()
- tdb := triedb.NewDatabase(mdb, triedb.HashDefaults)
+ tdb := triedb.NewDatabase(mdb, &dbconfig.HashDefaults)
defer tdb.Close()
snapTrie := trie.NewEmpty(tdb)
for i, key := range result.keys {
diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go
index da93ebc875..25670e6665 100644
--- a/core/state/snapshot/generate_test.go
+++ b/core/state/snapshot/generate_test.go
@@ -31,8 +31,7 @@ import (
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
)
@@ -162,14 +161,14 @@ type testHelper struct {
}
func newHelper(scheme string) *testHelper {
- diskdb := rawdb.NewMemoryDatabase()
- config := &triedb.Config{}
+ var config triedb.Config
if scheme == rawdb.PathScheme {
- config.PathDB = &pathdb.Config{} // disable caching
+ config = dbconfig.PathDefaults
} else {
- config.HashDB = &hashdb.Config{} // disable caching
+ config = dbconfig.HashDefaults
}
- triedb := triedb.NewDatabase(diskdb, config)
+ diskdb := rawdb.NewMemoryDatabase()
+ triedb := triedb.NewDatabase(diskdb, &config)
accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb)
return &testHelper{
diskdb: diskdb,
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 9be610f962..2cea04b339 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
)
@@ -43,7 +43,9 @@ func newStateEnv() *stateEnv {
func TestDump(t *testing.T) {
db := rawdb.NewMemoryDatabase()
- tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
+ config := dbconfig.HashDefaults
+ config.Preimages = true
+ tdb := NewDatabaseWithConfig(db, &config)
sdb, _ := New(types.EmptyRootHash, tdb, nil)
s := &stateEnv{db: db, state: sdb}
@@ -100,7 +102,9 @@ func TestDump(t *testing.T) {
func TestIterativeDump(t *testing.T) {
db := rawdb.NewMemoryDatabase()
- tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
+ config := dbconfig.HashDefaults
+ config.Preimages = true
+ tdb := NewDatabaseWithConfig(db, &config)
sdb, _ := New(types.EmptyRootHash, tdb, nil)
s := &stateEnv{db: db, state: sdb}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index f90b30f399..07211b87f5 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -31,7 +31,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
"github.com/holiman/uint256"
)
@@ -130,7 +130,7 @@ type StateDB struct {
StorageDeleted int
// Testing hooks
- onCommit func(states *triestate.Set) // Hook invoked when commit is performed
+ onCommit func(states *state.Origin) // Hook invoked when commit is performed
}
// New creates a new state from a given trie.
@@ -1239,7 +1239,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
}
if root != origin {
start = time.Now()
- set := triestate.New(s.accountsOrigin, s.storagesOrigin)
+ set := state.NewOrigin(s.accountsOrigin, s.storagesOrigin)
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
return common.Hash{}, err
}
diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go
index b416bcf1f3..a91385cf46 100644
--- a/core/state/statedb_fuzz_test.go
+++ b/core/state/statedb_fuzz_test.go
@@ -35,9 +35,9 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
- "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
+ "github.com/ethereum/go-ethereum/triedb/state"
"github.com/holiman/uint256"
)
@@ -177,12 +177,12 @@ func (test *stateTest) run() bool {
roots []common.Hash
accountList []map[common.Address][]byte
storageList []map[common.Address]map[common.Hash][]byte
- onCommit = func(states *triestate.Set) {
+ onCommit = func(states *state.Origin) {
accountList = append(accountList, copySet(states.Accounts))
storageList = append(storageList, copy2DSet(states.Storages))
}
disk = rawdb.NewMemoryDatabase()
- tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
+ tdb = triedb.NewDatabase(disk, &dbconfig.PathDefaults)
sdb = NewDatabaseWithNodeDB(disk, tdb)
byzantium = rand.Intn(2) == 0
)
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 3649b0ac58..e78693e9fc 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -38,8 +38,7 @@ import (
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
)
@@ -49,7 +48,7 @@ func TestUpdateLeaks(t *testing.T) {
// Create an empty state database
var (
db = rawdb.NewMemoryDatabase()
- tdb = triedb.NewDatabase(db, nil)
+ tdb = triedb.NewDatabase(db, &dbconfig.HashDefaults)
)
state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil)
@@ -85,8 +84,8 @@ func TestIntermediateLeaks(t *testing.T) {
// Create two state databases, one transitioning to the final state, the other final from the beginning
transDb := rawdb.NewMemoryDatabase()
finalDb := rawdb.NewMemoryDatabase()
- transNdb := triedb.NewDatabase(transDb, nil)
- finalNdb := triedb.NewDatabase(finalDb, nil)
+ transNdb := triedb.NewDatabase(transDb, &dbconfig.HashDefaults)
+ finalNdb := triedb.NewDatabase(finalDb, &dbconfig.HashDefaults)
transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil)
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
@@ -803,14 +802,9 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
memDb = rawdb.NewMemoryDatabase()
)
if scheme == rawdb.PathScheme {
- tdb = triedb.NewDatabase(memDb, &triedb.Config{PathDB: &pathdb.Config{
- CleanCacheSize: 0,
- DirtyCacheSize: 0,
- }}) // disable caching
+ tdb = triedb.NewDatabase(memDb, &dbconfig.PathDefaults) // disable caching
} else {
- tdb = triedb.NewDatabase(memDb, &triedb.Config{HashDB: &hashdb.Config{
- CleanCacheSize: 0,
- }}) // disable caching
+ tdb = triedb.NewDatabase(memDb, &dbconfig.HashDefaults) // cache is disabled by default
}
db := NewDatabaseWithNodeDB(memDb, tdb)
@@ -1033,7 +1027,7 @@ func TestFlushOrderDataLoss(t *testing.T) {
// Create a state trie with many accounts and slots
var (
memdb = rawdb.NewMemoryDatabase()
- triedb = triedb.NewDatabase(memdb, nil)
+ triedb = triedb.NewDatabase(memdb, &dbconfig.HashDefaults)
statedb = NewDatabaseWithNodeDB(memdb, triedb)
state, _ = New(types.EmptyRootHash, statedb, nil)
)
@@ -1105,7 +1099,7 @@ func TestStateDBTransientStorage(t *testing.T) {
func TestResetObject(t *testing.T) {
var (
disk = rawdb.NewMemoryDatabase()
- tdb = triedb.NewDatabase(disk, nil)
+ tdb = triedb.NewDatabase(disk, &dbconfig.HashDefaults)
db = NewDatabaseWithNodeDB(disk, tdb)
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash)
state, _ = New(types.EmptyRootHash, db, snaps)
@@ -1139,7 +1133,7 @@ func TestResetObject(t *testing.T) {
func TestDeleteStorage(t *testing.T) {
var (
disk = rawdb.NewMemoryDatabase()
- tdb = triedb.NewDatabase(disk, nil)
+ tdb = triedb.NewDatabase(disk, &dbconfig.HashDefaults)
db = NewDatabaseWithNodeDB(disk, tdb)
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash)
state, _ = New(types.EmptyRootHash, db, snaps)
diff --git a/core/state/sync_test.go b/core/state/sync_test.go
index 052c166578..46e4a2cef5 100644
--- a/core/state/sync_test.go
+++ b/core/state/sync_test.go
@@ -28,8 +28,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
)
@@ -44,14 +43,16 @@ type testAccount struct {
// makeTestState create a sample test state to test node-wise reconstruction.
func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, common.Hash, []*testAccount) {
// Create an empty state
- config := &triedb.Config{Preimages: true}
+ var config triedb.Config
if scheme == rawdb.PathScheme {
- config.PathDB = pathdb.Defaults
+ config = dbconfig.PathDefaults
} else {
- config.HashDB = hashdb.Defaults
+ config = dbconfig.HashDefaults
}
+ config.Preimages = true
+
db := rawdb.NewMemoryDatabase()
- nodeDb := triedb.NewDatabase(db, config)
+ nodeDb := triedb.NewDatabase(db, &config)
sdb := NewDatabaseWithNodeDB(db, nodeDb)
state, _ := New(types.EmptyRootHash, sdb, nil)
@@ -90,7 +91,9 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c
func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root common.Hash, accounts []*testAccount) {
var config triedb.Config
if scheme == rawdb.PathScheme {
- config.PathDB = pathdb.Defaults
+ config = dbconfig.PathDefaults
+ } else {
+ config = dbconfig.HashDefaults
}
// Check root availability and state contents
state, err := New(root, NewDatabaseWithConfig(db, &config), nil)
@@ -115,11 +118,15 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com
// checkStateConsistency checks that all data of a state root is present.
func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) error {
- config := &triedb.Config{Preimages: true}
+ var config triedb.Config
if scheme == rawdb.PathScheme {
- config.PathDB = pathdb.Defaults
+ config = dbconfig.PathDefaults
+ } else {
+ config = dbconfig.HashDefaults
}
- state, err := New(root, NewDatabaseWithConfig(db, config), nil)
+ config.Preimages = true
+
+ state, err := New(root, NewDatabaseWithConfig(db, &config), nil)
if err != nil {
return err
}
@@ -131,8 +138,8 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e
// Tests that an empty state is not scheduled for syncing.
func TestEmptyStateSync(t *testing.T) {
- dbA := triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)
- dbB := triedb.NewDatabase(rawdb.NewMemoryDatabase(), &triedb.Config{PathDB: pathdb.Defaults})
+ dbA := triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults)
+ dbB := triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.PathDefaults)
sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbA.Scheme())
if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 {
@@ -206,7 +213,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s
for i := 0; i < len(codes); i++ {
codeElements = append(codeElements, stateElement{code: codes[i]})
}
- reader, err := ndb.Reader(srcRoot)
+ reader, err := ndb.NodeReader(srcRoot)
if err != nil {
t.Fatalf("state is not existent, %#x", srcRoot)
}
@@ -325,7 +332,7 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) {
for i := 0; i < len(codes); i++ {
codeElements = append(codeElements, stateElement{code: codes[i]})
}
- reader, err := ndb.Reader(srcRoot)
+ reader, err := ndb.NodeReader(srcRoot)
if err != nil {
t.Fatalf("state is not existent, %#x", srcRoot)
}
@@ -429,7 +436,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) {
for _, hash := range codes {
codeQueue[hash] = struct{}{}
}
- reader, err := ndb.Reader(srcRoot)
+ reader, err := ndb.NodeReader(srcRoot)
if err != nil {
t.Fatalf("state is not existent, %#x", srcRoot)
}
@@ -522,7 +529,7 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) {
for _, hash := range codes {
codeQueue[hash] = struct{}{}
}
- reader, err := ndb.Reader(srcRoot)
+ reader, err := ndb.NodeReader(srcRoot)
if err != nil {
t.Fatalf("state is not existent, %#x", srcRoot)
}
@@ -627,7 +634,7 @@ func testIncompleteStateSync(t *testing.T, scheme string) {
addedPaths []string
addedHashes []common.Hash
)
- reader, err := ndb.Reader(srcRoot)
+ reader, err := ndb.NodeReader(srcRoot)
if err != nil {
t.Fatalf("state is not available %x", srcRoot)
}
diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go
index a6949414f3..edb41e58e9 100644
--- a/core/types/hashing_test.go
+++ b/core/types/hashing_test.go
@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
func TestDeriveSha(t *testing.T) {
@@ -40,7 +41,7 @@ func TestDeriveSha(t *testing.T) {
t.Fatal(err)
}
for len(txs) < 1000 {
- exp := types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
+ exp := types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults)))
got := types.DeriveSha(txs, trie.NewStackTrie(nil))
if !bytes.Equal(got[:], exp[:]) {
t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
@@ -87,7 +88,7 @@ func BenchmarkDeriveSha200(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- exp = types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
+ exp = types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults)))
}
})
@@ -108,7 +109,7 @@ func TestFuzzDeriveSha(t *testing.T) {
rndSeed := mrand.Int()
for i := 0; i < 10; i++ {
seed := rndSeed + i
- exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
+ exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults)))
got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
if !bytes.Equal(got[:], exp[:]) {
printList(newDummy(seed))
@@ -136,7 +137,7 @@ func TestDerivableList(t *testing.T) {
},
}
for i, tc := range tcs[1:] {
- exp := types.DeriveSha(flatList(tc), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
+ exp := types.DeriveSha(flatList(tc), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults)))
got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
if !bytes.Equal(got[:], exp[:]) {
t.Fatalf("case %d: got %x exp %x", i, got, exp)
diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go
index 671e935beb..6d118422f7 100644
--- a/eth/api_debug_test.go
+++ b/eth/api_debug_test.go
@@ -29,7 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
"golang.org/x/exp/slices"
)
@@ -62,13 +62,15 @@ func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, st
func TestAccountRange(t *testing.T) {
t.Parallel()
+ config := dbconfig.HashDefaults
+ config.Preimages = true
+
var (
- statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &triedb.Config{Preimages: true})
+ statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &config)
sdb, _ = state.New(types.EmptyRootHash, statedb, nil)
addrs = [AccountRangeMaxResults * 2]common.Address{}
m = map[common.Address]bool{}
)
-
for i := range addrs {
hash := common.HexToHash(fmt.Sprintf("%x", i))
addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes())
@@ -158,9 +160,12 @@ func TestEmptyAccountRange(t *testing.T) {
func TestStorageRangeAt(t *testing.T) {
t.Parallel()
+ config := dbconfig.HashDefaults
+ config.Preimages = true
+
// Create a state where account 0x010000... has a few storage entries.
var (
- db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &triedb.Config{Preimages: true})
+ db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &config)
sdb, _ = state.New(types.EmptyRootHash, db, nil)
addr = common.Address{0x01}
keys = []common.Hash{ // hashes of Keys of storage
diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go
index 46f3febd8b..67cc80da92 100644
--- a/eth/downloader/testchain_test.go
+++ b/eth/downloader/testchain_test.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
// Test chain parameters.
@@ -44,7 +45,7 @@ var (
Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}},
BaseFee: big.NewInt(params.InitialBaseFee),
}
- testGenesis = testGspec.MustCommit(testDB, triedb.NewDatabase(testDB, triedb.HashDefaults))
+ testGenesis = testGspec.MustCommit(testDB, triedb.NewDatabase(testDB, &dbconfig.HashDefaults))
)
// The common prefix of all test chains:
diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go
index 48aaa584db..9fcff03626 100644
--- a/eth/filters/filter_test.go
+++ b/eth/filters/filter_test.go
@@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
func makeReceipt(addr common.Address) *types.Receipt {
@@ -86,7 +87,7 @@ func BenchmarkFilters(b *testing.B) {
// The test txs are not properly signed, can't simply create a chain
// and then import blocks. TODO(rjl493456442) try to get rid of the
// manual database writes.
- gspec.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
+ gspec.MustCommit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults))
for i, block := range chain {
rawdb.WriteBlock(db, block)
@@ -181,7 +182,7 @@ func TestFilters(t *testing.T) {
// Hack: GenerateChainWithGenesis creates a new db.
// Commit the genesis manually and use GenerateChain.
- _, err = gspec.Commit(db, triedb.NewDatabase(db, nil))
+ _, err = gspec.Commit(db, triedb.NewDatabase(db, &dbconfig.HashDefaults))
if err != nil {
t.Fatal(err)
}
diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go
index 1d2e02cde6..0995b5d1b6 100644
--- a/eth/gasprice/gasprice_test.go
+++ b/eth/gasprice/gasprice_test.go
@@ -166,7 +166,10 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
b.AddTx(types.MustSignNewTx(key, signer, txdata))
})
// Construct testing chain
- chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil)
+ chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), &core.CacheConfig{
+ TrieCleanNoPrefetch: true,
+ StateScheme: rawdb.HashScheme,
+ }, gspec, nil, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("Failed to create local chain, %v", err)
}
diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go
index cea83aa2bc..cd855b3b14 100644
--- a/eth/protocols/snap/sync_test.go
+++ b/eth/protocols/snap/sync_test.go
@@ -32,13 +32,13 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
- "github.com/ethereum/go-ethereum/trie/testutil"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
"golang.org/x/exp/slices"
@@ -1816,8 +1816,8 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c
break
}
for j := 0; j < slots/3; j++ {
- key := append([]byte{byte(n)}, testutil.RandBytes(31)...)
- val, _ := rlp.EncodeToBytes(testutil.RandBytes(32))
+ key := append([]byte{byte(n)}, testrand.Bytes(31)...)
+ val, _ := rlp.EncodeToBytes(testrand.Bytes(32))
elem := &kv{key, val}
tr.MustUpdate(elem.k, elem.v)
@@ -1970,7 +1970,7 @@ func TestSlotEstimation(t *testing.T) {
func newDbConfig(scheme string) *triedb.Config {
if scheme == rawdb.HashScheme {
- return &triedb.Config{}
+ return &dbconfig.HashDefaults
}
- return &triedb.Config{PathDB: pathdb.Defaults}
+ return &dbconfig.PathDefaults
}
diff --git a/eth/state_accessor.go b/eth/state_accessor.go
index 526361a2b8..1d618d733d 100644
--- a/eth/state_accessor.go
+++ b/eth/state_accessor.go
@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
// noopReleaser is returned in case there is no operation expected
@@ -68,7 +69,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
// the internal junks created by tracing will be persisted into the disk.
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
// please re-enable it for better performance.
- database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults)
+ database = state.NewDatabaseWithConfig(eth.chainDb, &dbconfig.HashDefaults)
if statedb, err = state.New(block.Root(), database, nil); err == nil {
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
return statedb, noopReleaser, nil
@@ -85,7 +86,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
// the internal junks created by tracing will be persisted into the disk.
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
// please re-enable it for better performance.
- tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
+ tdb = triedb.NewDatabase(eth.chainDb, &dbconfig.HashDefaults)
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb)
// If we didn't check the live database, do check state over ephemeral database,
diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go
index d8e4b9a4ef..270d1d02ba 100644
--- a/eth/tracers/api_test.go
+++ b/eth/tracers/api_test.go
@@ -78,6 +78,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
TrieDirtyLimit: 256,
TrieTimeLimit: 5 * time.Minute,
SnapshotLimit: 0,
+ StateScheme: rawdb.HashScheme,
TrieDirtyDisabled: true, // Archive mode
}
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil)
diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go
index 3f69f86144..59b5bdb4c3 100644
--- a/internal/ethapi/api_test.go
+++ b/internal/ethapi/api_test.go
@@ -441,6 +441,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
TrieTimeLimit: 5 * time.Minute,
SnapshotLimit: 0,
TrieDirtyDisabled: true, // Archive mode
+ StateScheme: rawdb.HashScheme,
}
)
accman, acc := newTestAccountManager(t)
diff --git a/trie/testutil/utils.go b/internal/testrand/rand.go
similarity index 61%
rename from trie/testutil/utils.go
rename to internal/testrand/rand.go
index a75d0431b0..690993de05 100644
--- a/trie/testutil/utils.go
+++ b/internal/testrand/rand.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package testutil
+package testrand
import (
crand "crypto/rand"
@@ -22,11 +22,9 @@ import (
mrand "math/rand"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/trie/trienode"
)
-// Prng is a pseudo random number generator seeded by strong randomness.
+// prng is a pseudo random number generator seeded by strong randomness.
// The randomness is printed on startup in order to make failures reproducible.
var prng = initRand()
@@ -37,25 +35,19 @@ func initRand() *mrand.Rand {
return rnd
}
-// RandBytes generates a random byte slice with specified length.
-func RandBytes(n int) []byte {
+// Bytes generates a random byte slice with specified length.
+func Bytes(n int) []byte {
r := make([]byte, n)
prng.Read(r)
return r
}
-// RandomHash generates a random blob of data and returns it as a hash.
-func RandomHash() common.Hash {
- return common.BytesToHash(RandBytes(common.HashLength))
+// Hash generates a random hash.
+func Hash() common.Hash {
+ return common.BytesToHash(Bytes(common.HashLength))
}
-// RandomAddress generates a random blob of data and returns it as an address.
-func RandomAddress() common.Address {
- return common.BytesToAddress(RandBytes(common.AddressLength))
-}
-
-// RandomNode generates a random node.
-func RandomNode() *trienode.Node {
- val := RandBytes(100)
- return trienode.New(crypto.Keccak256Hash(val), val)
+// Address generates a random address.
+func Address() common.Address {
+ return common.BytesToAddress(Bytes(common.AddressLength))
}
diff --git a/miner/miner_test.go b/miner/miner_test.go
index 7c39564240..9c70710939 100644
--- a/miner/miner_test.go
+++ b/miner/miner_test.go
@@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
type mockBackend struct {
@@ -143,7 +144,7 @@ func createMiner(t *testing.T) *Miner {
}
// Create chainConfig
chainDB := rawdb.NewMemoryDatabase()
- triedb := triedb.NewDatabase(chainDB, nil)
+ triedb := triedb.NewDatabase(chainDB, &dbconfig.HashDefaults)
genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345"))
chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis)
if err != nil {
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 53d733f1c4..bfc4b8df63 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -40,8 +40,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
)
// A BlockTest checks handling of entire blocks.
@@ -116,19 +115,19 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, po
}
// import pre accounts & construct test genesis block & state root
var (
- db = rawdb.NewMemoryDatabase()
- tconf = &triedb.Config{
- Preimages: true,
- }
+ db = rawdb.NewMemoryDatabase()
+ dbconf triedb.Config
)
if scheme == rawdb.PathScheme {
- tconf.PathDB = pathdb.Defaults
+ dbconf = dbconfig.PathDefaults
} else {
- tconf.HashDB = hashdb.Defaults
+ dbconf = dbconfig.HashDefaults
}
+ dbconf.Preimages = true
+
// Commit genesis state
gspec := t.genesis(config)
- triedb := triedb.NewDatabase(db, tconf)
+ triedb := triedb.NewDatabase(db, &dbconf)
gblock, err := gspec.Commit(db, triedb)
if err != nil {
return err
diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go
index dcafebb265..b8c6f86b1a 100644
--- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go
+++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"golang.org/x/exp/slices"
)
@@ -57,7 +58,7 @@ func (f *fuzzer) readInt() uint64 {
}
func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) {
- trie := trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))
+ trie := trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), &dbconfig.HashDefaults))
vals := make(map[string]*kv)
size := f.readInt()
// Fill it with some fluff
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index c916d26d41..4f8b71369b 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -40,8 +40,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/triedb"
- "github.com/ethereum/go-ethereum/triedb/hashdb"
- "github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/dbconfig"
"github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
)
@@ -444,13 +443,15 @@ type StateTestState struct {
// MakePreState creates a state containing the given allocation.
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bool, scheme string) StateTestState {
- tconf := &triedb.Config{Preimages: true}
+ var dbconf triedb.Config
if scheme == rawdb.HashScheme {
- tconf.HashDB = hashdb.Defaults
+ dbconf = dbconfig.HashDefaults
} else {
- tconf.PathDB = pathdb.Defaults
+ dbconf = dbconfig.PathDefaults
}
- triedb := triedb.NewDatabase(db, tconf)
+ dbconf.Preimages = true
+
+ triedb := triedb.NewDatabase(db, &dbconf)
sdb := state.NewDatabaseWithNodeDB(db, triedb)
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
for addr, a := range accounts {
diff --git a/trie/committer.go b/trie/committer.go
index 4e2f7b8bd6..3b252bf7bb 100644
--- a/trie/committer.go
+++ b/trie/committer.go
@@ -154,12 +154,8 @@ func (c *committer) store(path []byte, n node) node {
return hash
}
-// MerkleResolver the children resolver in merkle-patricia-tree.
-type MerkleResolver struct{}
-
-// ForEach implements childResolver, decodes the provided node and
-// traverses the children inside.
-func (resolver MerkleResolver) ForEach(node []byte, onChild func(common.Hash)) {
+// MerkleResolver decodes the provided node and traverses the children inside.
+func MerkleResolver(node []byte, onChild func(common.Hash)) {
forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild)
}
diff --git a/trie/database_test.go b/trie/database_test.go
index aed508b368..837c209fdb 100644
--- a/trie/database_test.go
+++ b/trie/database_test.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/triedb/database"
)
-// testReader implements database.Reader interface, providing function to
+// testReader implements database.NodeReader interface, providing function to
// access trie nodes.
type testReader struct {
db ethdb.Database
@@ -33,7 +33,7 @@ type testReader struct {
nodes []*trienode.MergedNodeSet // sorted from new to old
}
-// Node implements database.Reader interface, retrieving trie node with
+// Node implements database.NodeReader interface, retrieving trie node with
// all available cached layers.
func (r *testReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
// Check the node presence with the cached layer, from latest to oldest.
@@ -73,7 +73,7 @@ func newTestDatabase(diskdb ethdb.Database, scheme string) *testDb {
}
}
-func (db *testDb) Reader(stateRoot common.Hash) (database.Reader, error) {
+func (db *testDb) NodeReader(stateRoot common.Hash) (database.NodeReader, error) {
nodes, _ := db.dirties(stateRoot, true)
return &testReader{db: db.disk, scheme: db.scheme, nodes: nodes}, nil
}
diff --git a/trie/iterator_test.go b/trie/iterator_test.go
index 41e83f6cb6..cced13a68a 100644
--- a/trie/iterator_test.go
+++ b/trie/iterator_test.go
@@ -146,7 +146,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) {
}
}
// Cross check the hashes and the database itself
- reader, err := nodeDb.Reader(trie.Hash())
+ reader, err := nodeDb.NodeReader(trie.Hash())
if err != nil {
t.Fatalf("state is not available %x", trie.Hash())
}
diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go
index 3a0e1cb260..203ebd99a9 100644
--- a/trie/stacktrie_test.go
+++ b/trie/stacktrie_test.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/trie/testutil"
+ "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/stretchr/testify/assert"
"golang.org/x/exp/slices"
)
@@ -431,12 +431,12 @@ func TestPartialStackTrie(t *testing.T) {
for i := 0; i < n; i++ {
var val []byte
if rand.Intn(3) == 0 {
- val = testutil.RandBytes(3)
+ val = testrand.Bytes(3)
} else {
- val = testutil.RandBytes(32)
+ val = testrand.Bytes(32)
}
entries = append(entries, &kv{
- k: testutil.RandBytes(32),
+ k: testrand.Bytes(32),
v: val,
})
}
diff --git a/trie/sync_test.go b/trie/sync_test.go
index 7bc68c041f..e0a31fca6f 100644
--- a/trie/sync_test.go
+++ b/trie/sync_test.go
@@ -182,7 +182,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) {
syncPath: NewSyncPath([]byte(paths[i])),
})
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -257,7 +257,7 @@ func testIterativeDelayedSync(t *testing.T, scheme string) {
syncPath: NewSyncPath([]byte(paths[i])),
})
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -326,7 +326,7 @@ func testIterativeRandomSync(t *testing.T, count int, scheme string) {
syncPath: NewSyncPath([]byte(paths[i])),
}
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -393,7 +393,7 @@ func testIterativeRandomDelayedSync(t *testing.T, scheme string) {
syncPath: NewSyncPath([]byte(path)),
}
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -465,7 +465,7 @@ func testDuplicateAvoidanceSync(t *testing.T, scheme string) {
syncPath: NewSyncPath([]byte(paths[i])),
})
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -541,7 +541,7 @@ func testIncompleteSync(t *testing.T, scheme string) {
syncPath: NewSyncPath([]byte(paths[i])),
})
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -633,7 +633,7 @@ func testSyncOrdering(t *testing.T, scheme string) {
})
reqs = append(reqs, NewSyncPath([]byte(paths[i])))
}
- reader, err := srcDb.Reader(srcTrie.Hash())
+ reader, err := srcDb.NodeReader(srcTrie.Hash())
if err != nil {
t.Fatalf("State is not available %x", srcTrie.Hash())
}
@@ -703,7 +703,7 @@ func syncWithHookWriter(t *testing.T, root common.Hash, db ethdb.Database, srcDb
syncPath: NewSyncPath([]byte(paths[i])),
})
}
- reader, err := srcDb.Reader(root)
+ reader, err := srcDb.NodeReader(root)
if err != nil {
t.Fatalf("State is not available %x", root)
}
diff --git a/trie/trie.go b/trie/trie.go
index 12764e18d1..f61bc85909 100644
--- a/trie/trie.go
+++ b/trie/trie.go
@@ -80,7 +80,7 @@ func (t *Trie) Copy() *Trie {
// zero hash or the sha3 hash of an empty string, then trie is initially
// empty, otherwise, the root node must be present in database or returns
// a MissingNodeError if not.
-func New(id *ID, db database.Database) (*Trie, error) {
+func New(id *ID, db database.NodeDatabase) (*Trie, error) {
reader, err := newTrieReader(id.StateRoot, id.Owner, db)
if err != nil {
return nil, err
diff --git a/trie/trie_reader.go b/trie/trie_reader.go
index 42bc4316fe..993e85d997 100644
--- a/trie/trie_reader.go
+++ b/trie/trie_reader.go
@@ -20,27 +20,27 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/triedb/database"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
// trieReader is a wrapper of the underlying node reader. It's not safe
// for concurrent usage.
type trieReader struct {
owner common.Hash
- reader database.Reader
+ reader database.NodeReader
banned map[string]struct{} // Marker to prevent node from being accessed, for tests
}
// newTrieReader initializes the trie reader with the given node reader.
-func newTrieReader(stateRoot, owner common.Hash, db database.Database) (*trieReader, error) {
+func newTrieReader(stateRoot, owner common.Hash, db database.NodeDatabase) (*trieReader, error) {
if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash {
if stateRoot == (common.Hash{}) {
log.Error("Zero state root hash!")
}
return &trieReader{owner: owner}, nil
}
- reader, err := db.Reader(stateRoot)
+ reader, err := db.NodeReader(stateRoot)
if err != nil {
return nil, &MissingNodeError{Owner: owner, NodeHash: stateRoot, err: err}
}
@@ -73,22 +73,22 @@ func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) {
return blob, nil
}
-// MerkleLoader implements triestate.TrieLoader for constructing tries.
-type MerkleLoader struct {
- db database.Database
+// MerkleOpener implements state.TrieOpener for constructing tries.
+type MerkleOpener struct {
+ db database.NodeDatabase
}
-// NewMerkleLoader creates the merkle trie loader.
-func NewMerkleLoader(db database.Database) *MerkleLoader {
- return &MerkleLoader{db: db}
+// NewMerkleOpener creates the merkle trie opener.
+func NewMerkleOpener(db database.NodeDatabase) state.TrieOpener {
+ return &MerkleOpener{db: db}
}
// OpenTrie opens the main account trie.
-func (l *MerkleLoader) OpenTrie(root common.Hash) (triestate.Trie, error) {
+func (l *MerkleOpener) OpenTrie(root common.Hash) (state.Trie, error) {
return New(TrieID(root), l.db)
}
// OpenStorageTrie opens the storage trie of an account.
-func (l *MerkleLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) {
+func (l *MerkleOpener) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (state.Trie, error) {
return New(StorageTrieID(stateRoot, addrHash, root), l.db)
}
diff --git a/trie/verkle.go b/trie/verkle.go
index 01d813d9ec..239e4e5e36 100644
--- a/trie/verkle.go
+++ b/trie/verkle.go
@@ -45,7 +45,7 @@ type VerkleTrie struct {
}
// NewVerkleTrie constructs a verkle tree based on the specified root hash.
-func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCache) (*VerkleTrie, error) {
+func NewVerkleTrie(root common.Hash, db database.NodeDatabase, cache *utils.PointCache) (*VerkleTrie, error) {
reader, err := newTrieReader(root, common.Hash{}, db)
if err != nil {
return nil, err
diff --git a/triedb/config.go b/triedb/config.go
new file mode 100644
index 0000000000..ea664e8923
--- /dev/null
+++ b/triedb/config.go
@@ -0,0 +1,61 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package triedb
+
+import (
+ "errors"
+
+ "github.com/ethereum/go-ethereum/triedb/hashdb"
+ "github.com/ethereum/go-ethereum/triedb/pathdb"
+)
+
+// Config defines all options for configuring database.
+type Config struct {
+ Preimages bool // Flag whether the preimage of node key is recorded
+ IsVerkle bool // Flag whether the db is holding a verkle tree
+ HashDB *hashdb.Config // Configs for hash-based scheme
+ PathDB *pathdb.Config // Configs for experimental path-based scheme
+}
+
+// sanitize validates the provided config.
+func (config *Config) sanitize() error {
+ if config == nil {
+ return errors.New("config is nil")
+ }
+ if config.HashDB != nil && config.PathDB != nil {
+ return errors.New("both 'hash' and 'path' mode are configured")
+ }
+ if config.HashDB == nil && config.PathDB == nil {
+ return errors.New("neither 'hash' nor 'path' mode is configured")
+ }
+ return nil
+}
+
+// Copy returns a deep copied config object.
+func (config *Config) Copy() *Config {
+ cpy := &Config{
+ Preimages: config.Preimages,
+ IsVerkle: config.IsVerkle,
+ }
+ if config.HashDB != nil {
+ cpy.HashDB = config.HashDB.Copy()
+ }
+ if config.PathDB != nil {
+ cpy.PathDB = config.PathDB.Copy()
+ }
+ return cpy
+}
diff --git a/triedb/database.go b/triedb/database.go
index 939a21f147..f53ef6d9cb 100644
--- a/triedb/database.go
+++ b/triedb/database.go
@@ -22,29 +22,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/triedb/database"
"github.com/ethereum/go-ethereum/triedb/hashdb"
"github.com/ethereum/go-ethereum/triedb/pathdb"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
-// Config defines all necessary options for database.
-type Config struct {
- Preimages bool // Flag whether the preimage of node key is recorded
- IsVerkle bool // Flag whether the db is holding a verkle tree
- HashDB *hashdb.Config // Configs for hash-based scheme
- PathDB *pathdb.Config // Configs for experimental path-based scheme
-}
-
-// HashDefaults represents a config for using hash-based scheme with
-// default settings.
-var HashDefaults = &Config{
- Preimages: false,
- HashDB: hashdb.Defaults,
-}
-
// backend defines the methods needed to access/update trie nodes in different
// state scheme.
type backend interface {
@@ -62,13 +46,17 @@ type backend interface {
// and dirty disk layer nodes, so both are merged into the second return.
Size() (common.StorageSize, common.StorageSize)
+ // NodeReader returns a node reader associated with the specific state.
+ // An error will be returned if the specified state is not available.
+ NodeReader(root common.Hash) (database.NodeReader, error)
+
// Update performs a state transition by committing dirty nodes contained
// in the given set in order to update state from the specified parent to
// the specified root.
//
// The passed in maps(nodes, states) will be retained to avoid copying
// everything. Therefore, these maps must not be changed afterwards.
- Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error
+ Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *state.Origin) error
// Commit writes all relevant trie nodes belonging to the specified state
// to disk. Report specifies whether logs will be displayed in info level.
@@ -91,9 +79,8 @@ type Database struct {
// NewDatabase initializes the trie database with default settings, note
// the legacy hash-based scheme is used by default.
func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
- // Sanitize the config and use the default one if it's not specified.
- if config == nil {
- config = HashDefaults
+ if err := config.sanitize(); err != nil {
+ log.Crit("Database config is invalid", "error", err)
}
var preimages *preimageStore
if config.Preimages {
@@ -104,34 +91,18 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
diskdb: diskdb,
preimages: preimages,
}
- if config.HashDB != nil && config.PathDB != nil {
- log.Crit("Both 'hash' and 'path' mode are configured")
- }
if config.PathDB != nil {
db.backend = pathdb.New(diskdb, config.PathDB)
} else {
- var resolver hashdb.ChildResolver
- if config.IsVerkle {
- // TODO define verkle resolver
- log.Crit("Verkle node resolver is not defined")
- } else {
- resolver = trie.MerkleResolver{}
- }
- db.backend = hashdb.New(diskdb, config.HashDB, resolver)
+ db.backend = hashdb.New(diskdb, config.HashDB)
}
return db
}
-// Reader returns a reader for accessing all trie nodes with provided state root.
-// An error will be returned if the requested state is not available.
-func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) {
- switch b := db.backend.(type) {
- case *hashdb.Database:
- return b.Reader(blockRoot)
- case *pathdb.Database:
- return b.Reader(blockRoot)
- }
- return nil, errors.New("unknown backend")
+// NodeReader returns a reader for accessing all trie nodes with provided state
+// root. An error will be returned if the requested state is not available.
+func (db *Database) NodeReader(blockRoot common.Hash) (database.NodeReader, error) {
+ return db.backend.NodeReader(blockRoot)
}
// Update performs a state transition by committing dirty nodes contained in the
@@ -141,7 +112,7 @@ func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) {
//
// The passed in maps(nodes, states) will be retained to avoid copying everything.
// Therefore, these maps must not be changed afterwards.
-func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
+func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *state.Origin) error {
if db.preimages != nil {
db.preimages.commit(false)
}
@@ -265,14 +236,7 @@ func (db *Database) Recover(target common.Hash) error {
if !ok {
return errors.New("not supported")
}
- var loader triestate.TrieLoader
- if db.config.IsVerkle {
- // TODO define verkle loader
- log.Crit("Verkle loader is not defined")
- } else {
- loader = trie.NewMerkleLoader(db)
- }
- return pdb.Recover(target, loader)
+ return pdb.Recover(target)
}
// Recoverable returns the indicator if the specified state is enabled to be
diff --git a/triedb/database/database.go b/triedb/database/database.go
index 18a8f454e2..f1a7e6523e 100644
--- a/triedb/database/database.go
+++ b/triedb/database/database.go
@@ -16,18 +16,23 @@
package database
-import (
- "github.com/ethereum/go-ethereum/common"
-)
+import "github.com/ethereum/go-ethereum/common"
-// Reader wraps the Node method of a backing trie reader.
-type Reader interface {
+// NodeReader wraps the Node method of a backing trie reader.
+type NodeReader interface {
// Node retrieves the trie node blob with the provided trie identifier,
// node path and the corresponding node hash. No error will be returned
// if the node is not found.
Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)
}
+// NodeDatabase warps the methods of a backing trie store.
+type NodeDatabase interface {
+ // NodeReader returns a node reader associated with the specific state.
+ // An error will be returned if the specified state is not available.
+ NodeReader(stateRoot common.Hash) (NodeReader, error)
+}
+
// PreimageStore wraps the methods of a backing store for reading and writing
// trie node preimages.
type PreimageStore interface {
@@ -41,8 +46,5 @@ type PreimageStore interface {
// Database wraps the methods of a backing trie store.
type Database interface {
PreimageStore
-
- // Reader returns a node reader associated with the specific state.
- // An error will be returned if the specified state is not available.
- Reader(stateRoot common.Hash) (Reader, error)
+ NodeDatabase
}
diff --git a/triedb/dbconfig/config.go b/triedb/dbconfig/config.go
new file mode 100644
index 0000000000..13e5bae8f5
--- /dev/null
+++ b/triedb/dbconfig/config.go
@@ -0,0 +1,62 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package dbconfig
+
+import (
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/trie"
+ "github.com/ethereum/go-ethereum/triedb"
+ "github.com/ethereum/go-ethereum/triedb/hashdb"
+ "github.com/ethereum/go-ethereum/triedb/pathdb"
+)
+
+// HashDefaults represents a configuration for using a hash-based scheme with
+// default settings. The default configuration is assumed immutable, so please
+// deep-copy the configuration if any mutation is expected.
+var HashDefaults = triedb.Config{
+ Preimages: false,
+ IsVerkle: false,
+ HashDB: &hashdb.Config{
+ // Explicitly set clean cache size to zero as default to avoid
+ // creating fastcache, otherwise database must be closed when
+ // it's no longer needed to prevent memory leak.
+ CleanCacheSize: 0,
+
+ // Merkle trie resolver is used as the default node resolver.
+ ChildResolver: trie.MerkleResolver,
+ },
+}
+
+// PathDefaults represents a configuration for using a path-based scheme with
+// default settings. The default configuration is assumed immutable, so please
+// deep-copy the configuration if any mutation is expected.
+var PathDefaults = triedb.Config{
+ Preimages: false,
+ IsVerkle: false,
+ PathDB: &pathdb.Config{
+ StateHistory: params.FullImmutabilityThreshold,
+
+ // Explicitly set clean cache size to zero as default to avoid
+ // creating fastcache, otherwise database must be closed when
+ // it's no longer needed to prevent memory leak.
+ CleanCacheSize: 0,
+ DirtyCacheSize: pathdb.DefaultBufferSize,
+
+ // Merkle trie loader is used as the default trie loader.
+ TrieOpener: trie.NewMerkleOpener,
+ },
+}
diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go
index e45ccdba32..f437159818 100644
--- a/triedb/hashdb/database.go
+++ b/triedb/hashdb/database.go
@@ -32,7 +32,8 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/database"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
var (
@@ -59,32 +60,42 @@ var (
memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil)
)
-// ChildResolver defines the required method to decode the provided
-// trie node and iterate the children on top.
-type ChildResolver interface {
- ForEach(node []byte, onChild func(common.Hash))
-}
-
// Config contains the settings for database.
type Config struct {
- CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
+ // CleanCacheSize specifies the maximum memory allowance (in bytes)
+ // for caching clean nodes.
+ CleanCacheSize int
+
+ // ChildResolver defines the method to decode the provided trie node
+ // and iterate the hash children on top.
+ ChildResolver func(node []byte, onChild func(common.Hash))
}
-// Defaults is the default setting for database if it's not specified.
-// Notably, clean cache is disabled explicitly,
-var Defaults = &Config{
- // Explicitly set clean cache size to 0 to avoid creating fastcache,
- // otherwise database must be closed when it's no longer needed to
- // prevent memory leak.
- CleanCacheSize: 0,
+// sanitize validates the provided config.
+func (config *Config) sanitize() error {
+ if config == nil {
+ return errors.New("hashdb config is nil")
+ }
+ if config.ChildResolver == nil {
+ return errors.New("node resolver is not configured")
+ }
+ return nil
+}
+
+// Copy returns a deep copied config object.
+func (config *Config) Copy() *Config {
+ return &Config{
+ CleanCacheSize: config.CleanCacheSize,
+ ChildResolver: config.ChildResolver,
+ }
}
// Database is an intermediate write layer between the trie data structures and
// the disk database. The aim is to accumulate trie writes in-memory and only
// periodically flush a couple tries to disk, garbage collecting the remainder.
type Database struct {
- diskdb ethdb.Database // Persistent storage for matured trie nodes
- resolver ChildResolver // The handler to resolve children of nodes
+ diskdb ethdb.Database // Persistent storage for matured trie nodes
+ config *Config // configuration used in hash db
cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs
dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes
@@ -123,27 +134,27 @@ var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size())
// forChildren invokes the callback for all the tracked children of this node,
// both the implicit ones from inside the node as well as the explicit ones
// from outside the node.
-func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash common.Hash)) {
+func (n *cachedNode) forChildren(resolver func(node []byte, onChild func(common.Hash)), onChild func(hash common.Hash)) {
for child := range n.external {
onChild(child)
}
- resolver.ForEach(n.node, onChild)
+ resolver(n.node, onChild)
}
// New initializes the hash-based node database.
-func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Database {
- if config == nil {
- config = Defaults
+func New(diskdb ethdb.Database, config *Config) *Database {
+ if err := config.sanitize(); err != nil {
+ log.Crit("Hash database config is invalid", "error", err)
}
var cleans *fastcache.Cache
if config.CleanCacheSize > 0 {
cleans = fastcache.New(config.CleanCacheSize)
}
return &Database{
- diskdb: diskdb,
- resolver: resolver,
- cleans: cleans,
- dirties: make(map[common.Hash]*cachedNode),
+ diskdb: diskdb,
+ config: config,
+ cleans: cleans,
+ dirties: make(map[common.Hash]*cachedNode),
}
}
@@ -162,7 +173,7 @@ func (db *Database) insert(hash common.Hash, node []byte) {
node: node,
flushPrev: db.newest,
}
- entry.forChildren(db.resolver, func(child common.Hash) {
+ entry.forChildren(db.config.ChildResolver, func(child common.Hash) {
if c := db.dirties[child]; c != nil {
c.parents++
}
@@ -315,7 +326,7 @@ func (db *Database) dereference(hash common.Hash) {
db.dirties[node.flushNext].flushPrev = node.flushPrev
}
// Dereference all children and delete the node
- node.forChildren(db.resolver, func(child common.Hash) {
+ node.forChildren(db.config.ChildResolver, func(child common.Hash) {
db.dereference(child)
})
delete(db.dirties, hash)
@@ -464,7 +475,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane
var err error
// Dereference all children and delete the node
- node.forChildren(db.resolver, func(child common.Hash) {
+ node.forChildren(db.config.ChildResolver, func(child common.Hash) {
if err == nil {
err = db.commit(child, batch, uncacher)
}
@@ -548,7 +559,7 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {
// Update inserts the dirty nodes in provided nodeset into database and link the
// account trie with multiple storage tries if necessary.
-func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
+func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *state.Origin) error {
// Ensure the parent state is present and signal a warning if not.
if parent != types.EmptyRootHash {
if blob, _ := db.node(parent); len(blob) == 0 {
@@ -629,9 +640,9 @@ func (db *Database) Scheme() string {
return rawdb.HashScheme
}
-// Reader retrieves a node reader belonging to the given state root.
+// NodeReader retrieves a node reader belonging to the given state root.
// An error will be returned if the requested state is not available.
-func (db *Database) Reader(root common.Hash) (*reader, error) {
+func (db *Database) NodeReader(root common.Hash) (database.NodeReader, error) {
if _, err := db.node(root); err != nil {
return nil, fmt.Errorf("state %#x is not available, %v", root, err)
}
diff --git a/triedb/pathdb/config.go b/triedb/pathdb/config.go
new file mode 100644
index 0000000000..dc4e811f01
--- /dev/null
+++ b/triedb/pathdb/config.go
@@ -0,0 +1,63 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see
+
+package pathdb
+
+import (
+ "errors"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/triedb/database"
+ "github.com/ethereum/go-ethereum/triedb/state"
+)
+
+// Config contains the settings for database.
+type Config struct {
+ StateHistory uint64 // Number of recent blocks to maintain state history for
+ CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
+ DirtyCacheSize int // Maximum memory allowance (in bytes) for caching dirty nodes
+ ReadOnly bool // Flag whether the database is opened in read only mode.
+ TrieOpener func(db database.NodeDatabase) state.TrieOpener // Function to create trie loader for trie state transition
+}
+
+// sanitize checks the provided user configurations and changes anything that's
+// unreasonable or unworkable.
+func (c *Config) sanitize() (*Config, error) {
+ if c == nil {
+ return nil, errors.New("pathdb config is nil")
+ }
+ if c.TrieOpener == nil {
+ return nil, errors.New("trie opener is not configured")
+ }
+ conf := *c
+ if conf.DirtyCacheSize > maxBufferSize {
+ log.Warn("Sanitizing invalid node buffer size", "provided", common.StorageSize(conf.DirtyCacheSize), "updated", common.StorageSize(maxBufferSize))
+ conf.DirtyCacheSize = maxBufferSize
+ }
+ return &conf, nil
+}
+
+// Copy returns a deep copied config object.
+func (c *Config) Copy() *Config {
+ return &Config{
+ StateHistory: c.StateHistory,
+ CleanCacheSize: c.CleanCacheSize,
+ DirtyCacheSize: c.DirtyCacheSize,
+ ReadOnly: c.ReadOnly,
+ TrieOpener: c.TrieOpener,
+ }
+}
diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go
index b1e01abac4..c3d1b7e710 100644
--- a/triedb/pathdb/database.go
+++ b/triedb/pathdb/database.go
@@ -28,17 +28,14 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/database"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
const (
- // maxDiffLayers is the maximum diff layers allowed in the layer tree.
- maxDiffLayers = 128
-
- // defaultCleanSize is the default memory allowance of clean cache.
- defaultCleanSize = 16 * 1024 * 1024
+ // DefaultCleanSize is the default memory allowance of clean cache.
+ DefaultCleanSize = 16 * 1024 * 1024
// maxBufferSize is the maximum memory allowance of node buffer.
// Too large nodebuffer will cause the system to pause for a long
@@ -54,6 +51,9 @@ const (
DefaultBufferSize = 64 * 1024 * 1024
)
+// maxDiffLayers is the maximum diff layers allowed in the layer tree.
+var maxDiffLayers = 128
+
// layer is the interface implemented by all state layers which includes some
// public methods and some additional methods for internal usage.
type layer interface {
@@ -76,7 +76,7 @@ type layer interface {
// the provided dirty trie nodes along with the state change set.
//
// Note, the maps are retained by the method to avoid copying everything.
- update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer
+ update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *state.Origin) *diffLayer
// journal commits an entire diff hierarchy to disk into a single journal entry.
// This is meant to be used during shutdown to persist the layer without
@@ -84,35 +84,6 @@ type layer interface {
journal(w io.Writer) error
}
-// Config contains the settings for database.
-type Config struct {
- StateHistory uint64 // Number of recent blocks to maintain state history for
- CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
- DirtyCacheSize int // Maximum memory allowance (in bytes) for caching dirty nodes
- ReadOnly bool // Flag whether the database is opened in read only mode.
-}
-
-// sanitize checks the provided user configurations and changes anything that's
-// unreasonable or unworkable.
-func (c *Config) sanitize() *Config {
- conf := *c
- if conf.DirtyCacheSize > maxBufferSize {
- log.Warn("Sanitizing invalid node buffer size", "provided", common.StorageSize(conf.DirtyCacheSize), "updated", common.StorageSize(maxBufferSize))
- conf.DirtyCacheSize = maxBufferSize
- }
- return &conf
-}
-
-// Defaults contains default settings for Ethereum mainnet.
-var Defaults = &Config{
- StateHistory: params.FullImmutabilityThreshold,
- CleanCacheSize: defaultCleanSize,
- DirtyCacheSize: DefaultBufferSize,
-}
-
-// ReadOnly is the config in order to open database in read only mode.
-var ReadOnly = &Config{ReadOnly: true}
-
// Database is a multiple-layered structure for maintaining in-memory trie nodes.
// It consists of one persistent base layer backed by a key-value store, on top
// of which arbitrarily many in-memory diff layers are stacked. The memory diffs
@@ -135,6 +106,7 @@ type Database struct {
diskdb ethdb.Database // Persistent storage for matured trie nodes
tree *layerTree // The group for all known layers
freezer *rawdb.ResettableFreezer // Freezer for storing trie histories, nil possible in tests
+ trieOpener state.TrieOpener // Trie loader to open trie for state recovering
lock sync.RWMutex // Lock to prevent mutations from happening at the same time
}
@@ -142,11 +114,10 @@ type Database struct {
// store (with a number of memory layers from a journal). If the journal is not
// matched with the base persistent layer, all the recorded diff layers are discarded.
func New(diskdb ethdb.Database, config *Config) *Database {
- if config == nil {
- config = Defaults
+ config, err := config.sanitize()
+ if err != nil {
+ log.Crit("Path database config is invalid", "err", err)
}
- config = config.sanitize()
-
db := &Database{
readOnly: config.ReadOnly,
bufferSize: config.DirtyCacheSize,
@@ -156,6 +127,7 @@ func New(diskdb ethdb.Database, config *Config) *Database {
// Construct the layer tree by resolving the in-disk singleton state
// and in-memory layer journal.
db.tree = newLayerTree(db.loadLayers())
+ db.trieOpener = db.config.TrieOpener(db)
// Open the freezer for state history if the passed database contains an
// ancient store. Otherwise, all the relevant functionalities are disabled.
@@ -206,8 +178,8 @@ func New(diskdb ethdb.Database, config *Config) *Database {
return db
}
-// Reader retrieves a layer belonging to the given state root.
-func (db *Database) Reader(root common.Hash) (layer, error) {
+// NodeReader retrieves a layer belonging to the given state root.
+func (db *Database) NodeReader(root common.Hash) (database.NodeReader, error) {
l := db.tree.get(root)
if l == nil {
return nil, fmt.Errorf("state %#x is not available", root)
@@ -222,7 +194,7 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
//
// The passed in maps(nodes, states) will be retained to avoid copying everything.
// Therefore, these maps must not be changed afterwards.
-func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
+func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *state.Origin) error {
// Hold the lock to prevent concurrent mutations.
db.lock.Lock()
defer db.lock.Unlock()
@@ -331,7 +303,7 @@ func (db *Database) Enable(root common.Hash) error {
// Recover rollbacks the database to a specified historical point.
// The state is supported as the rollback destination only if it's
// canonical state and the corresponding trie histories are existent.
-func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error {
+func (db *Database) Recover(root common.Hash) error {
db.lock.Lock()
defer db.lock.Unlock()
@@ -357,7 +329,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error
if err != nil {
return err
}
- dl, err = dl.revert(h, loader)
+ dl, err = dl.revert(h)
if err != nil {
return err
}
diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go
index 2e7e1bef05..4103749f7f 100644
--- a/triedb/pathdb/database_test.go
+++ b/triedb/pathdb/database_test.go
@@ -27,10 +27,11 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/trie/testutil"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/database"
+ "github.com/ethereum/go-ethereum/triedb/state"
"github.com/holiman/uint256"
)
@@ -54,7 +55,7 @@ func generateAccount(storageRoot common.Hash) types.StateAccount {
return types.StateAccount{
Nonce: uint64(rand.Intn(100)),
Balance: uint256.NewInt(rand.Uint64()),
- CodeHash: testutil.RandBytes(32),
+ CodeHash: testrand.Bytes(32),
Root: storageRoot,
}
}
@@ -98,22 +99,27 @@ type tester struct {
func newTester(t *testing.T, historyLimit uint64) *tester {
var (
- disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
- db = New(disk, &Config{
+ snapAccounts = make(map[common.Hash]map[common.Hash][]byte)
+ snapStorages = make(map[common.Hash]map[common.Hash]map[common.Hash][]byte)
+ disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
+ db = New(disk, &Config{
StateHistory: historyLimit,
- CleanCacheSize: 256 * 1024,
- DirtyCacheSize: 256 * 1024,
+ CleanCacheSize: 16 * 1024,
+ DirtyCacheSize: 16 * 1024,
+ TrieOpener: func(db database.NodeDatabase) state.TrieOpener {
+ return newHashOpener(snapAccounts, snapStorages)
+ },
})
obj = &tester{
db: db,
preimages: make(map[common.Hash]common.Address),
accounts: make(map[common.Hash][]byte),
storages: make(map[common.Hash]map[common.Hash][]byte),
- snapAccounts: make(map[common.Hash]map[common.Hash][]byte),
- snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte),
+ snapAccounts: snapAccounts,
+ snapStorages: snapStorages,
}
)
- for i := 0; i < 2*128; i++ {
+ for i := 0; i < 16; i++ {
var parent = types.EmptyRootHash
if len(obj.roots) != 0 {
parent = obj.roots[len(obj.roots)-1]
@@ -146,8 +152,8 @@ func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash {
origin = make(map[common.Hash][]byte)
)
for i := 0; i < 10; i++ {
- v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32)))
- hash := testutil.RandomHash()
+ v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32)))
+ hash := testrand.Hash()
storage[hash] = v
origin[hash] = nil
@@ -175,8 +181,8 @@ func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Has
}
}
for i := 0; i < 3; i++ {
- v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32)))
- hash := testutil.RandomHash()
+ v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32)))
+ hash := testrand.Hash()
storage[hash] = v
origin[hash] = nil
@@ -209,7 +215,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash
return root
}
-func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *triestate.Set) {
+func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *state.Origin) {
var (
ctx = newCtx()
dirties = make(map[common.Hash]struct{})
@@ -218,7 +224,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode
switch rand.Intn(opLen) {
case createAccountOp:
// account creation
- addr := testutil.RandomAddress()
+ addr := testrand.Address()
addrHash := crypto.Keccak256Hash(addr.Bytes())
if _, ok := t.accounts[addrHash]; ok {
continue
@@ -299,7 +305,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode
}
}
}
- return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin)
+ return root, ctx.nodes, state.NewOrigin(ctx.accountOrigin, ctx.storageOrigin)
}
// lastRoot returns the latest root hash, or empty if nothing is cached.
@@ -311,7 +317,7 @@ func (t *tester) lastHash() common.Hash {
}
func (t *tester) verifyState(root common.Hash) error {
- reader, err := t.db.Reader(root)
+ reader, err := t.db.NodeReader(root)
if err != nil {
return err
}
@@ -379,6 +385,10 @@ func (t *tester) bottomIndex() int {
}
func TestDatabaseRollback(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
// Verify state histories
tester := newTester(t, 0)
defer tester.release()
@@ -388,13 +398,11 @@ func TestDatabaseRollback(t *testing.T) {
}
// Revert database from top to bottom
for i := tester.bottomIndex(); i >= 0; i-- {
- root := tester.roots[i]
parent := types.EmptyRootHash
if i > 0 {
parent = tester.roots[i-1]
}
- loader := newHashLoader(tester.snapAccounts[root], tester.snapStorages[root])
- if err := tester.db.Recover(parent, loader); err != nil {
+ if err := tester.db.Recover(parent); err != nil {
t.Fatalf("Failed to revert db, err: %v", err)
}
if i > 0 {
@@ -409,6 +417,10 @@ func TestDatabaseRollback(t *testing.T) {
}
func TestDatabaseRecoverable(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
var (
tester = newTester(t, 0)
index = tester.bottomIndex()
@@ -448,6 +460,10 @@ func TestDatabaseRecoverable(t *testing.T) {
}
func TestDisable(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
tester := newTester(t, 0)
defer tester.release()
@@ -459,7 +475,7 @@ func TestDisable(t *testing.T) {
t.Fatalf("Invalid activation should be rejected")
}
if err := tester.db.Enable(stored); err != nil {
- t.Fatal("Failed to activate database")
+ t.Fatalf("Failed to activate database, %v", err)
}
// Ensure journal is deleted from disk
@@ -484,6 +500,10 @@ func TestDisable(t *testing.T) {
}
func TestCommit(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
tester := newTester(t, 0)
defer tester.release()
@@ -508,6 +528,10 @@ func TestCommit(t *testing.T) {
}
func TestJournal(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
tester := newTester(t, 0)
defer tester.release()
@@ -515,7 +539,7 @@ func TestJournal(t *testing.T) {
t.Errorf("Failed to journal, err: %v", err)
}
tester.db.Close()
- tester.db = New(tester.db.diskdb, nil)
+ tester.db = New(tester.db.diskdb, tester.db.config)
// Verify states including disk layer and all diff on top.
for i := 0; i < len(tester.roots); i++ {
@@ -532,6 +556,10 @@ func TestJournal(t *testing.T) {
}
func TestCorruptedJournal(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
tester := newTester(t, 0)
defer tester.release()
@@ -547,7 +575,7 @@ func TestCorruptedJournal(t *testing.T) {
rawdb.WriteTrieJournal(tester.db.diskdb, blob)
// Verify states, all not-yet-written states should be discarded
- tester.db = New(tester.db.diskdb, nil)
+ tester.db = New(tester.db.diskdb, tester.db.config)
for i := 0; i < len(tester.roots); i++ {
if tester.roots[i] == root {
if err := tester.verifyState(root); err != nil {
@@ -574,11 +602,15 @@ func TestCorruptedJournal(t *testing.T) {
// truncating the tail histories. This ensures that the ID of the persistent state
// always falls within the range of [oldest-history-id, latest-history-id].
func TestTailTruncateHistory(t *testing.T) {
+ maxDiffLayers = 4
+ defer func() {
+ maxDiffLayers = 128
+ }()
tester := newTester(t, 10)
defer tester.release()
tester.db.Close()
- tester.db = New(tester.db.diskdb, &Config{StateHistory: 10})
+ tester.db = New(tester.db.diskdb, &Config{StateHistory: 10, TrieOpener: func(db database.NodeDatabase) state.TrieOpener { return nil }})
head, err := tester.db.freezer.Ancients()
if err != nil {
diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go
index 10567715d2..b17af4751f 100644
--- a/triedb/pathdb/difflayer.go
+++ b/triedb/pathdb/difflayer.go
@@ -23,7 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
// diffLayer represents a collection of modifications made to the in-memory tries
@@ -37,7 +37,7 @@ type diffLayer struct {
id uint64 // Corresponding state id
block uint64 // Associated block number
nodes map[common.Hash]map[string]*trienode.Node // Cached trie nodes indexed by owner and path
- states *triestate.Set // Associated state change set for building history
+ states *state.Origin // Associated state change set for building history
memory uint64 // Approximate guess as to how much memory we use
parent layer // Parent layer modified by this one, never nil, **can be changed**
@@ -45,7 +45,7 @@ type diffLayer struct {
}
// newDiffLayer creates a new diff layer on top of an existing layer.
-func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer {
+func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *state.Origin) *diffLayer {
var (
size int64
count int
@@ -138,7 +138,7 @@ func (dl *diffLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b
// update implements the layer interface, creating a new layer on top of the
// existing layer tree with the specified data items.
-func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer {
+func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *state.Origin) *diffLayer {
return newDiffLayer(dl, root, id, block, nodes, states)
}
diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go
index 9b5907c3c5..75890b8a83 100644
--- a/triedb/pathdb/difflayer_test.go
+++ b/triedb/pathdb/difflayer_test.go
@@ -22,7 +22,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/trie/testutil"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/trie/trienode"
)
@@ -66,8 +67,9 @@ func benchmarkSearch(b *testing.B, depth int, total int) {
nodes[common.Hash{}] = make(map[string]*trienode.Node)
for i := 0; i < 3000; i++ {
var (
- path = testutil.RandBytes(32)
- node = testutil.RandomNode()
+ path = testrand.Bytes(32)
+ blob = testrand.Bytes(100)
+ node = trienode.New(crypto.Keccak256Hash(blob), blob)
)
nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob)
if npath == nil && depth == index {
@@ -112,8 +114,9 @@ func BenchmarkPersist(b *testing.B) {
nodes[common.Hash{}] = make(map[string]*trienode.Node)
for i := 0; i < 3000; i++ {
var (
- path = testutil.RandBytes(32)
- node = testutil.RandomNode()
+ path = testrand.Bytes(32)
+ blob = testrand.Bytes(100)
+ node = trienode.New(crypto.Keccak256Hash(blob), blob)
)
nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob)
}
@@ -149,8 +152,9 @@ func BenchmarkJournal(b *testing.B) {
nodes[common.Hash{}] = make(map[string]*trienode.Node)
for i := 0; i < 3000; i++ {
var (
- path = testutil.RandBytes(32)
- node = testutil.RandomNode()
+ path = testrand.Bytes(32)
+ blob = testrand.Bytes(100)
+ node = trienode.New(crypto.Keccak256Hash(blob), blob)
)
nodes[common.Hash{}][string(path)] = trienode.New(node.Hash, node.Blob)
}
diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go
index 777e4ec8a7..cbe33596e1 100644
--- a/triedb/pathdb/disklayer.go
+++ b/triedb/pathdb/disklayer.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
"golang.org/x/crypto/sha3"
)
@@ -160,7 +160,7 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b
// update implements the layer interface, returning a new diff layer on top
// with the given state set.
-func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer {
+func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *state.Origin) *diffLayer {
return newDiffLayer(dl, root, id, block, nodes, states)
}
@@ -234,17 +234,28 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
}
// revert applies the given state history and return a reverted disk layer.
-func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer, error) {
+func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
if h.meta.root != dl.rootHash() {
return nil, errUnexpectedHistory
}
if dl.id == 0 {
return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable)
}
+ var (
+ hasher = crypto.NewKeccakState()
+ accounts = make(map[common.Hash][]byte)
+ storages = make(map[common.Hash]map[common.Hash][]byte)
+ )
+ for addr, blob := range h.accounts {
+ accounts[crypto.HashData(hasher, addr.Bytes())] = blob
+ }
+ for addr, storage := range h.storages {
+ storages[crypto.HashData(hasher, addr.Bytes())] = storage
+ }
// Apply the reverse state changes upon the current state. This must
// be done before holding the lock in order to access state in "this"
// layer.
- nodes, err := triestate.Apply(h.meta.parent, h.meta.root, h.accounts, h.storages, loader)
+ nodes, err := state.Apply(h.meta.parent, h.meta.root, accounts, storages, dl.db.trieOpener)
if err != nil {
return nil, err
}
diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go
index 68fb4809f0..2dff3c9a75 100644
--- a/triedb/pathdb/history.go
+++ b/triedb/pathdb/history.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
"golang.org/x/exp/slices"
)
@@ -242,7 +242,7 @@ type history struct {
}
// newHistory constructs the state history object with provided state change set.
-func newHistory(root common.Hash, parent common.Hash, block uint64, states *triestate.Set) *history {
+func newHistory(root common.Hash, parent common.Hash, block uint64, states *state.Origin) *history {
var (
accountList []common.Address
storageList = make(map[common.Address][]common.Hash)
diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go
index ab0d44777d..2cc57ed928 100644
--- a/triedb/pathdb/history_test.go
+++ b/triedb/pathdb/history_test.go
@@ -26,32 +26,32 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/trie/testutil"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
// randomStateSet generates a random state change set.
-func randomStateSet(n int) *triestate.Set {
+func randomStateSet(n int) *state.Origin {
var (
accounts = make(map[common.Address][]byte)
storages = make(map[common.Address]map[common.Hash][]byte)
)
for i := 0; i < n; i++ {
- addr := testutil.RandomAddress()
+ addr := testrand.Address()
storages[addr] = make(map[common.Hash][]byte)
for j := 0; j < 3; j++ {
- v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32)))
- storages[addr][testutil.RandomHash()] = v
+ v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32)))
+ storages[addr][testrand.Hash()] = v
}
account := generateAccount(types.EmptyRootHash)
accounts[addr] = types.SlimAccountRLP(account)
}
- return triestate.New(accounts, storages)
+ return state.NewOrigin(accounts, storages)
}
func makeHistory() *history {
- return newHistory(testutil.RandomHash(), types.EmptyRootHash, 0, randomStateSet(3))
+ return newHistory(testrand.Hash(), types.EmptyRootHash, 0, randomStateSet(3))
}
func makeHistories(n int) []*history {
@@ -60,7 +60,7 @@ func makeHistories(n int) []*history {
result []*history
)
for i := 0; i < n; i++ {
- root := testutil.RandomHash()
+ root := testrand.Hash()
h := newHistory(root, parent, uint64(i), randomStateSet(3))
parent = root
result = append(result, h)
diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go
index 3a0b7ebae2..2d1d49fbc0 100644
--- a/triedb/pathdb/journal.go
+++ b/triedb/pathdb/journal.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
var (
@@ -239,7 +239,7 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
}
storages[entry.Account] = set
}
- return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages)), r)
+ return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, state.NewOrigin(accounts, storages)), r)
}
// journal implements the layer interface, marshaling the un-flushed trie nodes
diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go
index d314779910..63b5afbdb0 100644
--- a/triedb/pathdb/layertree.go
+++ b/triedb/pathdb/layertree.go
@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
)
// layerTree is a group of state layers identified by the state root.
@@ -86,7 +86,7 @@ func (tree *layerTree) len() int {
}
// add inserts a new layer into the tree if it can be linked to an existing old parent.
-func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
+func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *state.Origin) error {
// Reject noop updates to avoid self-loops. This is a special case that can
// happen for clique networks and proof-of-stake networks where empty blocks
// don't modify the state (0 block subsidy).
diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testhasher.go
similarity index 86%
rename from triedb/pathdb/testutils.go
rename to triedb/pathdb/testhasher.go
index d6fdacb421..b162eb47d4 100644
--- a/triedb/pathdb/testutils.go
+++ b/triedb/pathdb/testhasher.go
@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/trie/trienode"
- "github.com/ethereum/go-ethereum/trie/triestate"
+ "github.com/ethereum/go-ethereum/triedb/state"
"golang.org/x/exp/slices"
)
@@ -133,24 +133,24 @@ func hash(states map[common.Hash][]byte) (common.Hash, []byte) {
return crypto.Keccak256Hash(input), input
}
-type hashLoader struct {
- accounts map[common.Hash][]byte
- storages map[common.Hash]map[common.Hash][]byte
+type hashOpener struct {
+ accounts map[common.Hash]map[common.Hash][]byte
+ storages map[common.Hash]map[common.Hash]map[common.Hash][]byte
}
-func newHashLoader(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *hashLoader {
- return &hashLoader{
+func newHashOpener(accounts map[common.Hash]map[common.Hash][]byte, storages map[common.Hash]map[common.Hash]map[common.Hash][]byte) *hashOpener {
+ return &hashOpener{
accounts: accounts,
storages: storages,
}
}
// OpenTrie opens the main account trie.
-func (l *hashLoader) OpenTrie(root common.Hash) (triestate.Trie, error) {
- return newTestHasher(common.Hash{}, root, l.accounts)
+func (l *hashOpener) OpenTrie(root common.Hash) (state.Trie, error) {
+ return newTestHasher(common.Hash{}, root, l.accounts[root])
}
// OpenStorageTrie opens the storage trie of an account.
-func (l *hashLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) {
- return newTestHasher(addrHash, root, l.storages[addrHash])
+func (l *hashOpener) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (state.Trie, error) {
+ return newTestHasher(addrHash, root, l.storages[stateRoot][addrHash])
}
diff --git a/trie/triestate/state.go b/triedb/state/trie.go
similarity index 63%
rename from trie/triestate/state.go
rename to triedb/state/trie.go
index aa4d32f852..56b0defa29 100644
--- a/trie/triestate/state.go
+++ b/triedb/state/trie.go
@@ -14,19 +14,16 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
-package triestate
+package state
import (
"errors"
"fmt"
- "sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode"
- "golang.org/x/crypto/sha3"
)
// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia
@@ -46,8 +43,8 @@ type Trie interface {
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
}
-// TrieLoader wraps functions to load tries.
-type TrieLoader interface {
+// TrieOpener wraps functions to load tries.
+type TrieOpener interface {
// OpenTrie opens the main account trie.
OpenTrie(root common.Hash) (Trie, error)
@@ -55,55 +52,20 @@ type TrieLoader interface {
OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error)
}
-// Set represents a collection of mutated states during a state transition.
-// The value refers to the original content of state before the transition
-// is made. Nil means that the state was not present previously.
-type Set struct {
- Accounts map[common.Address][]byte // Mutated account set, nil means the account was not present
- Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present
- size common.StorageSize // Approximate size of set
-}
-
-// New constructs the state set with provided data.
-func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *Set {
- return &Set{
- Accounts: accounts,
- Storages: storages,
- }
-}
-
-// Size returns the approximate memory size occupied by the set.
-func (s *Set) Size() common.StorageSize {
- if s.size != 0 {
- return s.size
- }
- for _, account := range s.Accounts {
- s.size += common.StorageSize(common.AddressLength + len(account))
- }
- for _, slots := range s.Storages {
- for _, val := range slots {
- s.size += common.StorageSize(common.HashLength + len(val))
- }
- s.size += common.StorageSize(common.AddressLength)
- }
- return s.size
-}
-
// context wraps all fields for executing state diffs.
type context struct {
prevRoot common.Hash
postRoot common.Hash
- accounts map[common.Address][]byte
- storages map[common.Address]map[common.Hash][]byte
+ accounts map[common.Hash][]byte
+ storages map[common.Hash]map[common.Hash][]byte
accountTrie Trie
nodes *trienode.MergedNodeSet
}
-// Apply traverses the provided state diffs, apply them in the associated
-// post-state and return the generated dirty trie nodes. The state can be
-// loaded via the provided trie loader.
-func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) {
- tr, err := loader.OpenTrie(postRoot)
+// Apply traverses the provided state diffs, applying them in the associated
+// post-state and return the produced trie changes.
+func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte, opener TrieOpener) (map[common.Hash]map[string]*trienode.Node, error) {
+ tr, err := opener.OpenTrie(postRoot)
if err != nil {
return nil, err
}
@@ -115,12 +77,12 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre
accountTrie: tr,
nodes: trienode.NewMergedNodeSet(),
}
- for addr, account := range accounts {
+ for addrHash, account := range accounts {
var err error
if len(account) == 0 {
- err = deleteAccount(ctx, loader, addr)
+ err = deleteAccount(ctx, opener, addrHash)
} else {
- err = updateAccount(ctx, loader, addr)
+ err = updateAccount(ctx, opener, addrHash)
}
if err != nil {
return nil, fmt.Errorf("failed to revert state, err: %w", err)
@@ -142,14 +104,10 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre
// updateAccount the account was present in prev-state, and may or may not
// existent in post-state. Apply the reverse diff and verify if the storage
// root matches the one in prev-state account.
-func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
+func updateAccount(ctx *context, opener TrieOpener, addrHash common.Hash) error {
// The account was present in prev-state, decode it from the
// 'slim-rlp' format bytes.
- h := newHasher()
- defer h.release()
-
- addrHash := h.hash(addr.Bytes())
- prev, err := types.FullAccount(ctx.accounts[addr])
+ prev, err := types.FullAccount(ctx.accounts[addrHash])
if err != nil {
return err
}
@@ -166,11 +124,11 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
}
}
// Apply all storage changes into the post-state storage trie.
- st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
+ st, err := opener.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
if err != nil {
return err
}
- for key, val := range ctx.storages[addr] {
+ for key, val := range ctx.storages[addrHash] {
var err error
if len(val) == 0 {
err = st.Delete(key.Bytes())
@@ -206,12 +164,8 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
// deleteAccount the account was not present in prev-state, and is expected
// to be existent in post-state. Apply the reverse diff and verify if the
// account and storage is wiped out correctly.
-func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
+func deleteAccount(ctx *context, opener TrieOpener, addrHash common.Hash) error {
// The account must be existent in post-state, load the account.
- h := newHasher()
- defer h.release()
-
- addrHash := h.hash(addr.Bytes())
blob, err := ctx.accountTrie.Get(addrHash.Bytes())
if err != nil {
return err
@@ -223,11 +177,11 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
if err := rlp.DecodeBytes(blob, &post); err != nil {
return err
}
- st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
+ st, err := opener.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
if err != nil {
return err
}
- for key, val := range ctx.storages[addr] {
+ for key, val := range ctx.storages[addrHash] {
if len(val) != 0 {
return errors.New("expect storage deletion")
}
@@ -252,22 +206,3 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
// Delete the post-state account from the main trie.
return ctx.accountTrie.Delete(addrHash.Bytes())
}
-
-// hasher is used to compute the sha256 hash of the provided data.
-type hasher struct{ sha crypto.KeccakState }
-
-var hasherPool = sync.Pool{
- New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} },
-}
-
-func newHasher() *hasher {
- return hasherPool.Get().(*hasher)
-}
-
-func (h *hasher) hash(data []byte) common.Hash {
- return crypto.HashData(h.sha, data)
-}
-
-func (h *hasher) release() {
- hasherPool.Put(h)
-}
diff --git a/triedb/state/types.go b/triedb/state/types.go
new file mode 100644
index 0000000000..820eb17110
--- /dev/null
+++ b/triedb/state/types.go
@@ -0,0 +1,59 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see
+
+package state
+
+import "github.com/ethereum/go-ethereum/common"
+
+// Origin represents the prev-state for a state transition.
+type Origin struct {
+ // Accounts represents the account data before the state transition, keyed
+ // by the account address. The nil value means the account was not present
+ // before.
+ Accounts map[common.Address][]byte
+
+ // Storages represents the storage data before the state transition, keyed
+ // by the account address and slot key hash. The nil value means the slot
+ // was not present.
+ Storages map[common.Address]map[common.Hash][]byte
+
+ size common.StorageSize // Approximate size of set
+}
+
+// NewOrigin constructs the state set with provided data.
+func NewOrigin(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *Origin {
+ return &Origin{
+ Accounts: accounts,
+ Storages: storages,
+ }
+}
+
+// Size returns the approximate memory size occupied by the set.
+func (s *Origin) Size() common.StorageSize {
+ if s.size != 0 {
+ return s.size
+ }
+ for _, account := range s.Accounts {
+ s.size += common.StorageSize(common.AddressLength + len(account))
+ }
+ for _, slots := range s.Storages {
+ for _, val := range slots {
+ s.size += common.StorageSize(common.HashLength + len(val))
+ }
+ s.size += common.StorageSize(common.AddressLength)
+ }
+ return s.size
+}