Skip to content

Commit

Permalink
implement the framework of fast node
Browse files Browse the repository at this point in the history
  • Loading branch information
unclezoro committed Dec 7, 2021
1 parent 74f6b61 commit e0e7ead
Show file tree
Hide file tree
Showing 22 changed files with 459 additions and 70 deletions.
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ var (
utils.WhitelistFlag,
utils.BloomFilterSizeFlag,
utils.TriesInMemoryFlag,
utils.AllowInsecureNoTriesFlag,
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheTrieFlag,
Expand Down
62 changes: 61 additions & 1 deletion cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ package main

import (
"bytes"
"encoding/json"
"errors"
"os"
"time"

"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/pruner"
Expand Down Expand Up @@ -98,6 +101,32 @@ geth snapshot verify-state <state-root>
will traverse the whole accounts and storages set based on the specified
snapshot and recalculate the root hash of state for verification.
In other words, this command does the snapshot to trie conversion.
`,
},
{
Name: "insecure-prune-all",
Usage: "Prune all trie state data except genesis block, it will break storage for fullnode, only suitable for fast node " +
"who do not need trie storage at all",
ArgsUsage: "<genesisPath>",
Action: utils.MigrateFlags(pruneAllState),
Category: "MISCELLANEOUS COMMANDS",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.AncientFlag,
utils.RopstenFlag,
utils.RinkebyFlag,
utils.GoerliFlag,
},
Description: `
will prune all historical trie state data except genesis block.
All trie nodes and contract codes will be deleted from the database.
It expects the genesis file as argument.
WARNING: It's necessary to delete the trie clean cache after the pruning.
If you specify another directory for the trie clean cache via "--cache.trie.journal"
during the use of Geth, please also specify it here for correct deletion. Otherwise
the trie clean cache with default directory will be deleted.
`,
},
{
Expand Down Expand Up @@ -178,6 +207,37 @@ func pruneState(ctx *cli.Context) error {
return nil
}

func pruneAllState(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)
defer stack.Close()

genesisPath := ctx.Args().First()
if len(genesisPath) == 0 {
utils.Fatalf("Must supply path to genesis JSON file")
}
file, err := os.Open(genesisPath)
if err != nil {
utils.Fatalf("Failed to read genesis file: %v", err)
}
defer file.Close()

g := new(core.Genesis)
if err := json.NewDecoder(file).Decode(g); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
chaindb := utils.MakeChainDatabase(ctx, stack, false)
pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name), ctx.GlobalUint64(utils.TriesInMemoryFlag.Name))
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
}
if err = pruner.PruneAll(g); err != nil {
log.Error("Failed to prune state", "err", err)
return err
}
return nil
}

func verifyState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
Expand All @@ -188,7 +248,7 @@ func verifyState(ctx *cli.Context) error {
log.Error("Failed to load head block")
return errors.New("no head block")
}
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false)
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false, false)
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
Expand Down
9 changes: 8 additions & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ var (
Usage: "The layer of tries trees that keep in memory",
Value: 128,
}
AllowInsecureNoTriesFlag = cli.BoolTFlag{
Name: "allow-insecure-no-tries",
Usage: `Disable the tries state root verification, the state consistent is no longer 100% guaranteed. Do not enable it unless you know exactly what the consequence it will cause.`,
}
OverrideBerlinFlag = cli.Uint64Flag{
Name: "override.berlin",
Usage: "Manually specify Berlin fork-block, overriding the bundled setting",
Expand Down Expand Up @@ -1648,13 +1652,16 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.GlobalIsSet(TriesInMemoryFlag.Name) {
cfg.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name)
}
if ctx.GlobalIsSet(AllowInsecureNoTriesFlag.Name) {
cfg.NoTries = ctx.GlobalBool(AllowInsecureNoTriesFlag.Name)
}
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
}
if !ctx.GlobalBool(SnapshotFlag.Name) {
// If snap-sync is requested, this flag is also required
if cfg.SyncMode == downloader.SnapSync {
log.Info("Snap sync requested, enabling --snapshot")
log.Info("snap sync requested, enabling --snapshot")
} else {
cfg.TrieCleanCache += cfg.SnapshotCache
cfg.SnapshotCache = 0 // Disabled
Expand Down
4 changes: 0 additions & 4 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
// header's transaction and uncle roots. The headers are assumed to be already
// validated at this point.
func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Check whether the block's known, and if not, that it's linkable
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock
}
// Header validity is known at this point, check the uncles and transactions
header := block.Header()
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
Expand Down
21 changes: 20 additions & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ type CacheConfig struct {
SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory
Preimages bool // Whether to store preimage of trie key to the disk
TriesInMemory uint64 // How many tries keeps in memory
NoTries bool // Do not have any tries in databases if enabled. Unsecured settings.

SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
}
Expand Down Expand Up @@ -273,6 +274,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
Cache: cacheConfig.TrieCleanLimit,
Journal: cacheConfig.TrieCleanJournal,
Preimages: cacheConfig.Preimages,
NoTries: cacheConfig.NoTries,
}),
triesInMemory: cacheConfig.TriesInMemory,
quit: make(chan struct{}),
Expand Down Expand Up @@ -422,7 +424,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer)
recover = true
}
bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover)
bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover, bc.stateCache.NoTries())
}
// do options before start any routine
for _, option := range options {
Expand Down Expand Up @@ -1049,6 +1051,13 @@ func (bc *BlockChain) HasFastBlock(hash common.Hash, number uint64) bool {

// HasState checks if state trie is fully present in the database or not.
func (bc *BlockChain) HasState(hash common.Hash) bool {
if bc.stateCache.NoTries() {
if bc.snaps != nil && bc.snaps.Snapshot(hash) != nil {
return true
} else {
return false
}
}
_, err := bc.stateCache.OpenTrie(hash)
return err == nil
}
Expand All @@ -1061,6 +1070,13 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {
if block == nil {
return false
}
if bc.stateCache.NoTries() {
if bc.snaps != nil && bc.snaps.Snapshot(block.Root()) != nil {
return true
} else {
return false
}
}
return bc.HasState(block.Root())
}

Expand Down Expand Up @@ -2047,6 +2063,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
if err != nil {
return it.index, err
}
if statedb.NoTrie() {
statedb.SetCurrentRoot(block.Root())
}
bc.updateHighestVerifiedHeader(block.Header())

// Enable prefetching to pull in trie node paths while processing transactions
Expand Down
30 changes: 29 additions & 1 deletion core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ type Database interface {

// Purge cache
Purge()

// NoTries returns whether tries is supported
NoTries() bool
}

// Trie is a Ethereum Merkle Patricia trie.
Expand Down Expand Up @@ -134,10 +137,15 @@ func NewDatabase(db ethdb.Database) Database {
func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
csc, _ := lru.New(codeSizeCacheSize)
cc, _ := lru.New(codeCacheSize)
noTries := false
if config != nil && config.NoTries {
noTries = true
}
return &cachingDB{
db: trie.NewDatabaseWithConfig(db, config),
codeSizeCache: csc,
codeCache: cc,
noTries: noTries,
}
}

Expand All @@ -146,15 +154,22 @@ func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Datab
cc, _ := lru.New(codeCacheSize)
atc, _ := lru.New(accountTrieCacheSize)
stc, _ := lru.New(storageTrieCacheSize)
noTries := false
if config != nil && config.NoTries {
noTries = true
}

database := &cachingDB{
db: trie.NewDatabaseWithConfig(db, config),
codeSizeCache: csc,
codeCache: cc,
accountTrieCache: atc,
storageTrieCache: stc,
noTries: noTries,
}
if !noTries {
go database.purgeLoop()
}
go database.purgeLoop()
return database
}

Expand All @@ -164,6 +179,7 @@ type cachingDB struct {
codeCache *lru.Cache
accountTrieCache *lru.Cache
storageTrieCache *lru.Cache
noTries bool
}

type triePair struct {
Expand All @@ -187,6 +203,9 @@ func (db *cachingDB) purgeLoop() {

// OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.noTries {
return trie.NewEmptyTrie(), nil
}
if db.accountTrieCache != nil {
if tr, exist := db.accountTrieCache.Get(root); exist {
return tr.(Trie).(*trie.SecureTrie).Copy(), nil
Expand All @@ -201,6 +220,9 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {

// OpenStorageTrie opens the storage trie of an account.
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
if db.noTries {
return trie.NewEmptyTrie(), nil
}
if db.storageTrieCache != nil {
if tries, exist := db.storageTrieCache.Get(addrHash); exist {
triesPairs := tries.([3]*triePair)
Expand Down Expand Up @@ -246,6 +268,10 @@ func (db *cachingDB) CacheStorage(addrHash common.Hash, root common.Hash, t Trie
}
}

func (db *cachingDB) NoTries() bool {
return db.noTries
}

func (db *cachingDB) Purge() {
if db.storageTrieCache != nil {
db.storageTrieCache.Purge()
Expand All @@ -260,6 +286,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
switch t := t.(type) {
case *trie.SecureTrie:
return t.Copy()
case *trie.EmptyTrie:
return t.Copy()
default:
panic(fmt.Errorf("unknown trie type %T", t))
}
Expand Down
Loading

0 comments on commit e0e7ead

Please sign in to comment.