diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ab2c16e329..76aa67b0f2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -315,33 +315,33 @@ var ( Value: uint(ethconfig.Defaults.NodeFullValueCheckpoint), Category: flags.StateCategory, } - // Partial statefulness flags + // Partial state flags (EIP-7928 BAL-based partial statefulness) PartialStateFlag = &cli.BoolFlag{ Name: "partial-state", - Usage: "Enable partial statefulness mode (reduced storage, requires BAL support)", - Category: flags.StateCategory, + Usage: "Enable partial state mode: sync all accounts but only storage for tracked contracts (requires EIP-7928 BAL)", + Category: flags.PartialStateCategory, } PartialStateContractsFlag = &cli.StringSliceFlag{ Name: "partial-state.contracts", - Usage: "Contracts to track storage for in partial state mode (comma-separated addresses)", - Category: flags.StateCategory, + Usage: "Contract addresses to track full storage for (comma-separated hex, e.g. 0xC02a...,0xA0b8...)", + Category: flags.PartialStateCategory, } PartialStateContractsFileFlag = &cli.StringFlag{ Name: "partial-state.contracts-file", - Usage: "JSON file containing contracts to track in partial state mode", - Category: flags.StateCategory, + Usage: `Path to JSON file listing contracts to track (format: {"version":1,"contracts":[{"address":"0x..."}]})`, + Category: flags.PartialStateCategory, } PartialStateBALRetentionFlag = &cli.Uint64Flag{ Name: "partial-state.bal-retention", - Usage: "Number of blocks to retain BAL history for reorg handling", + Usage: "Number of blocks to retain BAL history for reorg handling (minimum 256 for BLOCKHASH)", Value: ethconfig.Defaults.PartialState.BALRetention, - Category: flags.StateCategory, + Category: flags.PartialStateCategory, } PartialStateChainRetentionFlag = &cli.Uint64Flag{ Name: "partial-state.chain-retention", - Usage: "Number of recent blocks to retain bodies and receipts for (0 = keep all)", + Usage: "Number of recent blocks to retain bodies and receipts for (default = ~3.4 hours, 0 = keep all)", Value: ethconfig.DefaultChainRetention, - Category: flags.StateCategory, + Category: flags.PartialStateCategory, } TransactionHistoryFlag = &cli.Uint64Flag{ Name: "history.transactions", diff --git a/eth/backend.go b/eth/backend.go index 77f5eed805..d52ac72128 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -355,7 +355,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, fmt.Errorf("failed to load partial state contracts: %w", err) } partialFilter = partial.NewConfiguredFilter(config.PartialState.Contracts) - log.Info("Partial statefulness enabled", "contracts", len(config.PartialState.Contracts)) + log.Info("Partial state mode enabled", + "contracts", len(config.PartialState.Contracts), + "balRetention", config.PartialState.BALRetention, + "chainRetention", config.PartialState.ChainRetention) } if eth.handler, err = newHandler(&handlerConfig{ diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 73e777267c..c0f8e7bb69 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -229,27 +229,39 @@ type Config struct { // --partial-state.chain-retention. const DefaultChainRetention = 1024 -// PartialStateConfig configures partial statefulness mode. -// When enabled, the node stores all accounts but only storage for configured contracts. -// State updates are applied via Block Access Lists (BALs) per EIP-7928. +// PartialStateConfig configures partial statefulness mode (EIP-7928). +// +// When enabled, the node maintains the full account trie (all accounts, balances, +// nonces, code hashes) but only stores storage for explicitly tracked contracts. +// Blocks are processed using Block Access Lists (BALs) instead of re-executing +// transactions, dramatically reducing both storage requirements and CPU usage. +// +// Requires a network that supports EIP-7928 BAL propagation via the Engine API. type PartialStateConfig struct { - // Enabled activates partial statefulness mode + // Enabled activates partial state mode. When true, snap sync downloads + // all accounts but skips storage and bytecode for untracked contracts. Enabled bool - // Contracts is the list of contracts to track storage for + // Contracts is the list of contract addresses to track full storage for. + // Storage for contracts not in this list is skipped during sync, so + // eth_getStorageAt returns zero values and eth_call may produce incorrect + // results when touching untracked contracts. Contracts []common.Address // ContractsFile is the path to a JSON file containing contract addresses + // to track. Merged with Contracts above. See loadContractsFromFile for format. ContractsFile string `toml:",omitempty"` - // BALRetention is the number of blocks to keep BAL history for reorg handling + // BALRetention is the number of blocks to keep BAL history for. Must + // be at least 256 (BLOCKHASH opcode requires 256 blocks of history). + // Increase beyond 256 to support deeper reorg windows. Default 256. BALRetention uint64 // ChainRetention is the number of recent blocks to retain bodies and // receipts for. Older blocks only keep their headers. During sync, bodies // and receipts outside this window are never downloaded. After sync, the // freezer enforces a rolling window, deleting aged-out data. Set to 0 to - // keep all chain history. + // keep all chain history. Default 1024 (~3.4 hours at 12s/block). ChainRetention uint64 } @@ -339,8 +351,8 @@ func (c *PartialStateConfig) Validate() error { } // Validate BAL retention - if c.BALRetention < 64 { - return fmt.Errorf("BAL retention must be at least 64 blocks (for BLOCKHASH support), got %d", c.BALRetention) + if c.BALRetention < 256 { + return fmt.Errorf("BAL retention must be at least 256 blocks (for BLOCKHASH opcode support), got %d", c.BALRetention) } return nil diff --git a/internal/flags/categories.go b/internal/flags/categories.go index d426add55b..0f3b957139 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -19,24 +19,25 @@ package flags import "github.com/urfave/cli/v2" const ( - EthCategory = "ETHEREUM" - BeaconCategory = "BEACON CHAIN" - DevCategory = "DEVELOPER CHAIN" - StateCategory = "STATE HISTORY MANAGEMENT" - TxPoolCategory = "TRANSACTION POOL (EVM)" - BlobPoolCategory = "TRANSACTION POOL (BLOB)" - PerfCategory = "PERFORMANCE TUNING" - AccountCategory = "ACCOUNT" - APICategory = "API AND CONSOLE" - NetworkingCategory = "NETWORKING" - MinerCategory = "MINER" - GasPriceCategory = "GAS PRICE ORACLE" - VMCategory = "VIRTUAL MACHINE" - LoggingCategory = "LOGGING AND DEBUGGING" - MetricsCategory = "METRICS AND STATS" - MiscCategory = "MISC" - TestingCategory = "TESTING" - DeprecatedCategory = "ALIASED (deprecated)" + EthCategory = "ETHEREUM" + BeaconCategory = "BEACON CHAIN" + DevCategory = "DEVELOPER CHAIN" + StateCategory = "STATE HISTORY MANAGEMENT" + PartialStateCategory = "PARTIAL STATE" + TxPoolCategory = "TRANSACTION POOL (EVM)" + BlobPoolCategory = "TRANSACTION POOL (BLOB)" + PerfCategory = "PERFORMANCE TUNING" + AccountCategory = "ACCOUNT" + APICategory = "API AND CONSOLE" + NetworkingCategory = "NETWORKING" + MinerCategory = "MINER" + GasPriceCategory = "GAS PRICE ORACLE" + VMCategory = "VIRTUAL MACHINE" + LoggingCategory = "LOGGING AND DEBUGGING" + MetricsCategory = "METRICS AND STATS" + MiscCategory = "MISC" + TestingCategory = "TESTING" + DeprecatedCategory = "ALIASED (deprecated)" ) func init() {