@@ -19,6 +19,7 @@ package trie
19
19
import (
20
20
"errors"
21
21
"fmt"
22
+ "sync"
22
23
23
24
"github.com/ethereum/go-ethereum/common"
24
25
"github.com/ethereum/go-ethereum/common/prque"
@@ -381,26 +382,26 @@ func (s *Sync) scheduleCodeRequest(req *codeRequest) {
381
382
// retrieval scheduling.
382
383
func (s * Sync ) children (req * nodeRequest , object node ) ([]* nodeRequest , error ) {
383
384
// Gather all the children of the node, irrelevant whether known or not
384
- type child struct {
385
+ type childNode struct {
385
386
path []byte
386
387
node node
387
388
}
388
- var children []child
389
+ var children []childNode
389
390
390
391
switch node := (object ).(type ) {
391
392
case * shortNode :
392
393
key := node .Key
393
394
if hasTerm (key ) {
394
395
key = key [:len (key )- 1 ]
395
396
}
396
- children = []child {{
397
+ children = []childNode {{
397
398
node : node .Val ,
398
399
path : append (append ([]byte (nil ), req .path ... ), key ... ),
399
400
}}
400
401
case * fullNode :
401
402
for i := 0 ; i < 17 ; i ++ {
402
403
if node .Children [i ] != nil {
403
- children = append (children , child {
404
+ children = append (children , childNode {
404
405
node : node .Children [i ],
405
406
path : append (append ([]byte (nil ), req .path ... ), byte (i )),
406
407
})
@@ -410,7 +411,10 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
410
411
panic (fmt .Sprintf ("unknown node: %+v" , node ))
411
412
}
412
413
// Iterate over the children, and request all unknown ones
413
- requests := make ([]* nodeRequest , 0 , len (children ))
414
+ var (
415
+ missing = make (chan * nodeRequest , len (children ))
416
+ pending sync.WaitGroup
417
+ )
414
418
for _ , child := range children {
415
419
// Notify any external watcher of a new key/value node
416
420
if req .callback != nil {
@@ -433,19 +437,36 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
433
437
if s .membatch .hasNode (child .path ) {
434
438
continue
435
439
}
436
- // If database says duplicate, then at least the trie node is present
437
- // and we hold the assumption that it's NOT legacy contract code.
438
- chash := common .BytesToHash (node )
439
- if rawdb .HasTrieNode (s .database , chash ) {
440
- continue
441
- }
442
- // Locally unknown node, schedule for retrieval
443
- requests = append (requests , & nodeRequest {
444
- path : child .path ,
445
- hash : chash ,
446
- parent : req ,
447
- callback : req .callback ,
448
- })
440
+ // Check the presence of children concurrently
441
+ pending .Add (1 )
442
+ go func (child childNode ) {
443
+ defer pending .Done ()
444
+
445
+ // If database says duplicate, then at least the trie node is present
446
+ // and we hold the assumption that it's NOT legacy contract code.
447
+ chash := common .BytesToHash (node )
448
+ if rawdb .HasTrieNode (s .database , chash ) {
449
+ return
450
+ }
451
+ // Locally unknown node, schedule for retrieval
452
+ missing <- & nodeRequest {
453
+ path : child .path ,
454
+ hash : chash ,
455
+ parent : req ,
456
+ callback : req .callback ,
457
+ }
458
+ }(child )
459
+ }
460
+ }
461
+ pending .Wait ()
462
+
463
+ requests := make ([]* nodeRequest , 0 , len (children ))
464
+ for done := false ; ! done ; {
465
+ select {
466
+ case miss := <- missing :
467
+ requests = append (requests , miss )
468
+ default :
469
+ done = true
449
470
}
450
471
}
451
472
return requests , nil
0 commit comments