/
journal.go
298 lines (245 loc) · 7.87 KB
/
journal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
// Copyright 2016 The github.com/blockchain-analysis-study/go-ethereum-analysis Authors
// This file is part of the github.com/blockchain-analysis-study/go-ethereum-analysis library.
//
// The github.com/blockchain-analysis-study/go-ethereum-analysis library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The github.com/blockchain-analysis-study/go-ethereum-analysis library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the github.com/blockchain-analysis-study/go-ethereum-analysis library. If not, see <http://www.gnu.org/licenses/>.
package state
import (
"math/big"
"github.com/blockchain-analysis-study/go-ethereum-analysis/common"
)
// journalEntry is a modification entry in the state change journal that can be
// reverted on demand.
//
// journalEntry是 `State更改日记帐` 中的修改条目,可以按需还原。
type journalEntry interface {
// revert undoes the changes introduced by this journal entry.
//
// revert: 撤消此日记帐分录引入的更改。
revert(*StateDB)
// dirtied returns the Ethereum address modified by this journal entry.
//
// dirtied: 返回由该日志条目修改的以太坊地址。
dirtied() *common.Address
}
// journal contains the list of state modifications applied since the last state
// commit. These are tracked to be able to be reverted in case of an execution
// exception or revertal request.
//
/**
journal包含自上次提交State以来应用的State修改列表。 在执行异常或恢复请求的情况下,将跟踪这些 `日志账条目` 以使其能够恢复。
*/
type journal struct {
// 日记跟踪的当前更改
entries []journalEntry // Current changes tracked by the journal
// 最近变更的账户 和 更改次数
//
// Finalise() 和 Commit 都会根据 这个来 for 最近变动的 stateObject
//
// 格式: map[账户]变更次数
dirties map[common.Address]int // Dirty accounts and the number of changes
}
// newJournal create a new initialized journal.
func newJournal() *journal {
return &journal{
dirties: make(map[common.Address]int),
}
}
// append inserts a new modification entry to the end of the change journal.
//
// 追加 `journalEntry` 实例, 并记录对应的 stateObject 的 addr 变动的 次数
func (j *journal) append(entry journalEntry) {
// todo 往 `State的修改杂志` 中添加 日志账条目
j.entries = append(j.entries, entry)
// todo 如果对应的 日志账条目 有 addr 存在的话,则记录下最近日志帐条目中对应的账户 Addr和变更次数
if addr := entry.dirtied(); addr != nil {
j.dirties[*addr]++
}
}
// revert undoes a batch of journalled modifications along with any reverted
// dirty handling too.
func (j *journal) revert(statedb *StateDB, snapshot int) {
// todo 遍历出最近存入的 所有 日志账条目实例,
// 一直遍历到 需要被回滚点为止
for i := len(j.entries) - 1; i >= snapshot; i-- {
// Undo the changes made by the operation
j.entries[i].revert(statedb)
// Drop any dirty tracking induced by the change
//
// 递减 账户的变动 计数
if addr := j.entries[i].dirtied(); addr != nil {
if j.dirties[*addr]--; j.dirties[*addr] == 0 {
delete(j.dirties, *addr)
}
}
}
// 保留 回滚点 之前的 `journalEntry` 实例
j.entries = j.entries[:snapshot]
}
// dirty explicitly sets an address to dirty, even if the change entries would
// otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
// precompile consensus exception.
func (j *journal) dirty(addr common.Address) {
j.dirties[addr]++
}
// length returns the current number of entries in the journal.
func (j *journal) length() int {
return len(j.entries)
}
// todo ###############################
// todo ###############################
// todo ###############################
// todo ###############################
//
// todo 下面这些都是 `journalEntry` 的实现
// todo journalEntry 是 `State更改日记帐` 中的修改条目,可以按需还原。
type (
// Changes to the account trie.
//
// 更改帐户尝试。
// todo 创建账户的 日志帐条目
createObjectChange struct {
account *common.Address
}
// todo 重置账户的 日志帐条目
resetObjectChange struct {
prev *stateObject
}
// todo 账户自杀的 日志账条目
suicideChange struct {
account *common.Address
prev bool // whether account had already suicided
prevbalance *big.Int
}
// Changes to individual accounts.
//
// 更改个人帐户。
// todo 余额变更的 日志帐条目
balanceChange struct {
account *common.Address
prev *big.Int
}
// todo nonce变更的 日志帐条目
nonceChange struct {
account *common.Address
prev uint64
}
// todo 账户的存储数据变更的 日志账条目
storageChange struct {
account *common.Address
key, prevalue common.Hash
}
// todo 账户的code变更的 日志账条目
codeChange struct {
account *common.Address
prevcode, prevhash []byte
}
// Changes to other state values.
//
// 更改为其他状态值。
// todo 需要退款的 日志账条目
refundChange struct {
prev uint64
}
// todo 增加了 log的 日志账条目
addLogChange struct {
txhash common.Hash
}
// todo preimage数据变更的 日志账条目
addPreimageChange struct {
hash common.Hash
}
// todo 这个还没启用 ...
touchChange struct {
account *common.Address
prev bool
prevDirty bool
}
)
func (ch createObjectChange) revert(s *StateDB) {
delete(s.stateObjects, *ch.account)
delete(s.stateObjectsDirty, *ch.account)
}
func (ch createObjectChange) dirtied() *common.Address {
return ch.account
}
func (ch resetObjectChange) revert(s *StateDB) {
s.setStateObject(ch.prev)
}
func (ch resetObjectChange) dirtied() *common.Address {
return nil
}
func (ch suicideChange) revert(s *StateDB) {
obj := s.getStateObject(*ch.account)
if obj != nil {
obj.suicided = ch.prev
obj.setBalance(ch.prevbalance)
}
}
func (ch suicideChange) dirtied() *common.Address {
return ch.account
}
var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
func (ch touchChange) revert(s *StateDB) {
}
func (ch touchChange) dirtied() *common.Address {
return ch.account
}
func (ch balanceChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setBalance(ch.prev)
}
func (ch balanceChange) dirtied() *common.Address {
return ch.account
}
func (ch nonceChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setNonce(ch.prev)
}
func (ch nonceChange) dirtied() *common.Address {
return ch.account
}
func (ch codeChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
}
func (ch codeChange) dirtied() *common.Address {
return ch.account
}
func (ch storageChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
}
func (ch storageChange) dirtied() *common.Address {
return ch.account
}
func (ch refundChange) revert(s *StateDB) {
s.refund = ch.prev
}
func (ch refundChange) dirtied() *common.Address {
return nil
}
func (ch addLogChange) revert(s *StateDB) {
logs := s.logs[ch.txhash]
if len(logs) == 1 {
delete(s.logs, ch.txhash)
} else {
s.logs[ch.txhash] = logs[:len(logs)-1]
}
s.logSize--
}
func (ch addLogChange) dirtied() *common.Address {
return nil
}
func (ch addPreimageChange) revert(s *StateDB) {
delete(s.preimages, ch.hash)
}
func (ch addPreimageChange) dirtied() *common.Address {
return nil
}