Use the statedb database to get Tries

The old approach of getting state tries involved instantiating a
new state database and using it to instantiate a trie. What we didn't
realize was that state database needed to have Close() called on it,
which we didn't offer a way for plugins to do, resulting in memory
leaking.

This approach reuses the primary trie database associated with the
blockchain object, albeit a bit indirectly. This will allow access
to recent tries that are stored in memory, where previously only
tries that had been committed to disk were accessible.
This commit is contained in:
Austin Roberts 2023-12-06 16:04:56 -06:00
parent 703c3b6b74
commit bc14d12fd7
4 changed files with 14 additions and 87 deletions

View File

@ -358,8 +358,7 @@ func geth(ctx *cli.Context) error {
}
stack, backend := makeFullNode(ctx)
trieCfg := plugethCaptureTrieConfig(ctx, stack, backend)
wrapperBackend := backendwrapper.NewBackend(backend, trieCfg)
wrapperBackend := backendwrapper.NewBackend(backend)
pluginsInitializeNode(stack, wrapperBackend)
if ok, err := plugins.RunSubcommand(ctx); ok {

View File

@ -1,25 +1,15 @@
package main
import (
"github.com/ethereum/go-ethereum/cmd/utils"
gcore "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
"github.com/ethereum/go-ethereum/plugins"
"github.com/ethereum/go-ethereum/plugins/wrappers"
"github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted"
"github.com/urfave/cli/v2"
)
func apiTranslate(apis []core.API) []rpc.API {
@ -132,69 +122,3 @@ func pluginBlockChain() {
}
BlockChain(plugins.DefaultPluginLoader)
}
func plugethCaptureTrieConfig(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) *trie.Config {
ethCfg := new(ethconfig.Config)
if ctx.IsSet(utils.CacheFlag.Name) || ctx.IsSet(utils.CacheTrieFlag.Name) {
ethCfg.TrieCleanCache = ctx.Int(utils.CacheFlag.Name) * ctx.Int(utils.CacheTrieFlag.Name) / 100
}
if ctx.IsSet(utils.CacheNoPrefetchFlag.Name) {
ethCfg.NoPrefetch = ctx.Bool(utils.CacheNoPrefetchFlag.Name)
}
if ctx.IsSet(utils.CacheFlag.Name) || ctx.IsSet(utils.CacheGCFlag.Name) {
ethCfg.TrieDirtyCache = ctx.Int(utils.CacheFlag.Name) * ctx.Int(utils.CacheGCFlag.Name) / 100
}
if ctx.IsSet(utils.GCModeFlag.Name) {
ethCfg.NoPruning = ctx.String(utils.GCModeFlag.Name) == "archive"
}
if ctx.IsSet(utils.CacheFlag.Name) || ctx.IsSet(utils.CacheSnapshotFlag.Name) {
ethCfg.SnapshotCache = ctx.Int(utils.CacheFlag.Name) * ctx.Int(utils.CacheSnapshotFlag.Name) / 100
}
ethCfg.Preimages = ctx.Bool(utils.CachePreimagesFlag.Name)
if ethCfg.NoPruning && !ethCfg.Preimages {
ethCfg.Preimages = true
log.Info("Enabling recording of key preimages since archive mode is used")
}
if ctx.IsSet(utils.StateHistoryFlag.Name) {
ethCfg.StateHistory = ctx.Uint64(utils.StateHistoryFlag.Name)
}
chaindb := backend.ChainDb()
scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), chaindb)
if err != nil {
utils.Fatalf("%v", err)
}
ethCfg.StateScheme = scheme
cacheCfg := &gcore.CacheConfig{
TrieCleanLimit: ethCfg.TrieCleanCache,
TrieCleanNoPrefetch: ethCfg.NoPrefetch,
TrieDirtyLimit: ethCfg.TrieDirtyCache,
TrieDirtyDisabled: ethCfg.NoPruning,
TrieTimeLimit: ethconfig.Defaults.TrieTimeout,
SnapshotLimit: ethCfg.SnapshotCache,
Preimages: ethCfg.Preimages,
StateHistory: ethCfg.StateHistory,
StateScheme: ethCfg.StateScheme,
}
config := &trie.Config{Preimages: cacheCfg.Preimages}
if cacheCfg.StateScheme == rawdb.HashScheme {
config.HashDB = &hashdb.Config{
CleanCacheSize: cacheCfg.TrieCleanLimit * 1024 * 1024,
}
}
if cacheCfg.StateScheme == rawdb.PathScheme {
config.PathDB = &pathdb.Config{
StateHistory: cacheCfg.StateHistory,
CleanCacheSize: cacheCfg.TrieCleanLimit * 1024 * 1024,
DirtyCacheSize: cacheCfg.TrieDirtyLimit * 1024 * 1024,
}
}
return config
}

View File

@ -13,12 +13,10 @@ import (
gcore "github.com/ethereum/go-ethereum/core"
"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/event"
gparams "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
@ -29,6 +27,7 @@ import (
type Backend struct {
b ethapi.Backend
db state.Database
newTxsFeed event.Feed
newTxsOnce sync.Once
chainFeed event.Feed
@ -44,14 +43,17 @@ type Backend struct {
removedLogsFeed event.Feed
removedLogsOnce sync.Once
chainConfig *params.ChainConfig
trieConfig *trie.Config
}
func NewBackend(b ethapi.Backend, tc *trie.Config) *Backend {
func NewBackend(b ethapi.Backend) *Backend {
state, _, err := b.StateAndHeaderByNumber(context.Background(), 0)
if err != nil {
panic(err.Error())
}
return &Backend{
b: b,
trieConfig: tc}
db: state.Database(),
}
}
func (b *Backend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
@ -492,7 +494,7 @@ func CloneChainConfig(cf *gparams.ChainConfig) *params.ChainConfig {
}
func (b *Backend) GetTrie(h core.Hash) (core.Trie, error) {
tr, err := trie.NewStateTrie(trie.TrieID(common.Hash(h)), trie.NewDatabase(b.b.ChainDb(), b.trieConfig))
tr, err := b.db.OpenTrie(common.Hash(h))
if err != nil {
return nil, err
}
@ -508,7 +510,7 @@ func (b *Backend) GetAccountTrie(stateRoot core.Hash, account core.Address) (cor
if err != nil {
return nil, err
}
acTr, err := trie.NewStateTrie(trie.StorageTrieID(common.Hash(stateRoot), crypto.Keccak256Hash(account[:]), common.Hash(act.Root)), trie.NewDatabase(b.b.ChainDb(), b.trieConfig))
acTr, err := b.db.OpenStorageTrie(common.Hash(stateRoot), common.Address(account), common.Hash(act.Root))
if err != nil {
return nil, err
}

View File

@ -40,7 +40,9 @@ func (t *WrappedTrie) Hash() core.Hash {
func (t *WrappedTrie) NodeIterator(startKey []byte) core.NodeIterator {
itr, err := t.t.NodeIterator(startKey)
if err != nil {
log.Error("Error returned from geth side NodeIterator", "err", err)
}
return &WrappedNodeIterator{itr}
}