@@ -19,6 +19,7 @@ package trie
19
19
import (
20
20
"fmt"
21
21
"reflect"
22
+ "sort"
22
23
"strings"
23
24
24
25
"github.com/ethereum/go-ethereum/common"
@@ -40,8 +41,8 @@ var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size())
40
41
41
42
// memorySize returns the total memory size used by this node.
42
43
// nolint:unused
43
- func (n * memoryNode ) memorySize (key int ) int {
44
- return int (n .size ) + memoryNodeSize + key
44
+ func (n * memoryNode ) memorySize (pathlen int ) int {
45
+ return int (n .size ) + memoryNodeSize + pathlen
45
46
}
46
47
47
48
// rlp returns the raw rlp encoded blob of the cached trie node, either directly
@@ -64,7 +65,13 @@ func (n *memoryNode) obj() node {
64
65
return expandNode (n .hash [:], n .node )
65
66
}
66
67
68
+ // isDeleted returns the indicator if the node is marked as deleted.
69
+ func (n * memoryNode ) isDeleted () bool {
70
+ return n .hash == (common.Hash {})
71
+ }
72
+
67
73
// nodeWithPrev wraps the memoryNode with the previous node value.
74
+ // nolint: unused
68
75
type nodeWithPrev struct {
69
76
* memoryNode
70
77
prev []byte // RLP-encoded previous value, nil means it's non-existent
@@ -79,81 +86,77 @@ func (n *nodeWithPrev) unwrap() *memoryNode {
79
86
// memorySize returns the total memory size used by this node. It overloads
80
87
// the function in memoryNode by counting the size of previous value as well.
81
88
// nolint: unused
82
- func (n * nodeWithPrev ) memorySize (key int ) int {
83
- return n .memoryNode .memorySize (key ) + len (n .prev )
84
- }
85
-
86
- // nodesWithOrder represents a collection of dirty nodes which includes
87
- // newly-inserted and updated nodes. The modification order of all nodes
88
- // is represented by order list.
89
- type nodesWithOrder struct {
90
- order []string // the path list of dirty nodes, sort by insertion order
91
- nodes map [string ]* nodeWithPrev // the map of dirty nodes, keyed by node path
89
+ func (n * nodeWithPrev ) memorySize (pathlen int ) int {
90
+ return n .memoryNode .memorySize (pathlen ) + len (n .prev )
92
91
}
93
92
94
93
// NodeSet contains all dirty nodes collected during the commit operation.
95
94
// Each node is keyed by path. It's not thread-safe to use.
96
95
type NodeSet struct {
97
- owner common.Hash // the identifier of the trie
98
- updates * nodesWithOrder // the set of updated nodes(newly inserted, updated)
99
- deletes map [string ][]byte // the map of deleted nodes, keyed by node
100
- leaves []* leaf // the list of dirty leaves
96
+ owner common.Hash // the identifier of the trie
97
+ nodes map [string ]* memoryNode // the set of dirty nodes(inserted, updated, deleted)
98
+ leaves []* leaf // the list of dirty leaves
99
+ updates int // the count of updated and inserted nodes
100
+ deletes int // the count of deleted nodes
101
+
102
+ // The list of accessed nodes, which records the original node value.
103
+ // The origin value is expected to be nil for newly inserted node
104
+ // and is expected to be non-nil for other types(updated, deleted).
105
+ accessList map [string ][]byte
101
106
}
102
107
103
108
// NewNodeSet initializes an empty node set to be used for tracking dirty nodes
104
109
// from a specific account or storage trie. The owner is zero for the account
105
110
// trie and the owning account address hash for storage tries.
106
- func NewNodeSet (owner common.Hash ) * NodeSet {
111
+ func NewNodeSet (owner common.Hash , accessList map [ string ][] byte ) * NodeSet {
107
112
return & NodeSet {
108
- owner : owner ,
109
- updates : & nodesWithOrder {
110
- nodes : make (map [string ]* nodeWithPrev ),
111
- },
112
- deletes : make (map [string ][]byte ),
113
+ owner : owner ,
114
+ nodes : make (map [string ]* memoryNode ),
115
+ accessList : accessList ,
113
116
}
114
117
}
115
118
116
- /*
117
- // NewNodeSetWithDeletion initializes the nodeset with provided deletion set.
118
- func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet {
119
- set := NewNodeSet(owner)
120
- for i, path := range paths {
121
- set.markDeleted(path, prev[i])
119
+ // forEachWithOrder iterates the dirty nodes with the order from bottom to top,
120
+ // right to left, nodes with the longest path will be iterated first.
121
+ func (set * NodeSet ) forEachWithOrder (callback func (path string , n * memoryNode )) {
122
+ var paths sort.StringSlice
123
+ for path := range set .nodes {
124
+ paths = append (paths , path )
125
+ }
126
+ // Bottom-up, longest path first
127
+ sort .Sort (sort .Reverse (paths ))
128
+ for _ , path := range paths {
129
+ callback (path , set .nodes [path ])
122
130
}
123
- return set
124
131
}
125
- */
126
132
127
- // markUpdated marks the node as dirty(newly-inserted or updated) with provided
128
- // node path, node object along with its previous value.
129
- func (set * NodeSet ) markUpdated (path []byte , node * memoryNode , prev []byte ) {
130
- set .updates .order = append (set .updates .order , string (path ))
131
- set .updates .nodes [string (path )] = & nodeWithPrev {
132
- memoryNode : node ,
133
- prev : prev ,
134
- }
133
+ // markUpdated marks the node as dirty(newly-inserted or updated).
134
+ func (set * NodeSet ) markUpdated (path []byte , node * memoryNode ) {
135
+ set .nodes [string (path )] = node
136
+ set .updates += 1
135
137
}
136
138
137
- // markDeleted marks the node as deleted with provided path and previous value.
138
- func (set * NodeSet ) markDeleted (path []byte , prev []byte ) {
139
- set .deletes [string (path )] = prev
139
+ // markDeleted marks the node as deleted.
140
+ func (set * NodeSet ) markDeleted (path []byte ) {
141
+ set .nodes [string (path )] = & memoryNode {}
142
+ set .deletes += 1
140
143
}
141
144
142
145
// addLeaf collects the provided leaf node into set.
143
146
func (set * NodeSet ) addLeaf (node * leaf ) {
144
147
set .leaves = append (set .leaves , node )
145
148
}
146
149
147
- // Size returns the number of updated and deleted nodes contained in the set.
150
+ // Size returns the number of dirty nodes in set.
148
151
func (set * NodeSet ) Size () (int , int ) {
149
- return len ( set .updates . order ), len ( set .deletes )
152
+ return set .updates , set .deletes
150
153
}
151
154
152
155
// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can
153
156
// we get rid of it?
154
157
func (set * NodeSet ) Hashes () []common.Hash {
155
158
var ret []common.Hash
156
- for _ , node := range set .updates . nodes {
159
+ for _ , node := range set .nodes {
157
160
ret = append (ret , node .hash )
158
161
}
159
162
return ret
@@ -163,19 +166,23 @@ func (set *NodeSet) Hashes() []common.Hash {
163
166
func (set * NodeSet ) Summary () string {
164
167
var out = new (strings.Builder )
165
168
fmt .Fprintf (out , "nodeset owner: %v\n " , set .owner )
166
- if set .updates != nil {
167
- for _ , key := range set .updates .order {
168
- updated := set .updates .nodes [key ]
169
- if updated .prev != nil {
170
- fmt .Fprintf (out , " [*]: %x -> %v prev: %x\n " , key , updated .hash , updated .prev )
171
- } else {
172
- fmt .Fprintf (out , " [+]: %x -> %v\n " , key , updated .hash )
169
+ if set .nodes != nil {
170
+ for path , n := range set .nodes {
171
+ // Deletion
172
+ if n .isDeleted () {
173
+ fmt .Fprintf (out , " [-]: %x prev: %x\n " , path , set .accessList [path ])
174
+ continue
173
175
}
176
+ // Insertion
177
+ origin , ok := set .accessList [path ]
178
+ if ! ok {
179
+ fmt .Fprintf (out , " [+]: %x -> %v\n " , path , n .hash )
180
+ continue
181
+ }
182
+ // Update
183
+ fmt .Fprintf (out , " [*]: %x -> %v prev: %x\n " , path , n .hash , origin )
174
184
}
175
185
}
176
- for k , n := range set .deletes {
177
- fmt .Fprintf (out , " [-]: %x -> %x\n " , k , n )
178
- }
179
186
for _ , n := range set .leaves {
180
187
fmt .Fprintf (out , "[leaf]: %v\n " , n )
181
188
}
0 commit comments