@@ -112,7 +112,7 @@ will traverse the whole state from the given state root and will abort if any
112
112
referenced trie node or contract code is missing. This command can be used for
113
113
state integrity verification. The default checking target is the HEAD state.
114
114
115
- If accountHash or accountAddress is provided, traversal will start from that specific account.
115
+ If accountHash or accountAddress is provided, traversal will start from that specific account and continue through all subsequent accounts .
116
116
The format is auto-detected: 40/42 chars for address, 64/66 chars for hash.
117
117
118
118
It's also usable without snapshot enabled.
@@ -121,7 +121,7 @@ It's also usable without snapshot enabled.
121
121
{
122
122
Name : "traverse-rawstate" ,
123
123
Usage : "Traverse the state with given root hash and perform detailed verification" ,
124
- ArgsUsage : "<root>" ,
124
+ ArgsUsage : "<root> [accountHash|accountAddress] " ,
125
125
Action : traverseRawState ,
126
126
Flags : slices .Concat (utils .NetworkFlags , utils .DatabaseFlags ),
127
127
Description : `
@@ -131,6 +131,9 @@ trie node or contract code is missing. This command can be used for state integr
131
131
verification. The default checking target is the HEAD state. It's basically identical
132
132
to traverse-state, but the check granularity is smaller.
133
133
134
+ If accountHash or accountAddress is provided, traversal will start from that specific account and continue through all subsequent accounts.
135
+ The format is auto-detected: 40/42 chars for address, 64/66 chars for hash.
136
+
134
137
It's also usable without snapshot enabled.
135
138
` ,
136
139
},
@@ -293,37 +296,15 @@ func traverseState(ctx *cli.Context) error {
293
296
log .Error ("Failed to load head block" )
294
297
return errors .New ("no head block" )
295
298
}
296
- if ctx .NArg () > 2 {
297
- log .Error ("Too many arguments given" )
298
- return errors .New ("too many arguments" )
299
+
300
+ root , startKey , err := parseTraverseArgs (ctx )
301
+ if err != nil {
302
+ return err
299
303
}
300
- var (
301
- root common.Hash
302
- startKey []byte
303
- err error
304
- )
305
- if ctx .NArg () >= 1 {
306
- root , err = parseRoot (ctx .Args ().First ())
307
- if err != nil {
308
- log .Error ("Failed to resolve state root" , "err" , err )
309
- return err
310
- }
311
- } else {
304
+ if root == (common.Hash {}) {
312
305
root = headBlock .Root ()
313
306
}
314
307
315
- if ctx .NArg () == 2 {
316
- arg := ctx .Args ().Get (1 )
317
- switch len (arg ) {
318
- case 40 , 42 :
319
- startKey = crypto .Keccak256Hash (common .HexToAddress (arg ).Bytes ()).Bytes ()
320
- case 64 , 66 :
321
- startKey = common .HexToHash (arg ).Bytes ()
322
- default :
323
- return errors .New ("invalid account format: must be 40/42 chars for address or 64/66 chars for hash" )
324
- }
325
- }
326
-
327
308
log .Info ("Start traversing the state" , "root" , root .Hex (), "startKey" , common .Bytes2Hex (startKey ))
328
309
t , err := trie .NewStateTrie (trie .StateTrieID (root ), triedb )
329
310
if err != nil {
@@ -397,6 +378,34 @@ func traverseState(ctx *cli.Context) error {
397
378
return nil
398
379
}
399
380
381
+ func parseTraverseArgs (ctx * cli.Context ) (root common.Hash , startKey []byte , err error ) {
382
+ if ctx .NArg () > 2 {
383
+ err = errors .New ("too many arguments" )
384
+ return
385
+ }
386
+
387
+ if ctx .NArg () >= 1 {
388
+ root , err = parseRoot (ctx .Args ().First ())
389
+ if err != nil {
390
+ return
391
+ }
392
+ }
393
+
394
+ if ctx .NArg () == 2 {
395
+ arg := ctx .Args ().Get (1 )
396
+ switch len (arg ) {
397
+ case 40 , 42 :
398
+ startKey = crypto .Keccak256Hash (common .HexToAddress (arg ).Bytes ()).Bytes ()
399
+ case 64 , 66 :
400
+ startKey = common .HexToHash (arg ).Bytes ()
401
+ default :
402
+ err = errors .New ("invalid account format: must be 40/42 chars for address or 64/66 chars for hash" )
403
+ return
404
+ }
405
+ }
406
+ return root , startKey , nil
407
+ }
408
+
400
409
// traverseRawState is a helper function used for pruning verification.
401
410
// Basically it just iterates the trie, ensure all nodes and associated
402
411
// contract codes are present. It's basically identical to traverseState
@@ -416,25 +425,14 @@ func traverseRawState(ctx *cli.Context) error {
416
425
log .Error ("Failed to load head block" )
417
426
return errors .New ("no head block" )
418
427
}
419
- if ctx .NArg () > 1 {
420
- log .Error ("Too many arguments given" )
421
- return errors .New ("too many arguments" )
422
- }
423
- var (
424
- root common.Hash
425
- err error
426
- )
427
- if ctx .NArg () == 1 {
428
- root , err = parseRoot (ctx .Args ().First ())
429
- if err != nil {
430
- log .Error ("Failed to resolve state root" , "err" , err )
431
- return err
432
- }
433
- log .Info ("Start traversing the state" , "root" , root )
434
- } else {
435
- root = headBlock .Root ()
436
- log .Info ("Start traversing the state" , "root" , root , "number" , headBlock .NumberU64 ())
428
+
429
+ root , startKey , err := parseTraverseArgs (ctx )
430
+ if err != nil {
431
+ log .Error ("Failed to parse arguments" , "err" , err )
432
+ return err
437
433
}
434
+
435
+ log .Info ("Start traversing the state" , "root" , root .Hex (), "startKey" , common .Bytes2Hex (startKey ))
438
436
t , err := trie .NewStateTrie (trie .StateTrieID (root ), triedb )
439
437
if err != nil {
440
438
log .Error ("Failed to open trie" , "root" , root , "err" , err )
@@ -450,7 +448,7 @@ func traverseRawState(ctx *cli.Context) error {
450
448
hasher = crypto .NewKeccakState ()
451
449
got = make ([]byte , 32 )
452
450
)
453
- accIter , err := t .NodeIterator (nil )
451
+ accIter , err := t .NodeIterator (startKey )
454
452
if err != nil {
455
453
log .Error ("Failed to open iterator" , "root" , root , "err" , err )
456
454
return err
0 commit comments