@@ -150,7 +150,7 @@ type CodeSyncResult struct {
150
150
type nodeOp struct {
151
151
owner common.Hash // identifier of the trie (empty for account trie)
152
152
path []byte // path from the root to the specified node.
153
- blob []byte // the content of the node, nil means it's deletion
153
+ blob []byte // the content of the node ( nil for deletion)
154
154
hash common.Hash // hash of the node content (empty for node deletion)
155
155
}
156
156
@@ -256,13 +256,16 @@ func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallb
256
256
// parent for completion tracking. The given path is a unique node path in
257
257
// hex format and contain all the parent path if it's layered trie node.
258
258
func (s * Sync ) AddSubTrie (root common.Hash , path []byte , parent common.Hash , parentPath []byte , callback LeafCallback ) {
259
- // Short circuit if the trie is empty or already known
259
+ // Short circuit if the trie is empty.
260
260
if root == types .EmptyRootHash {
261
261
return
262
262
}
263
+ // Short circuit if the trie is already known.
263
264
owner , inner := ResolvePath (path )
264
- if s .hasNode (owner , inner , root ) {
265
+ if exist , mismatch := s .hasNode (owner , inner , root ); exist {
265
266
return
267
+ } else if mismatch {
268
+ s .membatch .delNode (owner , inner ) // remove the inconsistent node.
266
269
}
267
270
// Assemble the new sub-trie sync request
268
271
req := & nodeRequest {
@@ -424,9 +427,12 @@ func (s *Sync) Commit(dbw ethdb.Batch) error {
424
427
)
425
428
for _ , op := range s .membatch .nodes {
426
429
if op .isDelete () {
427
- // node deletion is only supported in path mode for which
428
- // node hash is not required.
429
- rawdb .DeleteTrieNode (dbw , op .owner , op .path , common.Hash {} /* unused */ , s .scheme )
430
+ // node deletion is not supported in path mode.
431
+ if op .owner == (common.Hash {}) {
432
+ rawdb .DeleteAccountTrieNode (dbw , op .path )
433
+ } else {
434
+ rawdb .DeleteStorageTrieNode (dbw , op .owner , op .path )
435
+ }
430
436
deletionGauge .Inc (1 )
431
437
} else {
432
438
if op .owner == (common.Hash {}) {
@@ -566,6 +572,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
566
572
var (
567
573
missing = make (chan * nodeRequest , len (children ))
568
574
pending sync.WaitGroup
575
+ batchMu sync.Mutex
569
576
)
570
577
for _ , child := range children {
571
578
// Notify any external watcher of a new key/value node
@@ -590,11 +597,14 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
590
597
go func (path []byte , hash common.Hash ) {
591
598
defer pending .Done ()
592
599
593
- // If database says duplicate, then at least the trie node is present
594
- // and we hold the assumption that it's NOT legacy contract code.
600
+ // Short circuit if the child node is already known.
595
601
owner , inner := ResolvePath (path )
596
- if s .hasNode (owner , inner , hash ) {
602
+ if exist , mismatch := s .hasNode (owner , inner , hash ); exist {
597
603
return
604
+ } else if mismatch {
605
+ batchMu .Lock ()
606
+ s .membatch .delNode (owner , inner ) // remove the inconsistent node
607
+ batchMu .Unlock ()
598
608
}
599
609
// Locally unknown node, schedule for retrieval
600
610
missing <- & nodeRequest {
@@ -667,38 +677,27 @@ func (s *Sync) commitCodeRequest(req *codeRequest) error {
667
677
return nil
668
678
}
669
679
670
- // hasNode reports if the specified trie node is present in database or not.
671
- //
672
- // Notably, the existent node should be wiped in path scheme if it's not matched
673
- // with the requested one, otherwise the persistent state will end up with a
674
- // weird situation that parent node is inconsistent with children while they
675
- // are all present in database.
676
- func (s * Sync ) hasNode (owner common.Hash , path []byte , root common.Hash ) bool {
677
- // If node is run with hash scheme, check the presence with node hash.
680
+ // hasNode reports whether the specified trie node is already present in the
681
+ // database. Additionally, it returns a flag in the path-based scheme if
682
+ // there is an inconsistent node existing at the specified path.
683
+ func (s * Sync ) hasNode (owner common.Hash , path []byte , root common.Hash ) (bool , bool ) {
684
+ // If node is running with hash scheme, check the presence with node hash.
678
685
if s .scheme == rawdb .HashScheme {
679
- return rawdb .HasLegacyTrieNode (s .database , root )
686
+ return rawdb .HasLegacyTrieNode (s .database , root ), false
680
687
}
681
- // If node is run with path scheme, check the presence with node path.
688
+ // If node is running with path scheme, check the presence with node path.
682
689
if owner == (common.Hash {}) {
683
690
blob , hash := rawdb .ReadAccountTrieNode (s .database , path )
684
691
if hash == root {
685
- return true
686
- }
687
- // Remove the inconsistent node before expanding the path.
688
- if len (blob ) != 0 {
689
- s .membatch .delNode (common.Hash {}, path )
692
+ return true , false
690
693
}
691
- return false
694
+ return false , len ( blob ) != 0 // flag if the inconsistent node is present
692
695
}
693
696
blob , hash := rawdb .ReadStorageTrieNode (s .database , owner , path )
694
697
if hash == root {
695
- return true
696
- }
697
- // Remove the inconsistent node before expanding the path.
698
- if len (blob ) != 0 {
699
- s .membatch .delNode (owner , path )
698
+ return true , false
700
699
}
701
- return false
700
+ return false , len ( blob ) != 0 // flag if the inconsistent node is present
702
701
}
703
702
704
703
// ResolvePath resolves the provided composite node path by separating the
0 commit comments