diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 73816e833c9654710d697328d148156cd29f9b81..e5a49429c979637937983b3dfb26981cf2116f7b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -109,6 +109,7 @@ var ( utils.CacheTrieFlag, utils.CacheGCFlag, utils.TrieCacheGenFlag, + utils.DownloadOnlyFlag, utils.NoHistory, utils.ArchiveSyncInterval, utils.ListenPortFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 58d3fcdcf607cba50527755d461bd322a1d0040f..b79007678dc6e0eea52d35d963aa9f583d61d4cd 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -87,6 +87,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.IdentityFlag, utils.LightKDFFlag, utils.WhitelistFlag, + utils.DownloadOnlyFlag, utils.NoHistory, utils.ArchiveSyncInterval, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 12b71742a5d8f5717a5cfacef1e43d10a80ad4b6..e86601e90c552662459d6535c5fa8ffefa6fbb8a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -297,6 +297,10 @@ var ( Name: "ulc.onlyannounce", Usage: "Ultra light server sends announcements only", } + DownloadOnlyFlag = cli.BoolFlag{ + Name: "download-only", + Usage: "Run in download only mode - only fetch blocks but not process them", + } // Dashboard settings DashboardEnabledFlag = cli.BoolFlag{ Name: "dashboard", @@ -1468,6 +1472,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { cfg.BlocksToPrune = ctx.GlobalUint64(GCModeBlockToPruneFlag.Name) cfg.PruningTimeout = ctx.GlobalDuration(GCModeTickTimeout.Name) + cfg.DownloadOnly = ctx.GlobalBoolT(DownloadOnlyFlag.Name) cfg.NoHistory = ctx.GlobalBoolT(NoHistory.Name) cfg.ArchiveSyncInterval = ctx.GlobalInt(ArchiveSyncInterval.Name) diff --git a/core/blockchain.go b/core/blockchain.go index 1b3499994c42ffedf1f0562e97234577150f434f..e0ffca15871934c74b3be187c56e3f7bc5d7e035 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -124,6 +124,7 @@ type CacheConfig struct { BlocksToPrune uint64 PruneTimeout time.Duration ArchiveSyncInterval uint64 + DownloadOnly bool NoHistory bool } @@ -205,6 +206,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, + DownloadOnly: false, NoHistory: false, } } @@ -1243,7 +1245,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. // writeBlockWithState writes the block and all associated state to the database, // but is expects the chain mutex to be held. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.IntraBlockState, tds *state.TrieDbState) (status WriteStatus, err error) { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, stateDb *state.IntraBlockState, tds *state.TrieDbState) (status WriteStatus, err error) { bc.wg.Add(1) defer bc.wg.Done() @@ -1264,13 +1266,17 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } rawdb.WriteBlock(bc.db, block) - tds.SetBlockNr(block.NumberU64()) + if tds != nil { + tds.SetBlockNr(block.NumberU64()) + } ctx := bc.WithContext(context.Background(), block.Number()) - if err := state.CommitBlock(ctx, tds.DbStateWriter()); err != nil { - return NonStatTy, err + if stateDb != nil { + if err := stateDb.CommitBlock(ctx, tds.DbStateWriter()); err != nil { + return NonStatTy, err + } } - if bc.enableReceipts { + if bc.enableReceipts && !bc.cacheConfig.DownloadOnly { rawdb.WriteReceipts(bc.db, block.Hash(), block.NumberU64(), receipts) } @@ -1300,8 +1306,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } } // Write the positional metadata for transaction/receipt lookups and preimages - rawdb.WriteTxLookupEntries(bc.db, block) - rawdb.WritePreimages(bc.db, state.Preimages()) + if !bc.cacheConfig.DownloadOnly { + rawdb.WriteTxLookupEntries(bc.db, block) + } + if stateDb != nil && !bc.cacheConfig.DownloadOnly { + rawdb.WritePreimages(bc.db, stateDb.Preimages()) + } status = CanonStatTy //} else { @@ -1547,17 +1557,19 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, verif } readBlockNr := parentNumber var root common.Hash - if bc.trieDbState == nil { + if bc.trieDbState == nil && !bc.cacheConfig.DownloadOnly { if _, err = bc.GetTrieDbState(); err != nil { return k, events, coalescedLogs, err } } - root = bc.trieDbState.LastRoot() + if !bc.cacheConfig.DownloadOnly { + root = bc.trieDbState.LastRoot() + } var parentRoot common.Hash if parent != nil { parentRoot = parent.Root() } - if parent != nil && root != parentRoot { + if parent != nil && root != parentRoot && !bc.cacheConfig.DownloadOnly { log.Info("Rewinding from", "block", bc.CurrentBlock().NumberU64(), "to block", readBlockNr) if _, err = bc.db.Commit(); err != nil { log.Error("Could not commit chainDb before rewinding", "error", err) @@ -1591,38 +1603,44 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, verif return 0, events, coalescedLogs, err } } - stateDB := state.New(bc.trieDbState) - // Process block using the parent state as reference point. - //t0 := time.Now() - receipts, logs, usedGas, err := bc.processor.Process(block, stateDB, bc.trieDbState, bc.vmConfig) - //t1 := time.Now() - if err != nil { - bc.db.Rollback() - bc.trieDbState = nil - bc.reportBlock(block, receipts, err) - return k, events, coalescedLogs, err - } - // Update the metrics touched during block processing - /* - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them - - triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation - trieproc := statedb.AccountReads + statedb.AccountUpdates - trieproc += statedb.StorageReads + statedb.StorageUpdates - - blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash) - */ - - // Validate the state using the default validator - err = bc.Validator().ValidateState(block, parent, stateDB, bc.trieDbState, receipts, usedGas) - if err != nil { - bc.db.Rollback() - bc.trieDbState = nil - bc.reportBlock(block, receipts, err) - return k, events, coalescedLogs, err + var stateDB *state.IntraBlockState + var receipts types.Receipts + var logs []*types.Log + var usedGas uint64 + if !bc.cacheConfig.DownloadOnly { + stateDB = state.New(bc.trieDbState) + // Process block using the parent state as reference point. + //t0 := time.Now() + receipts, logs, usedGas, err = bc.processor.Process(block, stateDB, bc.trieDbState, bc.vmConfig) + //t1 := time.Now() + if err != nil { + bc.db.Rollback() + bc.trieDbState = nil + bc.reportBlock(block, receipts, err) + return k, events, coalescedLogs, err + } + // Update the metrics touched during block processing + /* + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them + + triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation + trieproc := statedb.AccountReads + statedb.AccountUpdates + trieproc += statedb.StorageReads + statedb.StorageUpdates + + blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash) + */ + + // Validate the state using the default validator + err = bc.Validator().ValidateState(block, parent, stateDB, bc.trieDbState, receipts, usedGas) + if err != nil { + bc.db.Rollback() + bc.trieDbState = nil + bc.reportBlock(block, receipts, err) + return k, events, coalescedLogs, err + } } proctime := time.Since(start) @@ -1693,7 +1711,9 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, verif bc.trieDbState = nil return 0, events, coalescedLogs, err } - bc.trieDbState.PruneTries(false) + if bc.trieDbState != nil { + bc.trieDbState.PruneTries(false) + } log.Info("Database", "size", bc.db.Size(), "written", written) } } diff --git a/eth/backend.go b/eth/backend.go index 1d464b63731433f1a7158ec5387f53ef26525ffa..06d445d56c67288cfb5849d2730ed15ba82b91f9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -186,6 +186,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { TrieDirtyLimit: config.TrieDirtyCache, TrieCleanNoPrefetch: config.NoPrefetch, TrieTimeLimit: config.TrieTimeout, + DownloadOnly: config.DownloadOnly, NoHistory: config.NoHistory, ArchiveSyncInterval: uint64(config.ArchiveSyncInterval), } diff --git a/eth/config.go b/eth/config.go index 71f829ac5959943ed41c5144fc993bb11a9284ae..024367e513bed3d2031bb5bb075190f140fc404d 100644 --- a/eth/config.go +++ b/eth/config.go @@ -98,7 +98,10 @@ type Config struct { NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - NoHistory bool + NoHistory bool + // DownloadOnly is set when the node does not need to process the blocks, but simply + // download them + DownloadOnly bool ArchiveSyncInterval int BlocksBeforePruning uint64 BlocksToPrune uint64