Skip to content

Commit a868a8e

Browse files
committed
trie: make value node resolvable, not needing to be known at insertion time.
1 parent 078a5ec commit a868a8e

File tree

13 files changed

+116
-41
lines changed

13 files changed

+116
-41
lines changed

core/state/database.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ type Trie interface {
9999
// in the trie with provided address.
100100
UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error
101101

102+
UpdateAccountAsync(address common.Address, accountResolver func() *types.StateAccount) error
103+
102104
// UpdateStorage associates key with value in the trie. If value has length zero,
103105
// any existing value is deleted from the trie. The value bytes must not be modified
104106
// by the caller while they are stored in the trie. If a node was not found in the

core/state/statedb.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,13 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
577577
}
578578
}
579579

580+
// updateStateObject writes the given object to the trie.
581+
func (s *StateDB) updateStateObjectAsync(addr common.Address, resolver func() *types.StateAccount) {
582+
if err := s.trie.UpdateAccountAsync(addr, resolver); err != nil {
583+
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr, err))
584+
}
585+
}
586+
580587
// deleteStateObject removes the given object from the state trie.
581588
func (s *StateDB) deleteStateObject(addr common.Address) {
582589
if err := s.trie.DeleteAccount(addr); err != nil {
@@ -829,11 +836,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
829836
// later time.
830837
workers.SetLimit(1)
831838
}
839+
840+
stateObjectsResolve := make(map[common.Address]func() *types.StateAccount)
832841
for addr, op := range s.mutations {
833842
if op.applied || op.isDelete() {
834843
continue
835844
}
836845
obj := s.stateObjects[addr] // closure for the task runner below
846+
complete := make(chan *types.StateAccount)
837847
workers.Go(func() error {
838848
if s.db.TrieDB().IsVerkle() {
839849
obj.updateTrie()
@@ -846,8 +856,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
846856
s.witness.AddState(obj.trie.Witness())
847857
}
848858
}
859+
complete <- &obj.data
849860
return nil
850861
})
862+
863+
stateObjectsResolve[addr] = func() *types.StateAccount {
864+
return <-complete
865+
}
851866
}
852867
// If witness building is enabled, gather all the read-only accesses.
853868
// Skip witness collection in Verkle mode, they will be gathered
@@ -898,7 +913,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
898913
}
899914
}
900915
}
901-
workers.Wait()
902916
s.StorageUpdates += time.Since(start)
903917

904918
// Now we're about to start to write changes to the trie. The trie is so far
@@ -939,7 +953,11 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
939953
if op.isDelete() {
940954
deletedAddrs = append(deletedAddrs, addr)
941955
} else {
942-
s.updateStateObject(s.stateObjects[addr])
956+
if s.db.TrieDB().IsVerkle() {
957+
s.updateStateObject(s.stateObjects[addr])
958+
} else {
959+
s.updateStateObjectAsync(addr, stateObjectsResolve[addr])
960+
}
943961
s.AccountUpdated += 1
944962
}
945963
usedAddrs = append(usedAddrs, addr) // Copy needed for closure
@@ -966,6 +984,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
966984
s.witnessStats.Add(witness, common.Hash{})
967985
}
968986
}
987+
969988
return hash
970989
}
971990

