|
16 | 16 |
|
17 | 17 | package triestate |
18 | 18 |
|
19 | | -import ( |
20 | | - "errors" |
21 | | - "fmt" |
22 | | - "sync" |
23 | | - |
24 | | - "github.com/ethereum/go-ethereum/common" |
25 | | - "github.com/ethereum/go-ethereum/core/types" |
26 | | - "github.com/ethereum/go-ethereum/crypto" |
27 | | - "github.com/ethereum/go-ethereum/rlp" |
28 | | - "github.com/ethereum/go-ethereum/trie/trienode" |
29 | | -) |
30 | | - |
31 | | -// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia |
32 | | -// tree or Verkle tree. |
33 | | -type Trie interface { |
34 | | - // Get returns the value for key stored in the trie. |
35 | | - Get(key []byte) ([]byte, error) |
36 | | - |
37 | | - // Update associates key with value in the trie. |
38 | | - Update(key, value []byte) error |
39 | | - |
40 | | - // Delete removes any existing value for key from the trie. |
41 | | - Delete(key []byte) error |
42 | | - |
43 | | - // Commit the trie and returns a set of dirty nodes generated along with |
44 | | - // the new root hash. |
45 | | - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) |
46 | | -} |
47 | | - |
48 | | -// TrieLoader wraps functions to load tries. |
49 | | -type TrieLoader interface { |
50 | | - // OpenTrie opens the main account trie. |
51 | | - OpenTrie(root common.Hash) (Trie, error) |
52 | | - |
53 | | - // OpenStorageTrie opens the storage trie of an account. |
54 | | - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) |
55 | | -} |
| 19 | +import "github.com/ethereum/go-ethereum/common" |
56 | 20 |
|
57 | 21 | // Set represents a collection of mutated states during a state transition. |
58 | 22 | // The value refers to the original content of state before the transition |
@@ -87,177 +51,3 @@ func (s *Set) Size() common.StorageSize { |
87 | 51 | } |
88 | 52 | return s.size |
89 | 53 | } |
90 | | - |
91 | | -// context wraps all fields for executing state diffs. |
92 | | -type context struct { |
93 | | - prevRoot common.Hash |
94 | | - postRoot common.Hash |
95 | | - accounts map[common.Address][]byte |
96 | | - storages map[common.Address]map[common.Hash][]byte |
97 | | - accountTrie Trie |
98 | | - nodes *trienode.MergedNodeSet |
99 | | -} |
100 | | - |
101 | | -// Apply traverses the provided state diffs, apply them in the associated |
102 | | -// post-state and return the generated dirty trie nodes. The state can be |
103 | | -// loaded via the provided trie loader. |
104 | | -func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) { |
105 | | - tr, err := loader.OpenTrie(postRoot) |
106 | | - if err != nil { |
107 | | - return nil, err |
108 | | - } |
109 | | - ctx := &context{ |
110 | | - prevRoot: prevRoot, |
111 | | - postRoot: postRoot, |
112 | | - accounts: accounts, |
113 | | - storages: storages, |
114 | | - accountTrie: tr, |
115 | | - nodes: trienode.NewMergedNodeSet(), |
116 | | - } |
117 | | - for addr, account := range accounts { |
118 | | - var err error |
119 | | - if len(account) == 0 { |
120 | | - err = deleteAccount(ctx, loader, addr) |
121 | | - } else { |
122 | | - err = updateAccount(ctx, loader, addr) |
123 | | - } |
124 | | - if err != nil { |
125 | | - return nil, fmt.Errorf("failed to revert state, err: %w", err) |
126 | | - } |
127 | | - } |
128 | | - root, result := tr.Commit(false) |
129 | | - if root != prevRoot { |
130 | | - return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) |
131 | | - } |
132 | | - if err := ctx.nodes.Merge(result); err != nil { |
133 | | - return nil, err |
134 | | - } |
135 | | - return ctx.nodes.Flatten(), nil |
136 | | -} |
137 | | - |
138 | | -// updateAccount the account was present in prev-state, and may or may not |
139 | | -// existent in post-state. Apply the reverse diff and verify if the storage |
140 | | -// root matches the one in prev-state account. |
141 | | -func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { |
142 | | - // The account was present in prev-state, decode it from the |
143 | | - // 'slim-rlp' format bytes. |
144 | | - h := newHasher() |
145 | | - defer h.release() |
146 | | - |
147 | | - addrHash := h.hash(addr.Bytes()) |
148 | | - prev, err := types.FullAccount(ctx.accounts[addr]) |
149 | | - if err != nil { |
150 | | - return err |
151 | | - } |
152 | | - // The account may or may not existent in post-state, try to |
153 | | - // load it and decode if it's found. |
154 | | - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) |
155 | | - if err != nil { |
156 | | - return err |
157 | | - } |
158 | | - post := types.NewEmptyStateAccount() |
159 | | - if len(blob) != 0 { |
160 | | - if err := rlp.DecodeBytes(blob, &post); err != nil { |
161 | | - return err |
162 | | - } |
163 | | - } |
164 | | - // Apply all storage changes into the post-state storage trie. |
165 | | - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) |
166 | | - if err != nil { |
167 | | - return err |
168 | | - } |
169 | | - for key, val := range ctx.storages[addr] { |
170 | | - var err error |
171 | | - if len(val) == 0 { |
172 | | - err = st.Delete(key.Bytes()) |
173 | | - } else { |
174 | | - err = st.Update(key.Bytes(), val) |
175 | | - } |
176 | | - if err != nil { |
177 | | - return err |
178 | | - } |
179 | | - } |
180 | | - root, result := st.Commit(false) |
181 | | - if root != prev.Root { |
182 | | - return errors.New("failed to reset storage trie") |
183 | | - } |
184 | | - // The returned set can be nil if storage trie is not changed |
185 | | - // at all. |
186 | | - if result != nil { |
187 | | - if err := ctx.nodes.Merge(result); err != nil { |
188 | | - return err |
189 | | - } |
190 | | - } |
191 | | - // Write the prev-state account into the main trie |
192 | | - full, err := rlp.EncodeToBytes(prev) |
193 | | - if err != nil { |
194 | | - return err |
195 | | - } |
196 | | - return ctx.accountTrie.Update(addrHash.Bytes(), full) |
197 | | -} |
198 | | - |
199 | | -// deleteAccount the account was not present in prev-state, and is expected |
200 | | -// to be existent in post-state. Apply the reverse diff and verify if the |
201 | | -// account and storage is wiped out correctly. |
202 | | -func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { |
203 | | - // The account must be existent in post-state, load the account. |
204 | | - h := newHasher() |
205 | | - defer h.release() |
206 | | - |
207 | | - addrHash := h.hash(addr.Bytes()) |
208 | | - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) |
209 | | - if err != nil { |
210 | | - return err |
211 | | - } |
212 | | - if len(blob) == 0 { |
213 | | - return fmt.Errorf("account is non-existent %#x", addrHash) |
214 | | - } |
215 | | - var post types.StateAccount |
216 | | - if err := rlp.DecodeBytes(blob, &post); err != nil { |
217 | | - return err |
218 | | - } |
219 | | - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) |
220 | | - if err != nil { |
221 | | - return err |
222 | | - } |
223 | | - for key, val := range ctx.storages[addr] { |
224 | | - if len(val) != 0 { |
225 | | - return errors.New("expect storage deletion") |
226 | | - } |
227 | | - if err := st.Delete(key.Bytes()); err != nil { |
228 | | - return err |
229 | | - } |
230 | | - } |
231 | | - root, result := st.Commit(false) |
232 | | - if root != types.EmptyRootHash { |
233 | | - return errors.New("failed to clear storage trie") |
234 | | - } |
235 | | - // The returned set can be nil if storage trie is not changed |
236 | | - // at all. |
237 | | - if result != nil { |
238 | | - if err := ctx.nodes.Merge(result); err != nil { |
239 | | - return err |
240 | | - } |
241 | | - } |
242 | | - // Delete the post-state account from the main trie. |
243 | | - return ctx.accountTrie.Delete(addrHash.Bytes()) |
244 | | -} |
245 | | - |
246 | | -// hasher is used to compute the sha256 hash of the provided data. |
247 | | -type hasher struct{ sha crypto.KeccakState } |
248 | | - |
249 | | -var hasherPool = sync.Pool{ |
250 | | - New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, |
251 | | -} |
252 | | - |
253 | | -func newHasher() *hasher { |
254 | | - return hasherPool.Get().(*hasher) |
255 | | -} |
256 | | - |
257 | | -func (h *hasher) hash(data []byte) common.Hash { |
258 | | - return crypto.HashData(h.sha, data) |
259 | | -} |
260 | | - |
261 | | -func (h *hasher) release() { |
262 | | - hasherPool.Put(h) |
263 | | -} |
0 commit comments