github.com/calmw/ethereum@v0.1.1/trie/tracer.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "github.com/calmw/ethereum/common" 21 "github.com/calmw/ethereum/trie/trienode" 22 ) 23 24 // tracer tracks the changes of trie nodes. During the trie operations, 25 // some nodes can be deleted from the trie, while these deleted nodes 26 // won't be captured by trie.Hasher or trie.Committer. Thus, these deleted 27 // nodes won't be removed from the disk at all. Tracer is an auxiliary tool 28 // used to track all insert and delete operations of trie and capture all 29 // deleted nodes eventually. 30 // 31 // The changed nodes can be mainly divided into two categories: the leaf 32 // node and intermediate node. The former is inserted/deleted by callers 33 // while the latter is inserted/deleted in order to follow the rule of trie. 34 // This tool can track all of them no matter the node is embedded in its 35 // parent or not, but valueNode is never tracked. 36 // 37 // Besides, it's also used for recording the original value of the nodes 38 // when they are resolved from the disk. The pre-value of the nodes will 39 // be used to construct trie history in the future. 40 // 41 // Note tracer is not thread-safe, callers should be responsible for handling 42 // the concurrency issues by themselves. 43 type tracer struct { 44 inserts map[string]struct{} 45 deletes map[string]struct{} 46 accessList map[string][]byte 47 } 48 49 // newTracer initializes the tracer for capturing trie changes. 50 func newTracer() *tracer { 51 return &tracer{ 52 inserts: make(map[string]struct{}), 53 deletes: make(map[string]struct{}), 54 accessList: make(map[string][]byte), 55 } 56 } 57 58 // onRead tracks the newly loaded trie node and caches the rlp-encoded 59 // blob internally. Don't change the value outside of function since 60 // it's not deep-copied. 61 func (t *tracer) onRead(path []byte, val []byte) { 62 t.accessList[string(path)] = val 63 } 64 65 // onInsert tracks the newly inserted trie node. If it's already 66 // in the deletion set (resurrected node), then just wipe it from 67 // the deletion set as it's "untouched". 68 func (t *tracer) onInsert(path []byte) { 69 if _, present := t.deletes[string(path)]; present { 70 delete(t.deletes, string(path)) 71 return 72 } 73 t.inserts[string(path)] = struct{}{} 74 } 75 76 // onDelete tracks the newly deleted trie node. If it's already 77 // in the addition set, then just wipe it from the addition set 78 // as it's untouched. 79 func (t *tracer) onDelete(path []byte) { 80 if _, present := t.inserts[string(path)]; present { 81 delete(t.inserts, string(path)) 82 return 83 } 84 t.deletes[string(path)] = struct{}{} 85 } 86 87 // reset clears the content tracked by tracer. 88 func (t *tracer) reset() { 89 t.inserts = make(map[string]struct{}) 90 t.deletes = make(map[string]struct{}) 91 t.accessList = make(map[string][]byte) 92 } 93 94 // copy returns a deep copied tracer instance. 95 func (t *tracer) copy() *tracer { 96 var ( 97 inserts = make(map[string]struct{}) 98 deletes = make(map[string]struct{}) 99 accessList = make(map[string][]byte) 100 ) 101 for path := range t.inserts { 102 inserts[path] = struct{}{} 103 } 104 for path := range t.deletes { 105 deletes[path] = struct{}{} 106 } 107 for path, blob := range t.accessList { 108 accessList[path] = common.CopyBytes(blob) 109 } 110 return &tracer{ 111 inserts: inserts, 112 deletes: deletes, 113 accessList: accessList, 114 } 115 } 116 117 // markDeletions puts all tracked deletions into the provided nodeset. 118 func (t *tracer) markDeletions(set *trienode.NodeSet) { 119 for path := range t.deletes { 120 // It's possible a few deleted nodes were embedded 121 // in their parent before, the deletions can be no 122 // effect by deleting nothing, filter them out. 123 prev, ok := t.accessList[path] 124 if !ok { 125 continue 126 } 127 set.AddNode([]byte(path), trienode.NewWithPrev(common.Hash{}, nil, prev)) 128 } 129 }