trie/committer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ func (c *committer) store(path []byte, n node) node {
157157
// length of leaves should be exactly same.
158158
if c.collectLeaf {
159159
if sn, ok := n.(*shortNode); ok {
160-
if val, ok := sn.Val.(valueNode); ok {
161-
c.nodes.AddLeaf(nhash, val)
160+
if val, ok := sn.Val.(*valueNode); ok {
161+
c.nodes.AddLeaf(nhash, val.resolve())
162162
}
163163
}
164164
}
@@ -182,7 +182,7 @@ func forGatherChildren(n node, onChild func(hash common.Hash)) {
182182
}
183183
case hashNode:
184184
onChild(common.BytesToHash(n))
185-
case valueNode, nil:
185+
case *valueNode, nil:
186186
default:
187187
panic(fmt.Sprintf("unknown node type: %T", n))
188188
}

trie/hasher.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (h *hasher) encodeShortNode(n *shortNode) []byte {
110110
if hasTerm(n.Key) {
111111
var ln leafNodeEncoder
112112
ln.Key = hexToCompact(n.Key)
113-
ln.Val = n.Val.(valueNode)
113+
ln.Val = n.Val.(*valueNode).resolve()
114114
ln.encode(h.encbuf)
115115
return h.encodedBytes()
116116
}
@@ -162,7 +162,7 @@ func (h *hasher) encodeFullNode(n *fullNode) []byte {
162162
}
163163
}
164164
if n.Children[16] != nil {
165-
fn.Children[16] = n.Children[16].(valueNode)
165+
fn.Children[16] = n.Children[16].(*valueNode).resolve()
166166
}
167167
fn.encode(h.encbuf)
168168
fnEncoderPool.Put(fn)

trie/iterator.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func (it *nodeIterator) Leaf() bool {
215215

216216
func (it *nodeIterator) LeafKey() []byte {
217217
if len(it.stack) > 0 {
218-
if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok {
218+
if _, ok := it.stack[len(it.stack)-1].node.(*valueNode); ok {
219219
return hexToKeybytes(it.path)
220220
}
221221
}
@@ -224,16 +224,16 @@ func (it *nodeIterator) LeafKey() []byte {
224224

225225
func (it *nodeIterator) LeafBlob() []byte {
226226
if len(it.stack) > 0 {
227-
if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok {
228-
return node
227+
if node, ok := it.stack[len(it.stack)-1].node.(*valueNode); ok {
228+
return node.resolve()
229229
}
230230
}
231231
panic("not at leaf")
232232
}
233233

234234
func (it *nodeIterator) LeafProof() [][]byte {
235235
if len(it.stack) > 0 {
236-
if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok {
236+
if _, ok := it.stack[len(it.stack)-1].node.(*valueNode); ok {
237237
hasher := newHasher(false)
238238
defer returnHasherToPool(hasher)
239239
proofs := make([][]byte, 0, len(it.stack))

trie/node.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ type (
4444
flags nodeFlag
4545
}
4646
hashNode []byte
47-
valueNode []byte
47+
valueNode struct {
48+
resolver func() []byte
49+
val []byte
50+
}
4851

4952
// fullnodeEncoder is a type used exclusively for encoding fullNode.
5053
// Briefly instantiating a fullnodeEncoder and initializing with
@@ -68,6 +71,19 @@ type (
6871
}
6972
)
7073

74+
func newValueNode(resolver func() []byte) *valueNode {
75+
return &valueNode{
76+
resolver: resolver,
77+
}
78+
}
79+
80+
func (v *valueNode) resolve() []byte {
81+
if v.val == nil {
82+
v.val = v.resolver()
83+
}
84+
return v.val
85+
}
86+
7187
// EncodeRLP encodes a full node into the consensus RLP format.
7288
func (n *fullNode) EncodeRLP(w io.Writer) error {
7389
eb := rlp.NewEncoderBuffer(w)
@@ -91,13 +107,13 @@ func (n nodeFlag) copy() nodeFlag {
91107
func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
92108
func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
93109
func (n hashNode) cache() (hashNode, bool) { return nil, true }
94-
func (n valueNode) cache() (hashNode, bool) { return nil, true }
110+
func (n *valueNode) cache() (hashNode, bool) { return nil, true }
95111

96112
// Pretty printing.
97113
func (n *fullNode) String() string { return n.fstring("") }
98114
func (n *shortNode) String() string { return n.fstring("") }
99115
func (n hashNode) String() string { return n.fstring("") }
100-
func (n valueNode) String() string { return n.fstring("") }
116+
func (n *valueNode) String() string { return n.fstring("") }
101117

102118
func (n *fullNode) fstring(ind string) string {
103119
resp := fmt.Sprintf("[\n%s ", ind)
@@ -117,8 +133,8 @@ func (n *shortNode) fstring(ind string) string {
117133
func (n hashNode) fstring(ind string) string {
118134
return fmt.Sprintf("<%x> ", []byte(n))
119135
}
120-
func (n valueNode) fstring(ind string) string {
121-
return fmt.Sprintf("%x ", []byte(n))
136+
func (n *valueNode) fstring(ind string) string {
137+
return fmt.Sprintf("%x ", n.resolve())
122138
}
123139

124140
// mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered.
@@ -185,7 +201,7 @@ func decodeShort(hash, elems []byte) (node, error) {
185201
if err != nil {
186202
return nil, fmt.Errorf("invalid value node: %v", err)
187203
}
188-
return &shortNode{key, valueNode(val), flag}, nil
204+
return &shortNode{key, newValueNode(func() []byte { return val }), flag}, nil
189205
}
190206
r, _, err := decodeRef(rest)
191207
if err != nil {
@@ -208,7 +224,7 @@ func decodeFull(hash, elems []byte) (*fullNode, error) {
208224
return n, err
209225
}
210226
if len(val) > 0 {
211-
n.Children[16] = valueNode(val)
227+
n.Children[16] = newValueNode(func() []byte { return val })
212228
}
213229
return n, nil
214230
}

trie/node_enc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,6 @@ func (n hashNode) encode(w rlp.EncoderBuffer) {
101101
w.WriteBytes(n)
102102
}
103103

104-
func (n valueNode) encode(w rlp.EncoderBuffer) {
105-
w.WriteBytes(n)
104+
func (n *valueNode) encode(w rlp.EncoderBuffer) {
105+
w.WriteBytes(n.resolve())
106106
}

trie/proof.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ func VerifyProof(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader)
128128
case hashNode:
129129
key = keyrest
130130
copy(wantHash[:], cld)
131-
case valueNode:
132-
return cld, nil
131+
case *valueNode:
132+
return cld.resolve(), nil
133133
}
134134
}
135135
}
@@ -191,8 +191,8 @@ func proofToPath(rootHash common.Hash, root node, key []byte, proofDb ethdb.KeyV
191191
if err != nil {
192192
return nil, nil, err
193193
}
194-
case valueNode:
195-
valnode = cld
194+
case *valueNode:
195+
valnode = cld.resolve()
196196
}
197197
// Link the parent and child.
198198
switch pnode := parent.(type) {
@@ -298,7 +298,7 @@ findFork:
298298
}
299299
// Only one proof points to non-existent key.
300300
if shortForkRight != 0 {
301-
if _, ok := rn.Val.(valueNode); ok {
301+
if _, ok := rn.Val.(*valueNode); ok {
302302
// The fork point is root node, unset the entire trie
303303
if parent == nil {
304304
return true, nil
@@ -309,7 +309,7 @@ findFork:
309309
return false, unset(rn, rn.Val, left[pos:], len(rn.Key), false)
310310
}
311311
if shortForkLeft != 0 {
312-
if _, ok := rn.Val.(valueNode); ok {
312+
if _, ok := rn.Val.(*valueNode); ok {
313313
// The fork point is root node, unset the entire trie
314314
if parent == nil {
315315
return true, nil
@@ -396,7 +396,7 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error
396396
}
397397
return nil
398398
}
399-
if _, ok := cld.Val.(valueNode); ok {
399+
if _, ok := cld.Val.(*valueNode); ok {
400400
fn := parent.(*fullNode)
401401
fn.Children[key[pos-1]] = nil
402402
return nil
@@ -432,7 +432,7 @@ func hasRightElement(node node, key []byte) bool {
432432
return bytes.Compare(rn.Key, key[pos:]) > 0
433433
}
434434
node, pos = rn.Val, pos+len(rn.Key)
435-
case valueNode:
435+
case *valueNode:
436436
return false // We have resolved the whole path
437437
default:
438438
panic(fmt.Sprintf("%T: invalid node: %v", node, node)) // hashnode
@@ -612,7 +612,7 @@ func get(tn node, key []byte, skipResolved bool) ([]byte, node) {
612612
return key, n
613613
case nil:
614614
return key, nil
615-
case valueNode:
615+
case *valueNode:
616616
return nil, n
617617
default:
618618
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))

trie/secure_trie.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,25 @@ func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccoun
226226
return nil
227227
}
228228

229+
func (t *StateTrie) UpdateAccountAsync(address common.Address, accountResolve func() *types.StateAccount) error {
230+
hk := crypto.Keccak256(address.Bytes())
231+
resolve := func() []byte {
232+
acc := accountResolve()
233+
data, err := rlp.EncodeToBytes(acc)
234+
if err != nil {
235+
panic(err) // TODO: what do do here?
236+
}
237+
return data
238+
}
239+
if err := t.trie.UpdateAsync(hk, resolve); err != nil {
240+
return err
241+
}
242+
if t.preimages != nil {
243+
t.secKeyCache[common.Hash(hk)] = address.Bytes()
244+
}
245+
return nil
246+
}
247+
229248
func (t *StateTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte) error {
230249
return nil
231250
}

trie/sync.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,15 +612,15 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
612612
for _, child := range children {
613613
// Notify any external watcher of a new key/value node
614614
if req.callback != nil {
615-
if node, ok := (child.node).(valueNode); ok {
615+
if node, ok := (child.node).(*valueNode); ok {
616616
var paths [][]byte
617617
if len(child.path) == 2*common.HashLength {
618618
paths = append(paths, hexToKeybytes(child.path))
619619
} else if len(child.path) == 4*common.HashLength {
620620
paths = append(paths, hexToKeybytes(child.path[:2*common.HashLength]))
621621
paths = append(paths, hexToKeybytes(child.path[2*common.HashLength:]))
622622
}
623-
if err := req.callback(paths, child.path, node, req.hash, req.path); err != nil {
623+
if err := req.callback(paths, child.path, node.resolve(), req.hash, req.path); err != nil {
624624
return nil, err
625625
}
626626
}

0 commit comments

Comments
 (0)