Skip to content

Commit a9ab76c

Browse files
authored
Merge pull request #210 from deep-stack/pm-removed-storage-nodes
Add diffs for storage nodes of destroyed contracts
2 parents 2aaf6bc + b351f8f commit a9ab76c

File tree

11 files changed

+544
-233
lines changed

11 files changed

+544
-233
lines changed

statediff/builder.go

Lines changed: 146 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args types2.StateRo
202202
// a map of their leafkey to all the accounts that were touched and exist at A
203203
diffAccountsAtA, err := sdb.deletedOrUpdatedState(
204204
oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}),
205-
diffPathsAtB, params.watchedAddressesLeafKeys, output)
205+
diffAccountsAtB, diffPathsAtB, params.watchedAddressesLeafKeys,
206+
params.IntermediateStorageNodes, output)
206207
if err != nil {
207208
return fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
208209
}
@@ -256,7 +257,8 @@ func (sdb *builder) buildStateDiffWithoutIntermediateStateNodes(args types2.Stat
256257
// a map of their leafkey to all the accounts that were touched and exist at A
257258
diffAccountsAtA, err := sdb.deletedOrUpdatedState(
258259
oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}),
259-
diffPathsAtB, params.watchedAddressesLeafKeys, output)
260+
diffAccountsAtB, diffPathsAtB, params.watchedAddressesLeafKeys,
261+
params.IntermediateStorageNodes, output)
260262
if err != nil {
261263
return fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err)
262264
}
@@ -386,7 +388,7 @@ func (sdb *builder) createdAndUpdatedStateWithIntermediateNodes(a, b trie.NodeIt
386388

387389
// deletedOrUpdatedState returns a slice of all the pathes that are emptied at B
388390
// and a mapping of their leafkeys to all the accounts that exist in a different state at A than B
389-
func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB map[string]bool, watchedAddressesLeafKeys map[common.Hash]struct{}, output types2.StateNodeSink) (types2.AccountMap, error) {
391+
func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffAccountsAtB types2.AccountMap, diffPathsAtB map[string]bool, watchedAddressesLeafKeys map[common.Hash]struct{}, intermediateStorageNodes bool, output types2.StateNodeSink) (types2.AccountMap, error) {
390392
diffAccountAtA := make(types2.AccountMap)
391393
it, _ := trie.NewDifferenceIterator(b, a)
392394
for it.Next(true) {
@@ -419,14 +421,36 @@ func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB m
419421
}
420422
// if this node's path did not show up in diffPathsAtB
421423
// that means the node at this path was deleted (or moved) in B
422-
// emit an empty "removed" diff to signify as such
423424
if _, ok := diffPathsAtB[common.Bytes2Hex(node.Path)]; !ok {
424-
if err := output(types2.StateNode{
425-
Path: node.Path,
426-
NodeValue: []byte{},
427-
NodeType: types2.Removed,
428-
LeafKey: leafKey,
429-
}); err != nil {
425+
var diff types2.StateNode
426+
// if this node's leaf key also did not show up in diffAccountsAtB
427+
// that means the node was deleted
428+
// in that case, emit an empty "removed" diff state node
429+
// include empty "removed" diff storage nodes for all the storage slots
430+
if _, ok := diffAccountsAtB[common.Bytes2Hex(leafKey)]; !ok {
431+
diff = types2.StateNode{
432+
NodeType: types2.Removed,
433+
Path: node.Path,
434+
LeafKey: leafKey,
435+
NodeValue: []byte{},
436+
}
437+
438+
var storageDiffs []types2.StorageNode
439+
err := sdb.buildRemovedAccountStorageNodes(account.Root, intermediateStorageNodes, storageNodeAppender(&storageDiffs))
440+
if err != nil {
441+
return nil, fmt.Errorf("failed building storage diffs for removed node %x\r\nerror: %v", node.Path, err)
442+
}
443+
diff.StorageNodes = storageDiffs
444+
} else {
445+
// emit an empty "removed" diff with empty leaf key if the account was moved
446+
diff = types2.StateNode{
447+
NodeType: types2.Removed,
448+
Path: node.Path,
449+
NodeValue: []byte{},
450+
}
451+
}
452+
453+
if err := output(diff); err != nil {
430454
return nil, err
431455
}
432456
}
@@ -548,7 +572,6 @@ func (sdb *builder) buildStorageNodesEventual(sr common.Hash, intermediateNodes
548572
}
549573

550574
// buildStorageNodesFromTrie returns all the storage diff node objects in the provided node interator
551-
// if any storage keys are provided it will only return those leaf nodes
552575
// including intermediate nodes can be turned on or off
553576
func (sdb *builder) buildStorageNodesFromTrie(it trie.NodeIterator, intermediateNodes bool, output types2.StorageNodeSink) error {
554577
for it.Next(true) {
@@ -591,6 +614,68 @@ func (sdb *builder) buildStorageNodesFromTrie(it trie.NodeIterator, intermediate
591614
return it.Error()
592615
}
593616

617+
// buildRemovedAccountStorageNodes builds the "removed" diffs for all the storage nodes for a destroyed account
618+
func (sdb *builder) buildRemovedAccountStorageNodes(sr common.Hash, intermediateNodes bool, output types2.StorageNodeSink) error {
619+
if bytes.Equal(sr.Bytes(), emptyContractRoot.Bytes()) {
620+
return nil
621+
}
622+
log.Debug("Storage Root For Removed Diffs", "root", sr.Hex())
623+
sTrie, err := sdb.stateCache.OpenTrie(sr)
624+
if err != nil {
625+
log.Info("error in build removed account storage diffs", "error", err)
626+
return err
627+
}
628+
it := sTrie.NodeIterator(make([]byte, 0))
629+
err = sdb.buildRemovedStorageNodesFromTrie(it, intermediateNodes, output)
630+
if err != nil {
631+
return err
632+
}
633+
return nil
634+
}
635+
636+
// buildRemovedStorageNodesFromTrie returns diffs for all the storage nodes in the provided node interator
637+
// including intermediate nodes can be turned on or off
638+
func (sdb *builder) buildRemovedStorageNodesFromTrie(it trie.NodeIterator, intermediateNodes bool, output types2.StorageNodeSink) error {
639+
for it.Next(true) {
640+
// skip value nodes
641+
if it.Leaf() || bytes.Equal(nullHashBytes, it.Hash().Bytes()) {
642+
continue
643+
}
644+
node, nodeElements, err := trie_helpers.ResolveNode(it, sdb.stateCache.TrieDB())
645+
if err != nil {
646+
return err
647+
}
648+
switch node.NodeType {
649+
case types2.Leaf:
650+
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
651+
valueNodePath := append(node.Path, partialPath...)
652+
encodedPath := trie.HexToCompact(valueNodePath)
653+
leafKey := encodedPath[1:]
654+
if err := output(types2.StorageNode{
655+
NodeType: types2.Removed,
656+
Path: node.Path,
657+
NodeValue: []byte{},
658+
LeafKey: leafKey,
659+
}); err != nil {
660+
return err
661+
}
662+
case types2.Extension, types2.Branch:
663+
if intermediateNodes {
664+
if err := output(types2.StorageNode{
665+
NodeType: types2.Removed,
666+
Path: node.Path,
667+
NodeValue: []byte{},
668+
}); err != nil {
669+
return err
670+
}
671+
}
672+
default:
673+
return fmt.Errorf("unexpected node type %s", node.NodeType)
674+
}
675+
}
676+
return it.Error()
677+
}
678+
594679
// buildStorageNodesIncremental builds the storage diff node objects for all nodes that exist in a different state at B than A
595680
func (sdb *builder) buildStorageNodesIncremental(oldSR common.Hash, newSR common.Hash, intermediateNodes bool, output types2.StorageNodeSink) error {
596681
if bytes.Equal(newSR.Bytes(), oldSR.Bytes()) {
@@ -606,22 +691,23 @@ func (sdb *builder) buildStorageNodesIncremental(oldSR common.Hash, newSR common
606691
return err
607692
}
608693

609-
diffPathsAtB, err := sdb.createdAndUpdatedStorage(
694+
diffSlotsAtB, diffPathsAtB, err := sdb.createdAndUpdatedStorage(
610695
oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}),
611696
intermediateNodes, output)
612697
if err != nil {
613698
return err
614699
}
615700
err = sdb.deletedOrUpdatedStorage(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}),
616-
diffPathsAtB, intermediateNodes, output)
701+
diffSlotsAtB, diffPathsAtB, intermediateNodes, output)
617702
if err != nil {
618703
return err
619704
}
620705
return nil
621706
}
622707

623-
func (sdb *builder) createdAndUpdatedStorage(a, b trie.NodeIterator, intermediateNodes bool, output types2.StorageNodeSink) (map[string]bool, error) {
708+
func (sdb *builder) createdAndUpdatedStorage(a, b trie.NodeIterator, intermediateNodes bool, output types2.StorageNodeSink) (map[string]bool, map[string]bool, error) {
624709
diffPathsAtB := make(map[string]bool)
710+
diffSlotsAtB := make(map[string]bool)
625711
it, _ := trie.NewDifferenceIterator(a, b)
626712
for it.Next(true) {
627713
// skip value nodes
@@ -630,21 +716,22 @@ func (sdb *builder) createdAndUpdatedStorage(a, b trie.NodeIterator, intermediat
630716
}
631717
node, nodeElements, err := trie_helpers.ResolveNode(it, sdb.stateCache.TrieDB())
632718
if err != nil {
633-
return nil, err
719+
return nil, nil, err
634720
}
635721
switch node.NodeType {
636722
case types2.Leaf:
637723
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
638724
valueNodePath := append(node.Path, partialPath...)
639725
encodedPath := trie.HexToCompact(valueNodePath)
640726
leafKey := encodedPath[1:]
727+
diffSlotsAtB[common.Bytes2Hex(leafKey)] = true
641728
if err := output(types2.StorageNode{
642729
NodeType: node.NodeType,
643730
Path: node.Path,
644731
NodeValue: node.NodeValue,
645732
LeafKey: leafKey,
646733
}); err != nil {
647-
return nil, err
734+
return nil, nil, err
648735
}
649736
case types2.Extension, types2.Branch:
650737
if intermediateNodes {
@@ -653,18 +740,18 @@ func (sdb *builder) createdAndUpdatedStorage(a, b trie.NodeIterator, intermediat
653740
Path: node.Path,
654741
NodeValue: node.NodeValue,
655742
}); err != nil {
656-
return nil, err
743+
return nil, nil, err
657744
}
658745
}
659746
default:
660-
return nil, fmt.Errorf("unexpected node type %s", node.NodeType)
747+
return nil, nil, fmt.Errorf("unexpected node type %s", node.NodeType)
661748
}
662749
diffPathsAtB[common.Bytes2Hex(node.Path)] = true
663750
}
664-
return diffPathsAtB, it.Error()
751+
return diffSlotsAtB, diffPathsAtB, it.Error()
665752
}
666753

667-
func (sdb *builder) deletedOrUpdatedStorage(a, b trie.NodeIterator, diffPathsAtB map[string]bool, intermediateNodes bool, output types2.StorageNodeSink) error {
754+
func (sdb *builder) deletedOrUpdatedStorage(a, b trie.NodeIterator, diffSlotsAtB, diffPathsAtB map[string]bool, intermediateNodes bool, output types2.StorageNodeSink) error {
668755
it, _ := trie.NewDifferenceIterator(b, a)
669756
for it.Next(true) {
670757
// skip value nodes
@@ -675,34 +762,53 @@ func (sdb *builder) deletedOrUpdatedStorage(a, b trie.NodeIterator, diffPathsAtB
675762
if err != nil {
676763
return err
677764
}
678-
// if this node path showed up in diffPathsAtB
679-
// that means this node was updated at B and we already have the updated diff for it
680-
// otherwise that means this node was deleted in B and we need to add a "removed" diff to represent that event
681-
if _, ok := diffPathsAtB[common.Bytes2Hex(node.Path)]; ok {
682-
continue
683-
}
765+
684766
switch node.NodeType {
685767
case types2.Leaf:
686768
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
687769
valueNodePath := append(node.Path, partialPath...)
688770
encodedPath := trie.HexToCompact(valueNodePath)
689771
leafKey := encodedPath[1:]
690-
if err := output(types2.StorageNode{
691-
NodeType: types2.Removed,
692-
Path: node.Path,
693-
NodeValue: []byte{},
694-
LeafKey: leafKey,
695-
}); err != nil {
696-
return err
772+
773+
// if this node's path did not show up in diffPathsAtB
774+
// that means the node at this path was deleted (or moved) in B
775+
if _, ok := diffPathsAtB[common.Bytes2Hex(node.Path)]; !ok {
776+
// if this node's leaf key also did not show up in diffSlotsAtB
777+
// that means the node was deleted
778+
// in that case, emit an empty "removed" diff storage node
779+
if _, ok := diffSlotsAtB[common.Bytes2Hex(leafKey)]; !ok {
780+
if err := output(types2.StorageNode{
781+
NodeType: types2.Removed,
782+
Path: node.Path,
783+
NodeValue: []byte{},
784+
LeafKey: leafKey,
785+
}); err != nil {
786+
return err
787+
}
788+
} else {
789+
// emit an empty "removed" diff with empty leaf key if the account was moved
790+
if err := output(types2.StorageNode{
791+
NodeType: types2.Removed,
792+
Path: node.Path,
793+
NodeValue: []byte{},
794+
}); err != nil {
795+
return err
796+
}
797+
}
697798
}
698799
case types2.Extension, types2.Branch:
699-
if intermediateNodes {
700-
if err := output(types2.StorageNode{
701-
NodeType: types2.Removed,
702-
Path: node.Path,
703-
NodeValue: []byte{},
704-
}); err != nil {
705-
return err
800+
// if this node's path did not show up in diffPathsAtB
801+
// that means the node at this path was deleted in B
802+
// in that case, emit an empty "removed" diff storage node
803+
if _, ok := diffPathsAtB[common.Bytes2Hex(node.Path)]; !ok {
804+
if intermediateNodes {
805+
if err := output(types2.StorageNode{
806+
NodeType: types2.Removed,
807+
Path: node.Path,
808+
NodeValue: []byte{},
809+
}); err != nil {
810+
return err
811+
}
706812
}
707813
}
708814
default:

0 commit comments

Comments
 (0)