Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
817553cc
Unverified
Commit
817553cc
authored
Jul 31, 2023
by
rjl493456442
Committed by
GitHub
Jul 31, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core, trie: track state change set with account address (#27815)
parent
43a1a48e
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
60 additions
and
57 deletions
+60
-57
journal.go
core/state/journal.go
+2
-2
state_object.go
core/state/state_object.go
+2
-2
statedb.go
core/state/statedb.go
+40
-40
statedb_fuzz_test.go
core/state/statedb_fuzz_test.go
+13
-10
state.go
trie/triestate/state.go
+3
-3
No files found.
core/state/journal.go
View file @
817553cc
...
...
@@ -173,10 +173,10 @@ func (ch resetObjectChange) revert(s *StateDB) {
s
.
storages
[
ch
.
prev
.
addrHash
]
=
ch
.
prevStorage
}
if
ch
.
prevAccountOriginExist
{
s
.
accountsOrigin
[
ch
.
prev
.
addr
Hash
]
=
ch
.
prevAccountOrigin
s
.
accountsOrigin
[
ch
.
prev
.
addr
ess
]
=
ch
.
prevAccountOrigin
}
if
ch
.
prevStorageOrigin
!=
nil
{
s
.
storagesOrigin
[
ch
.
prev
.
addr
Hash
]
=
ch
.
prevStorageOrigin
s
.
storagesOrigin
[
ch
.
prev
.
addr
ess
]
=
ch
.
prevStorageOrigin
}
}
...
...
core/state/state_object.go
View file @
817553cc
...
...
@@ -328,9 +328,9 @@ func (s *stateObject) updateTrie() (Trie, error) {
// Cache the original value of mutated storage slots
if
origin
==
nil
{
if
origin
=
s
.
db
.
storagesOrigin
[
s
.
addr
Hash
];
origin
==
nil
{
if
origin
=
s
.
db
.
storagesOrigin
[
s
.
addr
ess
];
origin
==
nil
{
origin
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
db
.
storagesOrigin
[
s
.
addr
Hash
]
=
origin
s
.
db
.
storagesOrigin
[
s
.
addr
ess
]
=
origin
}
}
// Track the original value of slot only if it's mutated first time
...
...
core/state/statedb.go
View file @
817553cc
...
...
@@ -81,8 +81,8 @@ type StateDB struct {
// original value) that occurred in this **block**.
accounts
map
[
common
.
Hash
][]
byte
// The mutated accounts in 'slim RLP' encoding
storages
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
// The mutated slots in prefix-zero trimmed rlp format
accountsOrigin
map
[
common
.
Hash
][]
byte
// The original value of mutated accounts in 'slim RLP' encoding
storagesOrigin
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
// The original value of mutated slots in prefix-zero trimmed rlp format
accountsOrigin
map
[
common
.
Address
][]
byte
// The original value of mutated accounts in 'slim RLP' encoding
storagesOrigin
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
// The original value of mutated slots in prefix-zero trimmed rlp format
// This map holds 'live' objects, which will get modified while processing
// a state transition.
...
...
@@ -157,8 +157,8 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
snaps
:
snaps
,
accounts
:
make
(
map
[
common
.
Hash
][]
byte
),
storages
:
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
),
accountsOrigin
:
make
(
map
[
common
.
Hash
][]
byte
),
storagesOrigin
:
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
),
accountsOrigin
:
make
(
map
[
common
.
Address
][]
byte
),
storagesOrigin
:
make
(
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
),
stateObjects
:
make
(
map
[
common
.
Address
]
*
stateObject
),
stateObjectsPending
:
make
(
map
[
common
.
Address
]
struct
{}),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{}),
...
...
@@ -555,11 +555,11 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
// Track the original value of mutated account, nil means it was not present.
// Skip if it has been tracked (because updateStateObject may be called
// multiple times in a block).
if
_
,
ok
:=
s
.
accountsOrigin
[
obj
.
addr
Hash
];
!
ok
{
if
_
,
ok
:=
s
.
accountsOrigin
[
obj
.
addr
ess
];
!
ok
{
if
obj
.
origin
==
nil
{
s
.
accountsOrigin
[
obj
.
addr
Hash
]
=
nil
s
.
accountsOrigin
[
obj
.
addr
ess
]
=
nil
}
else
{
s
.
accountsOrigin
[
obj
.
addr
Hash
]
=
types
.
SlimAccountRLP
(
*
obj
.
origin
)
s
.
accountsOrigin
[
obj
.
addr
ess
]
=
types
.
SlimAccountRLP
(
*
obj
.
origin
)
}
}
}
...
...
@@ -676,7 +676,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
// There may be some cached account/storage data already since IntermediateRoot
// will be called for each transaction before byzantium fork which will always
// cache the latest account/storage data.
prevAccount
,
ok
:=
s
.
accountsOrigin
[
prev
.
addr
Hash
]
prevAccount
,
ok
:=
s
.
accountsOrigin
[
prev
.
addr
ess
]
s
.
journal
.
append
(
resetObjectChange
{
account
:
&
addr
,
prev
:
prev
,
...
...
@@ -685,12 +685,12 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
prevStorage
:
s
.
storages
[
prev
.
addrHash
],
prevAccountOriginExist
:
ok
,
prevAccountOrigin
:
prevAccount
,
prevStorageOrigin
:
s
.
storagesOrigin
[
prev
.
addr
Hash
],
prevStorageOrigin
:
s
.
storagesOrigin
[
prev
.
addr
ess
],
})
delete
(
s
.
accounts
,
prev
.
addrHash
)
delete
(
s
.
storages
,
prev
.
addrHash
)
delete
(
s
.
accountsOrigin
,
prev
.
addr
Hash
)
delete
(
s
.
storagesOrigin
,
prev
.
addr
Hash
)
delete
(
s
.
accountsOrigin
,
prev
.
addr
ess
)
delete
(
s
.
storagesOrigin
,
prev
.
addr
ess
)
}
newobj
.
created
=
true
...
...
@@ -766,8 +766,8 @@ func (s *StateDB) Copy() *StateDB {
originalRoot
:
s
.
originalRoot
,
accounts
:
make
(
map
[
common
.
Hash
][]
byte
),
storages
:
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
),
accountsOrigin
:
make
(
map
[
common
.
Hash
][]
byte
),
storagesOrigin
:
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
),
accountsOrigin
:
make
(
map
[
common
.
Address
][]
byte
),
storagesOrigin
:
make
(
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
),
stateObjects
:
make
(
map
[
common
.
Address
]
*
stateObject
,
len
(
s
.
journal
.
dirties
)),
stateObjectsPending
:
make
(
map
[
common
.
Address
]
struct
{},
len
(
s
.
stateObjectsPending
)),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{},
len
(
s
.
journal
.
dirties
)),
...
...
@@ -824,10 +824,10 @@ func (s *StateDB) Copy() *StateDB {
}
// Deep copy the state changes made in the scope of block
// along with their original values.
state
.
accounts
=
copy
Accounts
(
s
.
accounts
)
state
.
storages
=
copy
Storages
(
s
.
storages
)
state
.
accountsOrigin
=
copy
Accounts
(
state
.
accountsOrigin
)
state
.
storagesOrigin
=
copy
Storages
(
state
.
storagesOrigin
)
state
.
accounts
=
copy
Set
(
s
.
accounts
)
state
.
storages
=
copy
2DSet
(
s
.
storages
)
state
.
accountsOrigin
=
copy
Set
(
state
.
accountsOrigin
)
state
.
storagesOrigin
=
copy
2DSet
(
state
.
storagesOrigin
)
// Deep copy the logs occurred in the scope of block
for
hash
,
logs
:=
range
s
.
logs
{
...
...
@@ -919,8 +919,8 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
// resurrect an account; but the snapshotter needs both events.
delete
(
s
.
accounts
,
obj
.
addrHash
)
// Clear out any previously updated account data (may be recreated via a resurrect)
delete
(
s
.
storages
,
obj
.
addrHash
)
// Clear out any previously updated storage data (may be recreated via a resurrect)
delete
(
s
.
accountsOrigin
,
obj
.
addr
Hash
)
// Clear out any previously updated account data (may be recreated via a resurrect)
delete
(
s
.
storagesOrigin
,
obj
.
addr
Hash
)
// Clear out any previously updated storage data (may be recreated via a resurrect)
delete
(
s
.
accountsOrigin
,
obj
.
addr
ess
)
// Clear out any previously updated account data (may be recreated via a resurrect)
delete
(
s
.
storagesOrigin
,
obj
.
addr
ess
)
// Clear out any previously updated storage data (may be recreated via a resurrect)
}
else
{
obj
.
finalise
(
true
)
// Prefetch slots in the background
}
...
...
@@ -1098,8 +1098,8 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
//
// In case (d), **original** account along with its storages should be deleted,
// with their values be tracked as original value.
func
(
s
*
StateDB
)
handleDestruction
(
nodes
*
trienode
.
MergedNodeSet
)
(
map
[
common
.
Hash
]
struct
{},
error
)
{
incomplete
:=
make
(
map
[
common
.
Hash
]
struct
{})
func
(
s
*
StateDB
)
handleDestruction
(
nodes
*
trienode
.
MergedNodeSet
)
(
map
[
common
.
Address
]
struct
{},
error
)
{
incomplete
:=
make
(
map
[
common
.
Address
]
struct
{})
for
addr
,
prev
:=
range
s
.
stateObjectsDestruct
{
// The original account was non-existing, and it's marked as destructed
// in the scope of block. It can be case (a) or (b).
...
...
@@ -1109,12 +1109,12 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.H
addrHash
:=
crypto
.
Keccak256Hash
(
addr
[
:
])
if
prev
==
nil
{
if
_
,
ok
:=
s
.
accounts
[
addrHash
];
ok
{
s
.
accountsOrigin
[
addr
Hash
]
=
nil
// case (b)
s
.
accountsOrigin
[
addr
]
=
nil
// case (b)
}
continue
}
// It can overwrite the data in s.accountsOrigin set by 'updateStateObject'.
s
.
accountsOrigin
[
addr
Hash
]
=
types
.
SlimAccountRLP
(
*
prev
)
// case (c) or (d)
s
.
accountsOrigin
[
addr
]
=
types
.
SlimAccountRLP
(
*
prev
)
// case (c) or (d)
// Short circuit if the storage was empty.
if
prev
.
Root
==
types
.
EmptyRootHash
{
...
...
@@ -1130,17 +1130,17 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.H
// created. In this case, wipe the entire storage state diff because
// of aborted deletion.
if
aborted
{
incomplete
[
addr
Hash
]
=
struct
{}{}
delete
(
s
.
storagesOrigin
,
addr
Hash
)
incomplete
[
addr
]
=
struct
{}{}
delete
(
s
.
storagesOrigin
,
addr
)
continue
}
if
s
.
storagesOrigin
[
addr
Hash
]
==
nil
{
s
.
storagesOrigin
[
addr
Hash
]
=
slots
if
s
.
storagesOrigin
[
addr
]
==
nil
{
s
.
storagesOrigin
[
addr
]
=
slots
}
else
{
// It can overwrite the data in s.storagesOrigin[addrHash] set by
// 'object.updateTrie'.
for
key
,
val
:=
range
slots
{
s
.
storagesOrigin
[
addr
Hash
][
key
]
=
val
s
.
storagesOrigin
[
addr
][
key
]
=
val
}
}
if
err
:=
nodes
.
Merge
(
set
);
err
!=
nil
{
...
...
@@ -1290,8 +1290,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// Clear all internal flags at the end of commit operation.
s
.
accounts
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
storages
=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
s
.
accountsOrigin
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
storagesOrigin
=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
s
.
accountsOrigin
=
make
(
map
[
common
.
Address
][]
byte
)
s
.
storagesOrigin
=
make
(
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
)
s
.
stateObjectsDirty
=
make
(
map
[
common
.
Address
]
struct
{})
s
.
stateObjectsDestruct
=
make
(
map
[
common
.
Address
]
*
types
.
StateAccount
)
return
root
,
nil
...
...
@@ -1387,18 +1387,18 @@ func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount)
return
ret
}
// copy
Accounts returns a deep-copied account set of the provided one
.
func
copy
Accounts
(
set
map
[
common
.
Hash
][]
byte
)
map
[
common
.
Hash
][]
byte
{
copied
:=
make
(
map
[
common
.
Hash
][]
byte
,
len
(
set
))
// copy
Set returns a deep-copied set
.
func
copy
Set
[
k
comparable
](
set
map
[
k
][]
byte
)
map
[
k
][]
byte
{
copied
:=
make
(
map
[
k
][]
byte
,
len
(
set
))
for
key
,
val
:=
range
set
{
copied
[
key
]
=
common
.
CopyBytes
(
val
)
}
return
copied
}
// copy
Storages returns a deep-copied storage set of the provided one
.
func
copy
Storages
(
set
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
{
copied
:=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
,
len
(
set
))
// copy
2DSet returns a two-dimensional deep-copied set
.
func
copy
2DSet
[
k
comparable
](
set
map
[
k
]
map
[
common
.
Hash
][]
byte
)
map
[
k
]
map
[
common
.
Hash
][]
byte
{
copied
:=
make
(
map
[
k
]
map
[
common
.
Hash
][]
byte
,
len
(
set
))
for
addr
,
subset
:=
range
set
{
copied
[
addr
]
=
make
(
map
[
common
.
Hash
][]
byte
,
len
(
subset
))
for
key
,
val
:=
range
subset
{
...
...
core/state/statedb_fuzz_test.go
View file @
817553cc
...
...
@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/triestate"
...
...
@@ -171,11 +172,11 @@ func (test *stateTest) String() string {
func
(
test
*
stateTest
)
run
()
bool
{
var
(
roots
[]
common
.
Hash
accountList
[]
map
[
common
.
Hash
][]
byte
storageList
[]
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
accountList
[]
map
[
common
.
Address
][]
byte
storageList
[]
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
onCommit
=
func
(
states
*
triestate
.
Set
)
{
accountList
=
append
(
accountList
,
copy
Accounts
(
states
.
Accounts
))
storageList
=
append
(
storageList
,
copy
Storages
(
states
.
Storages
))
accountList
=
append
(
accountList
,
copy
Set
(
states
.
Accounts
))
storageList
=
append
(
storageList
,
copy
2DSet
(
states
.
Storages
))
}
disk
=
rawdb
.
NewMemoryDatabase
()
tdb
=
trie
.
NewDatabaseWithConfig
(
disk
,
&
trie
.
Config
{
OnCommit
:
onCommit
})
...
...
@@ -235,8 +236,9 @@ func (test *stateTest) run() bool {
// - the account was indeed not present in trie
// - the account is present in new trie, nil->nil is regarded as invalid
// - the slots transition is correct
func
(
test
*
stateTest
)
verifyAccountCreation
(
next
common
.
Hash
,
db
*
trie
.
Database
,
otr
,
ntr
*
trie
.
Trie
,
addr
Hash
common
.
Hash
,
slots
map
[
common
.
Hash
][]
byte
)
error
{
func
(
test
*
stateTest
)
verifyAccountCreation
(
next
common
.
Hash
,
db
*
trie
.
Database
,
otr
,
ntr
*
trie
.
Trie
,
addr
common
.
Address
,
slots
map
[
common
.
Hash
][]
byte
)
error
{
// Verify account change
addrHash
:=
crypto
.
Keccak256Hash
(
addr
.
Bytes
())
oBlob
,
err
:=
otr
.
Get
(
addrHash
.
Bytes
())
if
err
!=
nil
{
return
err
...
...
@@ -285,8 +287,9 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *trie.Database
// - the account was indeed present in trie
// - the account in old trie matches the provided value
// - the slots transition is correct
func
(
test
*
stateTest
)
verifyAccountUpdate
(
next
common
.
Hash
,
db
*
trie
.
Database
,
otr
,
ntr
*
trie
.
Trie
,
addr
Hash
common
.
Hash
,
origin
[]
byte
,
slots
map
[
common
.
Hash
][]
byte
)
error
{
func
(
test
*
stateTest
)
verifyAccountUpdate
(
next
common
.
Hash
,
db
*
trie
.
Database
,
otr
,
ntr
*
trie
.
Trie
,
addr
common
.
Address
,
origin
[]
byte
,
slots
map
[
common
.
Hash
][]
byte
)
error
{
// Verify account change
addrHash
:=
crypto
.
Keccak256Hash
(
addr
.
Bytes
())
oBlob
,
err
:=
otr
.
Get
(
addrHash
.
Bytes
())
if
err
!=
nil
{
return
err
...
...
@@ -338,7 +341,7 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *trie.Database,
return
nil
}
func
(
test
*
stateTest
)
verify
(
root
common
.
Hash
,
next
common
.
Hash
,
db
*
trie
.
Database
,
accountsOrigin
map
[
common
.
Hash
][]
byte
,
storagesOrigin
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
error
{
func
(
test
*
stateTest
)
verify
(
root
common
.
Hash
,
next
common
.
Hash
,
db
*
trie
.
Database
,
accountsOrigin
map
[
common
.
Address
][]
byte
,
storagesOrigin
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
)
error
{
otr
,
err
:=
trie
.
New
(
trie
.
StateTrieID
(
root
),
db
)
if
err
!=
nil
{
return
err
...
...
@@ -347,12 +350,12 @@ func (test *stateTest) verify(root common.Hash, next common.Hash, db *trie.Datab
if
err
!=
nil
{
return
err
}
for
addr
Hash
,
account
:=
range
accountsOrigin
{
for
addr
,
account
:=
range
accountsOrigin
{
var
err
error
if
len
(
account
)
==
0
{
err
=
test
.
verifyAccountCreation
(
next
,
db
,
otr
,
ntr
,
addr
Hash
,
storagesOrigin
[
addrHash
])
err
=
test
.
verifyAccountCreation
(
next
,
db
,
otr
,
ntr
,
addr
,
storagesOrigin
[
addr
])
}
else
{
err
=
test
.
verifyAccountUpdate
(
next
,
db
,
otr
,
ntr
,
addr
Hash
,
accountsOrigin
[
addrHash
],
storagesOrigin
[
addrHash
])
err
=
test
.
verifyAccountUpdate
(
next
,
db
,
otr
,
ntr
,
addr
,
accountsOrigin
[
addr
],
storagesOrigin
[
addr
])
}
if
err
!=
nil
{
return
err
...
...
trie/triestate/state.go
View file @
817553cc
...
...
@@ -22,7 +22,7 @@ import "github.com/ethereum/go-ethereum/common"
// The value refers to the original content of state before the transition
// is made. Nil means that the state was not present previously.
type
Set
struct
{
Accounts
map
[
common
.
Hash
][]
byte
// Mutated account set, nil means the account was not present
Storages
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
// Mutated storage set, nil means the slot was not present
Incomplete
map
[
common
.
Hash
]
struct
{}
// Indicator whether the storage slot is incomplete due to large deletion
Accounts
map
[
common
.
Address
][]
byte
// Mutated account set, nil means the account was not present
Storages
map
[
common
.
Address
]
map
[
common
.
Hash
][]
byte
// Mutated storage set, nil means the slot was not present
Incomplete
map
[
common
.
Address
]
struct
{}
// Indicator whether the storage slot is incomplete due to large deletion
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment