Skip to content

Commit 9cf4cb7

Browse files
committed
Merge remote-tracking branch 'origin/time-based-pruning' into shutdown-markers
2 parents ef4387e + 21d73e3 commit 9cf4cb7

10 files changed

+112
-9
lines changed

core/blockchain.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ const (
9191
txLookupCacheLimit = 1024
9292
maxFutureBlocks = 256
9393
maxTimeFutureBlocks = 30
94-
TriesInMemory = 128
9594

9695
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
9796
//
@@ -132,12 +131,21 @@ type CacheConfig struct {
132131
SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory
133132
Preimages bool // Whether to store preimage of trie key to the disk
134133

134+
// Arbitrum: configure GC window
135+
TriesInMemory uint64 // Height difference before which a trie may not be garbage-collected
136+
TrieRetention time.Duration // Time limit before which a trie may not be garbage-collected
137+
135138
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
136139
}
137140

138141
// defaultCacheConfig are the default caching values if none are specified by the
139142
// user (also used during testing).
140143
var defaultCacheConfig = &CacheConfig{
144+
145+
// Arbitrum Config Options
146+
TriesInMemory: 128,
147+
TrieRetention: 30 * time.Minute,
148+
141149
TrieCleanLimit: 256,
142150
TrieDirtyLimit: 256,
143151
TrieTimeLimit: 5 * time.Minute,
@@ -862,6 +870,9 @@ func (bc *BlockChain) Stop() {
862870
}
863871
}
864872

873+
// Arbitrum: only discard tries sufficiently old in both time and height
874+
retain := bc.FindRetentionBound()
875+
865876
// Ensure the state of a recent block is also stored to disk before exiting.
866877
// We're writing three different states to catch different restart scenarios:
867878
// - HEAD: So we don't need to reprocess any blocks in the general case
@@ -870,7 +881,7 @@ func (bc *BlockChain) Stop() {
870881
if !bc.cacheConfig.TrieDirtyDisabled {
871882
triedb := bc.stateCache.TrieDB()
872883

873-
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
884+
for _, offset := range []uint64{0, 1, retain - 1} {
874885
if number := bc.CurrentBlock().NumberU64(); number > offset {
875886
recent := bc.GetBlockByNumber(number - offset)
876887
if recent.Root() == (common.Hash{}) {
@@ -1275,6 +1286,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
12751286
}
12761287
triedb := bc.stateCache.TrieDB()
12771288

1289+
// Arbitrum: only discard tries sufficiently old in both time and height
1290+
retain := bc.FindRetentionBound()
1291+
12781292
// If we're running an archive node, always flush
12791293
if bc.cacheConfig.TrieDirtyDisabled {
12801294
return triedb.Commit(root, false, nil)
@@ -1283,7 +1297,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
12831297
triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
12841298
bc.triegc.Push(root, -int64(block.NumberU64()))
12851299

1286-
if current := block.NumberU64(); current > TriesInMemory {
1300+
if current := block.NumberU64(); current > retain {
12871301
// If we exceeded our memory allowance, flush matured singleton nodes to disk
12881302
var (
12891303
nodes, imgs = triedb.Size()
@@ -1293,7 +1307,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
12931307
triedb.Cap(limit - ethdb.IdealBatchSize)
12941308
}
12951309
// Find the next state trie we need to commit
1296-
chosen := current - TriesInMemory
1310+
chosen := current - retain
12971311

12981312
// If we exceeded out time allowance, flush an entire trie to disk
12991313
if bc.gcproc > bc.cacheConfig.TrieTimeLimit {
@@ -1305,8 +1319,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13051319
} else {
13061320
// If we're exceeding limits but haven't reached a large enough memory gap,
13071321
// warn the user that the system is becoming unstable.
1308-
if chosen < lastWrite+TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
1309-
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory)
1322+
if chosen < lastWrite+retain && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit {
1323+
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/float64(retain))
13101324
}
13111325
// Flush an entire trie and restart the counters
13121326
triedb.Commit(header.Root, true, nil)

core/blockchain_arbitrum.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,52 @@ func (bc *BlockChain) ClipToPostNitroGenesis(blockNum rpc.BlockNumber) (rpc.Bloc
5454
}
5555
return blockNum, currentBlock
5656
}
57+
58+
// finds the number of blocks that aren't prunable
59+
func (bc *BlockChain) FindRetentionBound() uint64 {
60+
minimumSpan := bc.cacheConfig.TriesInMemory
61+
minimumAge := uint64(bc.cacheConfig.TrieRetention.Seconds())
62+
63+
saturatingCast := func(value int64) uint64 {
64+
if value < 0 {
65+
return 0
66+
}
67+
return uint64(value)
68+
}
69+
70+
// enforce that the block be sufficiently deep
71+
current := bc.CurrentBlock()
72+
heightBound := saturatingCast(int64(current.NumberU64()) - int64(minimumSpan) + 1)
73+
74+
// find the left bound to our subsequent binary search
75+
timeBound := heightBound
76+
leap := int64(1)
77+
for timeBound > 0 {
78+
age := current.Time() - bc.GetBlockByNumber(uint64(timeBound)).Time()
79+
if age > minimumAge {
80+
break
81+
}
82+
timeBound = saturatingCast(int64(timeBound) - leap)
83+
leap *= 2
84+
}
85+
if timeBound == heightBound {
86+
return current.NumberU64() - timeBound + 1
87+
}
88+
89+
// Algo: binary search on the interval [a, b] for the first prunable block
90+
// Timebound is a prunable block, if one exists.
91+
// We want to find the first block that's not prunable.
92+
//
93+
a := timeBound // a prunable block, if possible
94+
b := heightBound // not prunable
95+
for a+1 < b {
96+
mid := a/2 + b/2 // a < mid < b
97+
age := current.Time() - bc.GetBlockByNumber(mid).Time()
98+
if age <= minimumAge {
99+
b = mid // mid is not prunable and less than b
100+
} else {
101+
a = mid // mid is prunable, but might equal a
102+
}
103+
}
104+
return current.NumberU64() - a
105+
}

core/blockchain_repair_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,11 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
17671767
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
17681768
engine = ethash.NewFullFaker()
17691769
config = &CacheConfig{
1770+
1771+
// Arbitrum
1772+
TriesInMemory: 128,
1773+
TrieRetention: 30 * time.Minute,
1774+
17701775
TrieCleanLimit: 256,
17711776
TrieDirtyLimit: 256,
17721777
TrieTimeLimit: 5 * time.Minute,
@@ -1891,6 +1896,11 @@ func TestIssue23496(t *testing.T) {
18911896
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
18921897
engine = ethash.NewFullFaker()
18931898
config = &CacheConfig{
1899+
1900+
// Arbitrum
1901+
TriesInMemory: 128,
1902+
TrieRetention: 30 * time.Minute,
1903+
18941904
TrieCleanLimit: 256,
18951905
TrieDirtyLimit: 256,
18961906
TrieTimeLimit: 5 * time.Minute,

core/blockchain_sethead_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,11 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
19671967
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
19681968
engine = ethash.NewFullFaker()
19691969
config = &CacheConfig{
1970+
1971+
// Arbitrum
1972+
TriesInMemory: 128,
1973+
TrieRetention: 30 * time.Minute,
1974+
19701975
TrieCleanLimit: 256,
19711976
TrieDirtyLimit: 256,
19721977
TrieTimeLimit: 5 * time.Minute,

core/blockchain_snapshot_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
292292

293293
// Insert a few more blocks without enabling snapshot
294294
var cacheConfig = &CacheConfig{
295+
296+
// Arbitrum
297+
TriesInMemory: 128,
298+
TrieRetention: 30 * time.Minute,
299+
295300
TrieCleanLimit: 256,
296301
TrieDirtyLimit: 256,
297302
TrieTimeLimit: 5 * time.Minute,
@@ -363,6 +368,11 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
363368
chain.Stop()
364369

365370
config := &CacheConfig{
371+
372+
// Arbitrum
373+
TriesInMemory: 128,
374+
TrieRetention: 30 * time.Minute,
375+
366376
TrieCleanLimit: 256,
367377
TrieDirtyLimit: 256,
368378
TrieTimeLimit: 5 * time.Minute,
@@ -378,6 +388,11 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
378388

379389
// Restart the chain, the wiper should starts working
380390
config = &CacheConfig{
391+
392+
// Arbitrum
393+
TriesInMemory: 128,
394+
TrieRetention: 30 * time.Minute,
395+
381396
TrieCleanLimit: 256,
382397
TrieDirtyLimit: 256,
383398
TrieTimeLimit: 5 * time.Minute,

eth/backend.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
192192
EnablePreimageRecording: config.EnablePreimageRecording,
193193
}
194194
cacheConfig = &core.CacheConfig{
195+
196+
// Arbitrum
197+
TriesInMemory: 128,
198+
TrieRetention: 30 * time.Minute,
199+
195200
TrieCleanLimit: config.TrieCleanCache,
196201
TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal),
197202
TrieCleanRejournal: config.TrieCleanCacheRejournal,

eth/gasprice/gasprice_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
145145
// Construct testing chain
146146
diskdb := rawdb.NewMemoryDatabase()
147147
gspec.Commit(diskdb)
148-
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil)
148+
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true, TriesInMemory: 128}, gspec.Config, engine, vm.Config{}, nil, nil)
149149
if err != nil {
150150
t.Fatalf("Failed to create local chain, %v", err)
151151
}

eth/tracers/api_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
7676
// Import the canonical chain
7777
gspec.MustCommit(backend.chaindb)
7878
cacheConfig := &core.CacheConfig{
79+
80+
// Arbitrum
81+
TriesInMemory: 128,
82+
TrieRetention: 30 * time.Minute,
83+
7984
TrieCleanLimit: 256,
8085
TrieDirtyLimit: 256,
8186
TrieTimeLimit: 5 * time.Minute,

miner/worker_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
136136
}
137137
genesis := gspec.MustCommit(db)
138138

139-
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil)
139+
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true, TriesInMemory: 128}, gspec.Config, engine, vm.Config{}, nil, nil)
140140
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
141141

142142
// Generate a small n-block chain and an uncle block for it

tests/block_test_util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func (t *BlockTest) Run(snapshotter bool) error {
122122
} else {
123123
engine = ethash.NewShared()
124124
}
125-
cache := &core.CacheConfig{TrieCleanLimit: 0}
125+
cache := &core.CacheConfig{TrieCleanLimit: 0, TriesInMemory: 128}
126126
if snapshotter {
127127
cache.SnapshotLimit = 1
128128
cache.SnapshotWait = true

0 commit comments

Comments
 (0)