@@ -18,9 +18,11 @@ package main
18
18
19
19
import (
20
20
"bytes"
21
+ "encoding/binary"
21
22
"encoding/json"
22
23
"errors"
23
24
"fmt"
25
+ "math"
24
26
"os"
25
27
"slices"
26
28
"time"
@@ -33,6 +35,7 @@ import (
33
35
"github.com/ethereum/go-ethereum/core/state/snapshot"
34
36
"github.com/ethereum/go-ethereum/core/types"
35
37
"github.com/ethereum/go-ethereum/crypto"
38
+ "github.com/ethereum/go-ethereum/ethdb"
36
39
"github.com/ethereum/go-ethereum/log"
37
40
"github.com/ethereum/go-ethereum/rlp"
38
41
"github.com/ethereum/go-ethereum/trie"
@@ -63,6 +66,29 @@ two version states are available: genesis and the specific one.
63
66
The default pruning target is the HEAD-127 state.
64
67
65
68
WARNING: it's only supported in hash mode(--state.scheme=hash)".
69
+ ` ,
70
+ },
71
+ {
72
+ Name : "insecure-prune-pathdb" ,
73
+ Usage : "Prune all pathdb state data, it will break storage for fullnode, only suitable for fast node " +
74
+ "who do not need trie storage at all" ,
75
+ ArgsUsage : "" ,
76
+ Action : prunePathDB ,
77
+ Category : "MISCELLANEOUS COMMANDS" ,
78
+ Flags : []cli.Flag {
79
+ utils .DataDirFlag ,
80
+ utils .AncientFlag ,
81
+ },
82
+ Description : `
83
+ will prune all historical trie state data except genesis block.
84
+ All trie nodes will be deleted from the database.
85
+
86
+ It expects the genesis file as argument.
87
+
88
+ WARNING: It's necessary to delete the trie clean cache after the pruning.
89
+ If you specify another directory for the trie clean cache via "--cache.trie.journal"
90
+ during the use of Geth, please also specify it here for correct deletion. Otherwise
91
+ the trie clean cache with default directory will be deleted.
66
92
` ,
67
93
},
68
94
{
@@ -165,6 +191,101 @@ the expected order for the overlay tree migration.
165
191
}
166
192
)
167
193
194
+ // rangeCompactionThreshold is the minimal deleted entry number for
195
+ // triggering range compaction. It's a quite arbitrary number but just
196
+ // to avoid triggering range compaction because of small deletion.
197
+ const rangeCompactionThreshold = 1000000
198
+
199
+ func prunePathDB (ctx * cli.Context ) error {
200
+ stack , _ := makeConfigNode (ctx )
201
+ defer stack .Close ()
202
+
203
+ pruneDB := utils .MakeChainDatabase (ctx , stack , false )
204
+ defer pruneDB .Close ()
205
+
206
+ var (
207
+ count int
208
+ size common.StorageSize
209
+ pstart = time .Now ()
210
+ logged = time .Now ()
211
+ batch = pruneDB .NewBatch ()
212
+ iter = pruneDB .NewIterator (nil , nil )
213
+ stateIDPrefix = []byte ("L" )
214
+ )
215
+ for iter .Next () {
216
+ key := iter .Key ()
217
+ doDelete := false
218
+ switch {
219
+ case rawdb .IsLegacyTrieNode (key , iter .Value ()):
220
+ doDelete = true
221
+ case bytes .HasPrefix (key , stateIDPrefix ) && len (key ) == len (stateIDPrefix )+ common .HashLength :
222
+ doDelete = true
223
+ case rawdb .IsAccountTrieNode (key ):
224
+ doDelete = true
225
+ case rawdb .IsStorageTrieNode (key ):
226
+ doDelete = true
227
+ default :
228
+ }
229
+ if doDelete {
230
+ count += 1
231
+ size += common .StorageSize (len (key ) + len (iter .Value ()))
232
+ batch .Delete (key )
233
+
234
+ var eta time.Duration // Realistically will never remain uninited
235
+ if done := binary .BigEndian .Uint64 (key [:8 ]); done > 0 {
236
+ var (
237
+ left = math .MaxUint64 - binary .BigEndian .Uint64 (key [:8 ])
238
+ speed = done / uint64 (time .Since (pstart )/ time .Millisecond + 1 ) + 1 // +1s to avoid division by zero
239
+ )
240
+ eta = time .Duration (left / speed ) * time .Millisecond
241
+ }
242
+ if time .Since (logged ) > 8 * time .Second {
243
+ log .Info ("Pruning state data" , "nodes" , count , "size" , size ,
244
+ "elapsed" , common .PrettyDuration (time .Since (pstart )), "eta" , common .PrettyDuration (eta ))
245
+ logged = time .Now ()
246
+ }
247
+ // Recreate the iterator after every batch commit in order
248
+ // to allow the underlying compactor to delete the entries.
249
+ if batch .ValueSize () >= ethdb .IdealBatchSize {
250
+ batch .Write ()
251
+ batch .Reset ()
252
+
253
+ iter .Release ()
254
+ iter = pruneDB .NewIterator (nil , key )
255
+ }
256
+ }
257
+ }
258
+ if batch .ValueSize () > 0 {
259
+ batch .Write ()
260
+ batch .Reset ()
261
+ }
262
+ iter .Release ()
263
+ log .Info ("Pruned path db data" , "nodes" , count , "size" , size , "elapsed" , common .PrettyDuration (time .Since (pstart )))
264
+
265
+ // Start compactions, will remove the deleted data from the disk immediately.
266
+ // Note for small pruning, the compaction is skipped.
267
+ if count >= rangeCompactionThreshold {
268
+ cstart := time .Now ()
269
+ for b := 0x00 ; b <= 0xf0 ; b += 0x10 {
270
+ var (
271
+ start = []byte {byte (b )}
272
+ end = []byte {byte (b + 0x10 )}
273
+ )
274
+ if b == 0xf0 {
275
+ end = nil
276
+ }
277
+ log .Info ("Compacting database" , "range" , fmt .Sprintf ("%#x-%#x" , start , end ), "elapsed" , common .PrettyDuration (time .Since (cstart )))
278
+ if err := pruneDB .Compact (start , end ); err != nil {
279
+ log .Error ("Database compaction failed" , "error" , err )
280
+ return err
281
+ }
282
+ }
283
+ log .Info ("Database compaction finished" , "elapsed" , common .PrettyDuration (time .Since (cstart )))
284
+ }
285
+
286
+ return nil
287
+ }
288
+
168
289
// Deprecation: this command should be deprecated once the hash-based
169
290
// scheme is deprecated.
170
291
func pruneState (ctx * cli.Context ) error {
@@ -230,7 +351,7 @@ func verifyState(ctx *cli.Context) error {
230
351
NoBuild : true ,
231
352
AsyncBuild : false ,
232
353
}
233
- snaptree , err := snapshot .New (snapConfig , chaindb , triedb , headBlock .Root ())
354
+ snaptree , err := snapshot .New (snapConfig , chaindb , triedb , headBlock .Root (), false )
234
355
if err != nil {
235
356
log .Error ("Failed to open snapshot tree" , "err" , err )
236
357
return err
@@ -561,7 +682,7 @@ func dumpState(ctx *cli.Context) error {
561
682
NoBuild : true ,
562
683
AsyncBuild : false ,
563
684
}
564
- snaptree , err := snapshot .New (snapConfig , db , triedb , root )
685
+ snaptree , err := snapshot .New (snapConfig , db , triedb , root , false )
565
686
if err != nil {
566
687
return err
567
688
}
@@ -658,7 +779,7 @@ func snapshotExportPreimages(ctx *cli.Context) error {
658
779
NoBuild : true ,
659
780
AsyncBuild : false ,
660
781
}
661
- snaptree , err := snapshot .New (snapConfig , chaindb , triedb , root )
782
+ snaptree , err := snapshot .New (snapConfig , chaindb , triedb , root , false )
662
783
if err != nil {
663
784
return err
664
785
}
0 commit comments