diff --git a/cmd/ronin/chaincmd.go b/cmd/ronin/chaincmd.go index b53a5c895..23a103d5d 100644 --- a/cmd/ronin/chaincmd.go +++ b/cmd/ronin/chaincmd.go @@ -87,6 +87,7 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to utils.CacheFlag, utils.SyncModeFlag, utils.GCModeFlag, + utils.NoPruningSideCarFlag, utils.SnapshotFlag, utils.CacheDatabaseFlag, utils.CacheGCFlag, diff --git a/cmd/ronin/main.go b/cmd/ronin/main.go index 5144bc14a..553796dd9 100644 --- a/cmd/ronin/main.go +++ b/cmd/ronin/main.go @@ -100,6 +100,7 @@ var ( utils.SyncModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, + utils.NoPruningSideCarFlag, utils.SnapshotFlag, utils.TxLookupLimitFlag, utils.TriesInMemoryFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 1a5377eeb..d2bcf4c82 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -225,6 +225,12 @@ var ( Value: "full", Category: flags.StateCategory, } + NoPruningSideCarFlag = &cli.BoolFlag{ + Name: "no-pruning-sidecar", + Usage: `Disable blob sidecar pruning in archive node`, + Value: true, + Category: flags.StateCategory, + } SnapshotFlag = &cli.BoolFlag{ Name: "snapshot", Usage: `Enables snapshot-database mode (default = enable)`, @@ -1907,6 +1913,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(GCModeFlag.Name) { cfg.NoPruning = ctx.String(GCModeFlag.Name) == "archive" } + if !cfg.NoPruning && ctx.IsSet(NoPruningSideCarFlag.Name) { + log.Warn(fmt.Sprintf("Flag --%s has no effect when gcmode is not archive", + NoPruningSideCarFlag.Name)) + } + if cfg.NoPruning && ctx.Bool(NoPruningSideCarFlag.Name) { + cfg.NoPruningSideCar = true + } if ctx.IsSet(CacheNoPrefetchFlag.Name) { cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name) } @@ -2305,14 +2318,20 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } + isArchive := ctx.String(GCModeFlag.Name) == "archive" + if !isArchive && ctx.IsSet(NoPruningSideCarFlag.Name) { + log.Warn(fmt.Sprintf("Flag --%s has no effect when gcmode is not archive", + NoPruningSideCarFlag.Name)) + } cache := &core.CacheConfig{ TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, - TrieDirtyDisabled: ctx.String(GCModeFlag.Name) == "archive", + TrieDirtyDisabled: isArchive, TrieTimeLimit: ethconfig.Defaults.TrieTimeout, SnapshotLimit: ethconfig.Defaults.SnapshotCache, Preimages: ctx.Bool(CachePreimagesFlag.Name), + NoPruningSideCar: isArchive && ctx.Bool(NoPruningSideCarFlag.Name), } if cache.TrieDirtyDisabled && !cache.Preimages { cache.Preimages = true diff --git a/core/blockchain.go b/core/blockchain.go index e8688443b..f16d23c2d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -139,6 +139,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 int // The number of tries is kept in memory before pruning + NoPruningSideCar bool // Whether to disable blob sidecar pruning SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } @@ -1486,7 +1487,7 @@ func (bc *BlockChain) reorgNeeded(localBlock *types.Block, localTd *big.Int, ext // pruneBlockSidecars prunes the sidecars of blocks that are older than the keep period func (bc *BlockChain) pruneBlockSidecars(db ethdb.KeyValueWriter, curBlock *types.Block) { - if curBlock.NumberU64() < uint64(bc.blobPrunePeriod) { + if bc.cacheConfig.NoPruningSideCar || curBlock.NumberU64() < uint64(bc.blobPrunePeriod) { return } pruneBlockNumber := curBlock.NumberU64() - uint64(bc.blobPrunePeriod) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 265393a69..7e4adb214 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4223,7 +4223,15 @@ func TestInsertChainWithSidecars(t *testing.T) { wg.Wait() } -func TestSidecarsPruning(t *testing.T) { +func TestSidecarPruning(t *testing.T) { + testSidecarsPruning(t, true) +} + +func TestNoSidecarPruning(t *testing.T) { + testSidecarsPruning(t, false) +} + +func testSidecarsPruning(t *testing.T, enabled bool) { var prunePeriod uint64 = 1000 privateKey, _ := crypto.GenerateKey() address := crypto.PubkeyToAddress(privateKey.PublicKey) @@ -4244,6 +4252,9 @@ func TestSidecarsPruning(t *testing.T) { if err != nil { t.Fatalf("Failed to create blockchain, err %s", err) } + if !enabled { + chain.cacheConfig.NoPruningSideCar = true + } chain.setBlobPrunePeriod(prunePeriod) signer := types.NewCancunSigner(chainConfig.ChainID) @@ -4309,8 +4320,14 @@ func TestSidecarsPruning(t *testing.T) { pruneBlockNumber := curBlockNumber - prunePeriod pruneBlockHash := chain.GetBlockByNumber(uint64(pruneBlockNumber)).Hash() sidecars := rawdb.ReadBlobSidecars(chain.db, pruneBlockHash, uint64(pruneBlockNumber)) - if sidecars != nil { - t.Fatalf("Sidecars should be pruned at block %d", curBlockNumber-prunePeriod) + if enabled { + if sidecars != nil { + t.Fatalf("Sidecars should be pruned at block %d", curBlockNumber-prunePeriod) + } + } else { + if sidecars == nil { + t.Fatalf("Sidecars must not be pruned at block %d", curBlockNumber-prunePeriod) + } } } } diff --git a/eth/backend.go b/eth/backend.go index 52f1b0f6b..f136042f9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -202,6 +202,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, TriesInMemory: config.TriesInMemory, + NoPruningSideCar: config.NoPruningSideCar, } ) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 5e6406912..c3c6eda0a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -143,6 +143,8 @@ 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 + NoPruningSideCar bool // Whether to disable blob sidecar pruning + TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. // Whitelist of required block number -> hash values to accept