Skip to content

Commit 67a4a11

Browse files
rjl493456442shekhirin
authored andcommitted
Revert "core/trie: remove trie tracer (ethereum#26665)" (ethereum#26732)
This reverts commit 7c749c9.
1 parent a4fd50c commit 67a4a11

File tree

9 files changed

+725
-116
lines changed

9 files changed

+725
-116
lines changed

core/state/metrics.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ package state
1919
import "github.com/ethereum/go-ethereum/metrics"
2020

2121
var (
22-
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
23-
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
24-
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
25-
storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil)
26-
accountTrieNodesMeter = metrics.NewRegisteredMeter("state/trie/account", nil)
27-
storageTriesNodesMeter = metrics.NewRegisteredMeter("state/trie/storage", nil)
22+
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
23+
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
24+
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
25+
storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil)
26+
accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil)
27+
storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil)
28+
accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil)
29+
storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil)
2830
)

core/state/statedb.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -970,11 +970,13 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
970970

971971
// Commit objects to the trie, measuring the elapsed time
972972
var (
973-
accountTrieNodes int
974-
storageTrieNodes int
975-
nodes = trie.NewMergedNodeSet()
976-
codeWriter = s.db.DiskDB().NewBatch()
973+
accountTrieNodesUpdated int
974+
accountTrieNodesDeleted int
975+
storageTrieNodesUpdated int
976+
storageTrieNodesDeleted int
977+
nodes = trie.NewMergedNodeSet()
977978
)
979+
codeWriter := s.db.DiskDB().NewBatch()
978980
for addr := range s.stateObjectsDirty {
979981
if obj := s.stateObjects[addr]; !obj.deleted {
980982
// Write any contract code associated with the state object
@@ -992,9 +994,17 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
992994
if err := nodes.Merge(set); err != nil {
993995
return common.Hash{}, err
994996
}
995-
storageTrieNodes += set.Size()
997+
updates, deleted := set.Size()
998+
storageTrieNodesUpdated += updates
999+
storageTrieNodesDeleted += deleted
9961000
}
9971001
}
1002+
// If the contract is destructed, the storage is still left in the
1003+
// database as dangling data. Theoretically it's should be wiped from
1004+
// database as well, but in hash-based-scheme it's extremely hard to
1005+
// determine that if the trie nodes are also referenced by other storage,
1006+
// and in path-based-scheme some technical challenges are still unsolved.
1007+
// Although it won't affect the correctness but please fix it TODO(rjl493456442).
9981008
}
9991009
if len(s.stateObjectsDirty) > 0 {
10001010
s.stateObjectsDirty = make(map[common.Address]struct{})
@@ -1015,7 +1025,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10151025
if err := nodes.Merge(set); err != nil {
10161026
return common.Hash{}, err
10171027
}
1018-
accountTrieNodes = set.Size()
1028+
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
10191029
}
10201030
if metrics.EnabledExpensive {
10211031
s.AccountCommits += time.Since(start)
@@ -1024,9 +1034,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10241034
storageUpdatedMeter.Mark(int64(s.StorageUpdated))
10251035
accountDeletedMeter.Mark(int64(s.AccountDeleted))
10261036
storageDeletedMeter.Mark(int64(s.StorageDeleted))
1027-
accountTrieNodesMeter.Mark(int64(accountTrieNodes))
1028-
storageTriesNodesMeter.Mark(int64(storageTrieNodes))
1029-
1037+
accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated))
1038+
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))
1039+
storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated))
1040+
storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted))
10301041
s.AccountUpdated, s.AccountDeleted = 0, 0
10311042
s.StorageUpdated, s.StorageDeleted = 0, 0
10321043
}

trie/committer.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,29 @@ type leaf struct {
3333
// insertion order.
3434
type committer struct {
3535
nodes *NodeSet
36+
tracer *tracer
3637
collectLeaf bool
3738
}
3839

3940
// newCommitter creates a new committer or picks one from the pool.
40-
func newCommitter(nodes *NodeSet, collectLeaf bool) *committer {
41+
func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer {
4142
return &committer{
42-
nodes: nodes,
43+
nodes: NewNodeSet(owner),
44+
tracer: tracer,
4345
collectLeaf: collectLeaf,
4446
}
4547
}
4648

4749
// Commit collapses a node down into a hash node and returns it along with
4850
// the modified nodeset.
49-
func (c *committer) Commit(n node) hashNode {
51+
func (c *committer) Commit(n node) (hashNode, *NodeSet) {
5052
h := c.commit(nil, n)
51-
return h.(hashNode)
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
5259
}
5360

5461
// commit collapses a node down into a hash node and returns it.
@@ -78,6 +85,12 @@ func (c *committer) commit(path []byte, n node) node {
7885
if hn, ok := hashedNode.(hashNode); ok {
7986
return hn
8087
}
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+
}
8194
return collapsed
8295
case *fullNode:
8396
hashedKids := c.commitChildren(path, cn)
@@ -88,6 +101,12 @@ func (c *committer) commit(path []byte, n node) node {
88101
if hn, ok := hashedNode.(hashNode); ok {
89102
return hn
90103
}
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+
}
91110
return collapsed
92111
case hashNode:
93112
return cn
@@ -150,7 +169,7 @@ func (c *committer) store(path []byte, n node) node {
150169
}
151170
)
152171
// Collect the dirty node to nodeset for return.
153-
c.nodes.markUpdated(path, mnode)
172+
c.nodes.markUpdated(path, mnode, c.tracer.getPrev(path))
154173

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

trie/database.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,13 @@ func (db *Database) Update(nodes *MergedNodeSet) error {
792792
}
793793
for _, owner := range order {
794794
subset := nodes.sets[owner]
795-
subset.forEachWithOrder(false, func(path string, n *memoryNode) {
796-
if n.isDeleted() {
797-
return // ignore deletion
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)
798799
}
799800
db.insert(n.hash, int(n.size), n.node)
800-
})
801+
}
801802
}
802803
// Link up the account trie and storage trie if the node points
803804
// to an account trie leaf.

