@@ -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,96 +65,107 @@ 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
71
78
}
72
79
73
80
// unwrap returns the internal memoryNode object.
74
- // nolint:unused
81
+ // nolint: unused
75
82
func (n *nodeWithPrev) unwrap() *memoryNode {
76
83
return n.memoryNode
77
84
}
78
85
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
+ accessList map[string][]byte // The list of accessed nodes, which records the original node value
101
100
}
102
101
103
102
// NewNodeSet initializes an empty node set to be used for tracking dirty nodes
104
- // from a specific account or storage trie. The owner is zero for the account
105
- // trie and the owning account address hash for storage tries.
106
- func NewNodeSet(owner common.Hash) *NodeSet {
103
+ // for a specific account or storage trie. The owner is zero for the account trie
104
+ // and the owning account address hash for storage tries. The provided accessList
105
+ // represents the original value of accessed nodes, it can be optional but would
106
+ // be beneficial for speeding up the construction of trie history.
107
+ func NewNodeSet(owner common.Hash, accessList map[string][]byte) *NodeSet {
108
+ // Don't panic for lazy users
109
+ if accessList == nil {
110
+ accessList = make(map[string][]byte)
111
+ }
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 specified order.
120
+ // If topToBottom is true:
121
+ //
122
+ // then the order of iteration is top to bottom, left to right.
123
+ //
124
+ // If topToBottom is false:
125
+ //
126
+ // then the order of iteration is bottom to top, right to left.
127
+ func (set *NodeSet) forEachWithOrder(topToBottom bool, callback func(path string, n *memoryNode)) {
128
+ var paths sort.StringSlice
129
+ for path := range set.nodes {
130
+ paths = append(paths, path)
131
+ }
132
+ if topToBottom {
133
+ paths.Sort()
134
+ } else {
135
+ sort.Sort(sort.Reverse(paths))
136
+ }
137
+ for _, path := range paths {
138
+ callback(path, set.nodes[path])
122
139
}
123
- return set
124
140
}
125
- */
126
141
127
142
// markUpdated marks the node as dirty(newly-inserted or updated) with provided
128
143
// 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
- }
144
+ func (set *NodeSet) markUpdated(path []byte, node *memoryNode) {
145
+ set.nodes[string(path)] = node
135
146
}
136
147
137
148
// 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
149
+ // nolint: unused
150
+ func (set *NodeSet) markDeleted(path []byte) {
151
+ set.nodes[string(path)] = &memoryNode{}
140
152
}
141
153
142
154
// addLeaf collects the provided leaf node into set.
143
155
func (set *NodeSet) addLeaf(node *leaf) {
144
156
set.leaves = append(set.leaves, node)
145
157
}
146
158
147
- // Size returns the number of updated and deleted nodes contained in the set.
148
- func (set *NodeSet) Size() ( int, int) {
149
- return len(set.updates.order), len(set.deletes )
159
+ // Size returns the number of dirty nodes contained in the set.
160
+ func (set *NodeSet) Size() int {
161
+ return len(set.nodes )
150
162
}
151
163
152
164
// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can
153
165
// we get rid of it?
154
166
func (set *NodeSet) Hashes() []common.Hash {
155
167
var ret []common.Hash
156
- for _, node := range set.updates. nodes {
168
+ for _, node := range set.nodes {
157
169
ret = append(ret, node.hash)
158
170
}
159
171
return ret
@@ -163,19 +175,17 @@ func (set *NodeSet) Hashes() []common.Hash {
163
175
func (set *NodeSet) Summary() string {
164
176
var out = new(strings.Builder)
165
177
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)
178
+ if set.nodes != nil {
179
+ for path, n := range set.nodes {
180
+ // Deletion
181
+ if n.isDeleted() {
182
+ fmt.Fprintf(out, " [-]: %x\n", path)
183
+ continue
173
184
}
185
+ // Update
186
+ fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash)
174
187
}
175
188
}
176
- for k, n := range set.deletes {
177
- fmt.Fprintf(out, " [-]: %x -> %x\n", k, n)
178
- }
179
189
for _, n := range set.leaves {
180
190
fmt.Fprintf(out, "[leaf]: %v\n", n)
181
191
}
0 commit comments