Skip to content

Commit c8a6b71

Browse files
authored
core/state, trie: port changes from PBSS (#26763)
1 parent 94ff721 commit c8a6b71

File tree

11 files changed

+645
-645
lines changed

11 files changed

+645
-645
lines changed

core/state/statedb.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,8 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
970970
storageTrieNodesUpdated int
971971
storageTrieNodesDeleted int
972972
nodes = trie.NewMergedNodeSet()
973+
codeWriter = s.db.DiskDB().NewBatch()
973974
)
974-
codeWriter := s.db.DiskDB().NewBatch()
975975
for addr := range s.stateObjectsDirty {
976976
if obj := s.stateObjects[addr]; !obj.deleted {
977977
// Write any contract code associated with the state object

trie/committer.go

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,20 @@ type leaf struct {
3333
// insertion order.
3434
type committer struct {
3535
nodes *NodeSet
36-
tracer *tracer
3736
collectLeaf bool
3837
}
3938

4039
// newCommitter creates a new committer or picks one from the pool.
41-
func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer {
40+
func newCommitter(nodeset *NodeSet, collectLeaf bool) *committer {
4241
return &committer{
43-
nodes: NewNodeSet(owner),
44-
tracer: tracer,
42+
nodes: nodeset,
4543
collectLeaf: collectLeaf,
4644
}
4745
}
4846

49-
// Commit collapses a node down into a hash node and returns it along with
50-
// the modified nodeset.
51-
func (c *committer) Commit(n node) (hashNode, *NodeSet) {
52-
h := c.commit(nil, n)
53-
// Some nodes can be deleted from trie which can't be captured
54-
// by committer itself. Iterate all deleted nodes tracked by
55-
// tracer and marked them as deleted only if they are present
56-
// in database previously.
57-
c.tracer.markDeletions(c.nodes)
58-
return h.(hashNode), c.nodes
47+
// Commit collapses a node down into a hash node.
48+
func (c *committer) Commit(n node) hashNode {
49+
return c.commit(nil, n).(hashNode)
5950
}
6051

6152
// commit collapses a node down into a hash node and returns it.
@@ -74,9 +65,7 @@ func (c *committer) commit(path []byte, n node) node {
7465
// If the child is fullNode, recursively commit,
7566
// otherwise it can only be hashNode or valueNode.
7667
if _, ok := cn.Val.(*fullNode); ok {
77-
childV := c.commit(append(path, cn.Key...), cn.Val)
78-
79-
collapsed.Val = childV
68+
collapsed.Val = c.commit(append(path, cn.Key...), cn.Val)
8069
}
8170
// The key needs to be copied, since we're adding it to the
8271
// modified nodeset.
@@ -85,12 +74,6 @@ func (c *committer) commit(path []byte, n node) node {
8574
if hn, ok := hashedNode.(hashNode); ok {
8675
return hn
8776
}
88-
// The short node now is embedded in its parent. Mark the node as
89-
// deleted if it's present in database previously. It's equivalent
90-
// as deletion from database's perspective.
91-
if prev := c.tracer.getPrev(path); len(prev) != 0 {
92-
c.nodes.markDeleted(path, prev)
93-
}
9477
return collapsed
9578
case *fullNode:
9679
hashedKids := c.commitChildren(path, cn)
@@ -101,12 +84,6 @@ func (c *committer) commit(path []byte, n node) node {
10184
if hn, ok := hashedNode.(hashNode); ok {
10285
return hn
10386
}
104-
// The full node now is embedded in its parent. Mark the node as
105-
// deleted if it's present in database previously. It's equivalent
106-
// as deletion from database's perspective.
107-
if prev := c.tracer.getPrev(path); len(prev) != 0 {
108-
c.nodes.markDeleted(path, prev)
109-
}
11087
return collapsed
11188
case hashNode:
11289
return cn
@@ -134,8 +111,7 @@ func (c *committer) commitChildren(path []byte, n *fullNode) [17]node {
134111
// Commit the child recursively and store the "hashed" value.
135112
// Note the returned node can be some embedded nodes, so it's
136113
// possible the type is not hashNode.
137-
hashed := c.commit(append(path, byte(i)), child)
138-
children[i] = hashed
114+
children[i] = c.commit(append(path, byte(i)), child)
139115
}
140116
// For the 17th child, it's possible the type is valuenode.
141117
if n.Children[16] != nil {
@@ -155,6 +131,12 @@ func (c *committer) store(path []byte, n node) node {
155131
// usually is leaf node). But small value (less than 32bytes) is not
156132
// our target (leaves in account trie only).
157133
if hash == nil {
134+
// The node is embedded in its parent, in other words, this node
135+
// will not be stored in the database independently, mark it as
136+
// deleted only if the node was existent in database before.
137+
if _, ok := c.nodes.accessList[string(path)]; ok {
138+
c.nodes.markDeleted(path)
139+
}
158140
return n
159141
}
160142
// We have the hash already, estimate the RLP encoding-size of the node.
@@ -169,7 +151,7 @@ func (c *committer) store(path []byte, n node) node {
169151
}
170152
)
171153
// Collect the dirty node to nodeset for return.
172-
c.nodes.markUpdated(path, mnode, c.tracer.getPrev(path))
154+
c.nodes.markUpdated(path, mnode)
173155

174156
// Collect the corresponding leaf node if it's required. We don't check
175157
// full node since it's impossible to store value in fullNode. The key

trie/database.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -792,13 +792,12 @@ func (db *Database) Update(nodes *MergedNodeSet) error {
792792
}
793793
for _, owner := range order {
794794
subset := nodes.sets[owner]
795-
for _, path := range subset.updates.order {
796-
n, ok := subset.updates.nodes[path]
797-
if !ok {
798-
return fmt.Errorf("missing node %x %v", owner, path)
795+
subset.forEachWithOrder(func(path string, n *memoryNode) {
796+
if n.isDeleted() {
797+
return // ignore deletion
799798
}
800799
db.insert(n.hash, int(n.size), n.node)
801-
}
800+
})
802801
}
803802
// Link up the account trie and storage trie if the node points
804803
// to an account trie leaf.

trie/nodeset.go

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package trie
1919
import (
2020
"fmt"
2121
"reflect"
22+
"sort"
2223
"strings"
2324

2425
"github.com/ethereum/go-ethereum/common"
@@ -40,8 +41,8 @@ var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size())
4041

4142
// memorySize returns the total memory size used by this node.
4243
// 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
4546
}
4647

4748
// rlp returns the raw rlp encoded blob of the cached trie node, either directly
@@ -64,7 +65,13 @@ func (n *memoryNode) obj() node {
6465
return expandNode(n.hash[:], n.node)
6566
}
6667

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+
6773
// nodeWithPrev wraps the memoryNode with the previous node value.
74+
// nolint: unused
6875
type nodeWithPrev struct {
6976
*memoryNode
7077
prev []byte // RLP-encoded previous value, nil means it's non-existent
@@ -79,81 +86,77 @@ func (n *nodeWithPrev) unwrap() *memoryNode {
7986
// memorySize returns the total memory size used by this node. It overloads
8087
// the function in memoryNode by counting the size of previous value as well.
8188
// 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)
9291
}
9392

9493
// NodeSet contains all dirty nodes collected during the commit operation.
9594
// Each node is keyed by path. It's not thread-safe to use.
9695
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
101106
}
102107

103108
// NewNodeSet initializes an empty node set to be used for tracking dirty nodes
104109
// from a specific account or storage trie. The owner is zero for the account
105110
// 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 {
107112
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,
113116
}
114117
}
115118

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])
122130
}
123-
return set
124131
}
125-
*/
126132

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
135137
}
136138

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
140143
}
141144

142145
// addLeaf collects the provided leaf node into set.
143146
func (set *NodeSet) addLeaf(node *leaf) {
144147
set.leaves = append(set.leaves, node)
145148
}
146149

147-
// Size returns the number of updated and deleted nodes contained in the set.
150+
// Size returns the number of dirty nodes in set.
148151
func (set *NodeSet) Size() (int, int) {
149-
return len(set.updates.order), len(set.deletes)
152+
return set.updates, set.deletes
150153
}
151154

152155
// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can
153156
// we get rid of it?
154157
func (set *NodeSet) Hashes() []common.Hash {
155158
var ret []common.Hash
156-
for _, node := range set.updates.nodes {
159+
for _, node := range set.nodes {
157160
ret = append(ret, node.hash)
158161
}
159162
return ret
@@ -163,19 +166,23 @@ func (set *NodeSet) Hashes() []common.Hash {
163166
func (set *NodeSet) Summary() string {
164167
var out = new(strings.Builder)
165168
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
173175
}
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)
174184
}
175185
}
176-
for k, n := range set.deletes {
177-
fmt.Fprintf(out, " [-]: %x -> %x\n", k, n)
178-
}
179186
for _, n := range set.leaves {
180187
fmt.Fprintf(out, "[leaf]: %v\n", n)
181188
}

trie/proof.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key
563563
}
564564
// Rebuild the trie with the leaf stream, the shape of trie
565565
// should be same with the original one.
566-
tr := &Trie{root: root, reader: newEmptyReader()}
566+
tr := &Trie{root: root, reader: newEmptyReader(), tracer: newTracer()}
567567
if empty {
568568
tr.root = nil
569569
}

0 commit comments

Comments
 (0)