Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
d985b905
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
d985b905
编写于
3月 27, 2018
作者:
P
Péter Szilágyi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
core/state: avoid linear overhead on journal dirty listing
上级
958ed4f3
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
92 addition
and
66 deletion
+92
-66
core/state/journal.go
core/state/journal.go
+73
-40
core/state/state_object.go
core/state/state_object.go
+3
-3
core/state/statedb.go
core/state/statedb.go
+14
-21
core/state/statedb_test.go
core/state/statedb_test.go
+2
-2
未找到文件。
core/state/journal.go
浏览文件 @
d985b905
...
...
@@ -22,41 +22,66 @@ import (
"github.com/ethereum/go-ethereum/common"
)
// journalEntry is a modification entry in the state change journal that can be
// reverted on demand.
type
journalEntry
interface
{
undo
(
*
StateDB
)
getAccount
()
*
common
.
Address
// revert undoes the changes introduced by this journal entry.
revert
(
*
StateDB
)
// dirtied returns the Ethereum address modified by this journal entry.
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.
type
journal
struct
{
entries
[]
journalEntry
dirtyOverrides
[]
common
.
Address
entries
[]
journalEntry
// Current changes tracked by the journal
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.
func
(
j
*
journal
)
append
(
entry
journalEntry
)
{
j
.
entries
=
append
(
j
.
entries
,
entry
)
if
addr
:=
entry
.
dirtied
();
addr
!=
nil
{
j
.
dirties
[
*
addr
]
++
}
}
func
(
j
*
journal
)
flatten
()
map
[
common
.
Address
]
struct
{}
{
// revert undoes a batch of journalled modifications along with any reverted
// dirty handling too.
func
(
j
*
journal
)
revert
(
statedb
*
StateDB
,
snapshot
int
)
{
for
i
:=
len
(
j
.
entries
)
-
1
;
i
>=
snapshot
;
i
--
{
// Undo the changes made by the operation
j
.
entries
[
i
]
.
revert
(
statedb
)
dirtyObjects
:=
make
(
map
[
common
.
Address
]
struct
{})
for
_
,
journalEntry
:=
range
j
.
entries
{
if
addr
:=
journalEntry
.
getAccount
();
addr
!=
nil
{
dirtyObjects
[
*
addr
]
=
struct
{}{}
// 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
)
}
}
}
for
_
,
addr
:=
range
j
.
dirtyOverrides
{
dirtyObjects
[
addr
]
=
struct
{}{}
}
return
dirtyObjects
j
.
entries
=
j
.
entries
[
:
snapshot
]
}
// Length returns the number of journal entries in the journal
func
(
j
*
journal
)
Length
()
int
{
return
len
(
j
.
entries
)
// 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
]
++
}
func
(
j
*
journal
)
dirtyOverride
(
address
common
.
Address
)
{
j
.
dirtyOverrides
=
append
(
j
.
dirtyOverrides
,
address
)
// length returns the current number of entries in the journal.
func
(
j
*
journal
)
length
()
int
{
return
len
(
j
.
entries
)
}
type
(
...
...
@@ -108,78 +133,85 @@ type (
}
)
func
(
ch
createObjectChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
createObjectChange
)
revert
(
s
*
StateDB
)
{
delete
(
s
.
stateObjects
,
*
ch
.
account
)
delete
(
s
.
stateObjectsDirty
,
*
ch
.
account
)
}
func
(
ch
createObjectChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
createObjectChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
resetObjectChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
resetObjectChange
)
revert
(
s
*
StateDB
)
{
s
.
setStateObject
(
ch
.
prev
)
}
func
(
ch
resetObjectChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
resetObjectChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
func
(
ch
suicideChange
)
undo
(
s
*
StateDB
)
{
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
)
getAccount
()
*
common
.
Address
{
func
(
ch
suicideChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
var
ripemd
=
common
.
HexToAddress
(
"0000000000000000000000000000000000000003"
)
func
(
ch
touchChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
touchChange
)
revert
(
s
*
StateDB
)
{
}
func
(
ch
touchChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
touchChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
balanceChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
balanceChange
)
revert
(
s
*
StateDB
)
{
s
.
getStateObject
(
*
ch
.
account
)
.
setBalance
(
ch
.
prev
)
}
func
(
ch
balanceChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
balanceChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
nonceChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
nonceChange
)
revert
(
s
*
StateDB
)
{
s
.
getStateObject
(
*
ch
.
account
)
.
setNonce
(
ch
.
prev
)
}
func
(
ch
nonceChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
nonceChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
codeChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
codeChange
)
revert
(
s
*
StateDB
)
{
s
.
getStateObject
(
*
ch
.
account
)
.
setCode
(
common
.
BytesToHash
(
ch
.
prevhash
),
ch
.
prevcode
)
}
func
(
ch
codeChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
codeChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
storageChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
storageChange
)
revert
(
s
*
StateDB
)
{
s
.
getStateObject
(
*
ch
.
account
)
.
setState
(
ch
.
key
,
ch
.
prevalue
)
}
func
(
ch
storageChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
storageChange
)
dirtied
()
*
common
.
Address
{
return
ch
.
account
}
func
(
ch
refundChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
refundChange
)
revert
(
s
*
StateDB
)
{
s
.
refund
=
ch
.
prev
}
func
(
ch
refundChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
refundChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
func
(
ch
addLogChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
addLogChange
)
revert
(
s
*
StateDB
)
{
logs
:=
s
.
logs
[
ch
.
txhash
]
if
len
(
logs
)
==
1
{
delete
(
s
.
logs
,
ch
.
txhash
)
...
...
@@ -188,14 +220,15 @@ func (ch addLogChange) undo(s *StateDB) {
}
s
.
logSize
--
}
func
(
ch
addLogChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
addLogChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
func
(
ch
addPreimageChange
)
undo
(
s
*
StateDB
)
{
func
(
ch
addPreimageChange
)
revert
(
s
*
StateDB
)
{
delete
(
s
.
preimages
,
ch
.
hash
)
}
func
(
ch
addPreimageChange
)
getAccount
()
*
common
.
Address
{
func
(
ch
addPreimageChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
core/state/state_object.go
浏览文件 @
d985b905
...
...
@@ -141,9 +141,9 @@ func (c *stateObject) touch() {
account
:
&
c
.
address
,
})
if
c
.
address
==
ripemd
{
//
Explicitly put it in the dirty-cache, which is otherwise
//
generated from flattened journals
c
.
db
.
journal
.
dirty
Override
(
c
.
address
)
//
Explicitly put it in the dirty-cache, which is otherwise generated from
//
flattened journals.
c
.
db
.
journal
.
dirty
(
c
.
address
)
}
}
...
...
core/state/statedb.go
浏览文件 @
d985b905
...
...
@@ -76,7 +76,7 @@ type StateDB struct {
// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
journal
journal
journal
*
journal
validRevisions
[]
revision
nextRevisionId
int
...
...
@@ -96,6 +96,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{}),
logs
:
make
(
map
[
common
.
Hash
][]
*
types
.
Log
),
preimages
:
make
(
map
[
common
.
Hash
][]
byte
),
journal
:
newJournal
(),
},
nil
}
...
...
@@ -456,21 +457,20 @@ func (self *StateDB) Copy() *StateDB {
self
.
lock
.
Lock
()
defer
self
.
lock
.
Unlock
()
dirtyObjects
:=
self
.
journal
.
flatten
()
// Copy all the basic fields, initialize the memory ones
state
:=
&
StateDB
{
db
:
self
.
db
,
trie
:
self
.
db
.
CopyTrie
(
self
.
trie
),
stateObjects
:
make
(
map
[
common
.
Address
]
*
stateObject
,
len
(
dirtyObject
s
)),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{},
len
(
dirtyObject
s
)),
stateObjects
:
make
(
map
[
common
.
Address
]
*
stateObject
,
len
(
self
.
journal
.
dirtie
s
)),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{},
len
(
self
.
journal
.
dirtie
s
)),
refund
:
self
.
refund
,
logs
:
make
(
map
[
common
.
Hash
][]
*
types
.
Log
,
len
(
self
.
logs
)),
logSize
:
self
.
logSize
,
preimages
:
make
(
map
[
common
.
Hash
][]
byte
),
journal
:
newJournal
(),
}
// Copy the dirty states, logs, and preimages
for
addr
:=
range
dirtyObject
s
{
for
addr
:=
range
self
.
journal
.
dirtie
s
{
state
.
stateObjects
[
addr
]
=
self
.
stateObjects
[
addr
]
.
deepCopy
(
state
)
state
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
}
...
...
@@ -488,7 +488,7 @@ func (self *StateDB) Copy() *StateDB {
func
(
self
*
StateDB
)
Snapshot
()
int
{
id
:=
self
.
nextRevisionId
self
.
nextRevisionId
++
self
.
validRevisions
=
append
(
self
.
validRevisions
,
revision
{
id
,
self
.
journal
.
L
ength
()})
self
.
validRevisions
=
append
(
self
.
validRevisions
,
revision
{
id
,
self
.
journal
.
l
ength
()})
return
id
}
...
...
@@ -503,13 +503,8 @@ func (self *StateDB) RevertToSnapshot(revid int) {
}
snapshot
:=
self
.
validRevisions
[
idx
]
.
journalIndex
// Replay the journal to undo changes.
for
i
:=
self
.
journal
.
Length
()
-
1
;
i
>=
snapshot
;
i
--
{
self
.
journal
.
entries
[
i
]
.
undo
(
self
)
}
self
.
journal
.
entries
=
self
.
journal
.
entries
[
:
snapshot
]
// Remove invalidated snapshots from the stack.
// Replay the journal to undo changes and remove invalidated snapshots
self
.
journal
.
revert
(
self
,
snapshot
)
self
.
validRevisions
=
self
.
validRevisions
[
:
idx
]
}
...
...
@@ -521,8 +516,7 @@ func (self *StateDB) GetRefund() uint64 {
// Finalise finalises the state by removing the self destructed objects
// and clears the journal as well as the refunds.
func
(
s
*
StateDB
)
Finalise
(
deleteEmptyObjects
bool
)
{
for
addr
,
v
:=
range
s
.
journal
.
flatten
()
{
for
addr
:=
range
s
.
journal
.
dirties
{
stateObject
:=
s
.
stateObjects
[
addr
]
if
stateObject
.
suicided
||
(
deleteEmptyObjects
&&
stateObject
.
empty
())
{
s
.
deleteStateObject
(
stateObject
)
...
...
@@ -530,7 +524,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
stateObject
.
updateRoot
(
s
.
db
)
s
.
updateStateObject
(
stateObject
)
}
s
.
stateObjectsDirty
[
addr
]
=
v
s
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
}
// Invalidate journal because reverting across transactions is not allowed.
s
.
clearJournalAndRefund
()
...
...
@@ -574,7 +568,7 @@ func (s *StateDB) DeleteSuicides() {
}
func
(
s
*
StateDB
)
clearJournalAndRefund
()
{
s
.
journal
=
journal
{}
s
.
journal
=
newJournal
()
s
.
validRevisions
=
s
.
validRevisions
[
:
0
]
s
.
refund
=
0
}
...
...
@@ -583,10 +577,9 @@ func (s *StateDB) clearJournalAndRefund() {
func
(
s
*
StateDB
)
Commit
(
deleteEmptyObjects
bool
)
(
root
common
.
Hash
,
err
error
)
{
defer
s
.
clearJournalAndRefund
()
for
addr
,
v
:=
range
s
.
journal
.
flatten
()
{
s
.
stateObjectsDirty
[
addr
]
=
v
for
addr
:=
range
s
.
journal
.
dirties
{
s
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
}
// Commit objects to the trie.
for
addr
,
stateObject
:=
range
s
.
stateObjects
{
_
,
isDirty
:=
s
.
stateObjectsDirty
[
addr
]
...
...
core/state/statedb_test.go
浏览文件 @
d985b905
...
...
@@ -414,11 +414,11 @@ func (s *StateSuite) TestTouchDelete(c *check.C) {
snapshot
:=
s
.
state
.
Snapshot
()
s
.
state
.
AddBalance
(
common
.
Address
{},
new
(
big
.
Int
))
if
len
(
s
.
state
.
journal
.
flatten
()
)
!=
1
{
if
len
(
s
.
state
.
journal
.
dirties
)
!=
1
{
c
.
Fatal
(
"expected one dirty state object"
)
}
s
.
state
.
RevertToSnapshot
(
snapshot
)
if
len
(
s
.
state
.
journal
.
flatten
()
)
!=
0
{
if
len
(
s
.
state
.
journal
.
dirties
)
!=
0
{
c
.
Fatal
(
"expected no dirty state object"
)
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录