trie/nodeset.go

Lines changed: 55 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package trie
1919
import (
2020
"fmt"
2121
"reflect"
22-
"sort"
2322
"strings"
2423

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

4241
// memorySize returns the total memory size used by this node.
4342
// nolint:unused
44-
func (n *memoryNode) memorySize(pathlen int) int {
45-
return int(n.size) + memoryNodeSize + pathlen
43+
func (n *memoryNode) memorySize(key int) int {
44+
return int(n.size) + memoryNodeSize + key
4645
}
4746

4847
// rlp returns the raw rlp encoded blob of the cached trie node, either directly
@@ -65,107 +64,96 @@ func (n *memoryNode) obj() node {
6564
return expandNode(n.hash[:], n.node)
6665
}
6766

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-
7367
// nodeWithPrev wraps the memoryNode with the previous node value.
74-
// nolint: unused
7568
type nodeWithPrev struct {
7669
*memoryNode
7770
prev []byte // RLP-encoded previous value, nil means it's non-existent
7871
}
7972

8073
// unwrap returns the internal memoryNode object.
81-
// nolint: unused
74+
// nolint:unused
8275
func (n *nodeWithPrev) unwrap() *memoryNode {
8376
return n.memoryNode
8477
}
8578

8679
// memorySize returns the total memory size used by this node. It overloads
8780
// the function in memoryNode by counting the size of previous value as well.
8881
// nolint: unused
89-
func (n *nodeWithPrev) memorySize(pathlen int) int {
90-
return n.memoryNode.memorySize(pathlen) + len(n.prev)
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
9192
}
9293

9394
// NodeSet contains all dirty nodes collected during the commit operation.
9495
// Each node is keyed by path. It's not thread-safe to use.
9596
type NodeSet struct {
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
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
100101
}
101102

102103
// NewNodeSet initializes an empty node set to be used for tracking dirty nodes
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-
}
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 {
112107
return &NodeSet{
113-
owner: owner,
114-
nodes: make(map[string]*memoryNode),
115-
accessList: accessList,
108+
owner: owner,
109+
updates: &nodesWithOrder{
110+
nodes: make(map[string]*nodeWithPrev),
111+
},
112+
deletes: make(map[string][]byte),
116113
}
117114
}
118115

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])
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])
139122
}
123+
return set
140124
}
125+
*/
141126

142127
// markUpdated marks the node as dirty(newly-inserted or updated) with provided
143128
// node path, node object along with its previous value.
144-
func (set *NodeSet) markUpdated(path []byte, node *memoryNode) {
145-
set.nodes[string(path)] = node
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+
}
146135
}
147136

148137
// markDeleted marks the node as deleted with provided path and previous value.
149-
// nolint: unused
150-
func (set *NodeSet) markDeleted(path []byte) {
151-
set.nodes[string(path)] = &memoryNode{}
138+
func (set *NodeSet) markDeleted(path []byte, prev []byte) {
139+
set.deletes[string(path)] = prev
152140
}
153141

154142
// addLeaf collects the provided leaf node into set.
155143
func (set *NodeSet) addLeaf(node *leaf) {
156144
set.leaves = append(set.leaves, node)
157145
}
158146

159-
// Size returns the number of dirty nodes contained in the set.
160-
func (set *NodeSet) Size() int {
161-
return len(set.nodes)
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)
162150
}
163151

164152
// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can
165153
// we get rid of it?
166154
func (set *NodeSet) Hashes() []common.Hash {
167155
var ret []common.Hash
168-
for _, node := range set.nodes {
156+
for _, node := range set.updates.nodes {
169157
ret = append(ret, node.hash)
170158
}
171159
return ret
@@ -175,17 +163,19 @@ func (set *NodeSet) Hashes() []common.Hash {
175163
func (set *NodeSet) Summary() string {
176164
var out = new(strings.Builder)
177165
fmt.Fprintf(out, "nodeset owner: %v\n", set.owner)
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
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)
184173
}
185-
// Update
186-
fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash)
187174
}
188175
}
176+
for k, n := range set.deletes {
177+
fmt.Fprintf(out, " [-]: %x -> %x\n", k, n)
178+
}
189179
for _, n := range set.leaves {
190180
fmt.Fprintf(out, "[leaf]: %v\n", n)
191181
}

0 commit comments

Comments
 (0)