Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
exchain
nebula
Commits
634eb065
Commit
634eb065
authored
Jan 19, 2022
by
Mark Tyneway
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
l2geth: add access lists to statedb
parent
2508c083
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
291 additions
and
0 deletions
+291
-0
journal.go
l2geth/core/state/journal.go
+34
-0
statedb.go
l2geth/core/state/statedb.go
+73
-0
statedb_test.go
l2geth/core/state/statedb_test.go
+174
-0
interface.go
l2geth/core/vm/interface.go
+10
-0
No files found.
l2geth/core/state/journal.go
View file @
634eb065
...
@@ -129,6 +129,15 @@ type (
...
@@ -129,6 +129,15 @@ type (
touchChange
struct
{
touchChange
struct
{
account
*
common
.
Address
account
*
common
.
Address
}
}
// Changes to the access list
accessListAddAccountChange
struct
{
address
*
common
.
Address
}
accessListAddSlotChange
struct
{
address
*
common
.
Address
slot
*
common
.
Hash
}
)
)
func
(
ch
createObjectChange
)
revert
(
s
*
StateDB
)
{
func
(
ch
createObjectChange
)
revert
(
s
*
StateDB
)
{
...
@@ -230,3 +239,28 @@ func (ch addPreimageChange) revert(s *StateDB) {
...
@@ -230,3 +239,28 @@ func (ch addPreimageChange) revert(s *StateDB) {
func
(
ch
addPreimageChange
)
dirtied
()
*
common
.
Address
{
func
(
ch
addPreimageChange
)
dirtied
()
*
common
.
Address
{
return
nil
return
nil
}
}
func
(
ch
accessListAddAccountChange
)
revert
(
s
*
StateDB
)
{
/*
One important invariant here, is that whenever a (addr, slot) is added, if the
addr is not already present, the add causes two journal entries:
- one for the address,
- one for the (address,slot)
Therefore, when unrolling the change, we can always blindly delete the
(addr) at this point, since no storage adds can remain when come upon
a single (addr) change.
*/
s
.
accessList
.
DeleteAddress
(
*
ch
.
address
)
}
func
(
ch
accessListAddAccountChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
func
(
ch
accessListAddSlotChange
)
revert
(
s
*
StateDB
)
{
s
.
accessList
.
DeleteSlot
(
*
ch
.
address
,
*
ch
.
slot
)
}
func
(
ch
accessListAddSlotChange
)
dirtied
()
*
common
.
Address
{
return
nil
}
l2geth/core/state/statedb.go
View file @
634eb065
...
@@ -100,6 +100,9 @@ type StateDB struct {
...
@@ -100,6 +100,9 @@ type StateDB struct {
preimages
map
[
common
.
Hash
][]
byte
preimages
map
[
common
.
Hash
][]
byte
// Per-transaction access list
accessList
*
accessList
// Journal of state modifications. This is the backbone of
// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
// Snapshot and RevertToSnapshot.
journal
*
journal
journal
*
journal
...
@@ -132,6 +135,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
...
@@ -132,6 +135,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
logs
:
make
(
map
[
common
.
Hash
][]
*
types
.
Log
),
logs
:
make
(
map
[
common
.
Hash
][]
*
types
.
Log
),
preimages
:
make
(
map
[
common
.
Hash
][]
byte
),
preimages
:
make
(
map
[
common
.
Hash
][]
byte
),
journal
:
newJournal
(),
journal
:
newJournal
(),
accessList
:
newAccessList
(),
},
nil
},
nil
}
}
...
@@ -163,6 +167,7 @@ func (s *StateDB) Reset(root common.Hash) error {
...
@@ -163,6 +167,7 @@ func (s *StateDB) Reset(root common.Hash) error {
s
.
logs
=
make
(
map
[
common
.
Hash
][]
*
types
.
Log
)
s
.
logs
=
make
(
map
[
common
.
Hash
][]
*
types
.
Log
)
s
.
logSize
=
0
s
.
logSize
=
0
s
.
preimages
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
preimages
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
accessList
=
newAccessList
()
s
.
clearJournalAndRefund
()
s
.
clearJournalAndRefund
()
return
nil
return
nil
}
}
...
@@ -673,6 +678,13 @@ func (s *StateDB) Copy() *StateDB {
...
@@ -673,6 +678,13 @@ func (s *StateDB) Copy() *StateDB {
for
hash
,
preimage
:=
range
s
.
preimages
{
for
hash
,
preimage
:=
range
s
.
preimages
{
state
.
preimages
[
hash
]
=
preimage
state
.
preimages
[
hash
]
=
preimage
}
}
// Do we need to copy the access list? In practice: No. At the start of a
// transaction, the access list is empty. In practice, we only ever copy state
// _between_ transactions/blocks, never in the middle of a transaction.
// However, it doesn't cost us much to copy an empty list, so we do it anyway
// to not blow up if we ever decide copy it in the middle of a transaction
state
.
accessList
=
s
.
accessList
.
Copy
()
return
state
return
state
}
}
...
@@ -764,6 +776,7 @@ func (s *StateDB) Prepare(thash, bhash common.Hash, ti int) {
...
@@ -764,6 +776,7 @@ func (s *StateDB) Prepare(thash, bhash common.Hash, ti int) {
s
.
thash
=
thash
s
.
thash
=
thash
s
.
bhash
=
bhash
s
.
bhash
=
bhash
s
.
txIndex
=
ti
s
.
txIndex
=
ti
s
.
accessList
=
newAccessList
()
}
}
func
(
s
*
StateDB
)
clearJournalAndRefund
()
{
func
(
s
*
StateDB
)
clearJournalAndRefund
()
{
...
@@ -815,3 +828,63 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
...
@@ -815,3 +828,63 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
return
nil
return
nil
})
})
}
}
// PrepareAccessList handles the preparatory steps for executing a state transition with
// regards to both EIP-2929 and EIP-2930:
//
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
//
// This method should only be called if Berlin/2929+2930 is applicable at the current number.
func
(
s
*
StateDB
)
PrepareAccessList
(
sender
common
.
Address
,
dst
*
common
.
Address
,
precompiles
[]
common
.
Address
,
list
types
.
AccessList
)
{
s
.
AddAddressToAccessList
(
sender
)
if
dst
!=
nil
{
s
.
AddAddressToAccessList
(
*
dst
)
}
for
_
,
addr
:=
range
precompiles
{
s
.
AddAddressToAccessList
(
addr
)
}
for
_
,
el
:=
range
list
{
s
.
AddAddressToAccessList
(
el
.
Address
)
for
_
,
key
:=
range
el
.
StorageKeys
{
s
.
AddSlotToAccessList
(
el
.
Address
,
key
)
}
}
}
// AddAddressToAccessList adds the given address to the access list
func
(
s
*
StateDB
)
AddAddressToAccessList
(
addr
common
.
Address
)
{
if
s
.
accessList
.
AddAddress
(
addr
)
{
s
.
journal
.
append
(
accessListAddAccountChange
{
&
addr
})
}
}
// AddSlotToAccessList adds the given (address, slot)-tuple to the access list
func
(
s
*
StateDB
)
AddSlotToAccessList
(
addr
common
.
Address
,
slot
common
.
Hash
)
{
addrMod
,
slotMod
:=
s
.
accessList
.
AddSlot
(
addr
,
slot
)
if
addrMod
{
// In practice, this should not happen, since there is no way to enter the
// scope of 'address' without having the 'address' become already added
// to the access list (via call-variant, create, etc).
// Better safe than sorry, though
s
.
journal
.
append
(
accessListAddAccountChange
{
&
addr
})
}
if
slotMod
{
s
.
journal
.
append
(
accessListAddSlotChange
{
address
:
&
addr
,
slot
:
&
slot
,
})
}
}
// AddressInAccessList returns true if the given address is in the access list.
func
(
s
*
StateDB
)
AddressInAccessList
(
addr
common
.
Address
)
bool
{
return
s
.
accessList
.
ContainsAddress
(
addr
)
}
// SlotInAccessList returns true if the given (address, slot)-tuple is in the access list.
func
(
s
*
StateDB
)
SlotInAccessList
(
addr
common
.
Address
,
slot
common
.
Hash
)
(
addressPresent
bool
,
slotPresent
bool
)
{
return
s
.
accessList
.
Contains
(
addr
,
slot
)
}
l2geth/core/state/statedb_test.go
View file @
634eb065
...
@@ -680,3 +680,177 @@ func TestDeleteCreateRevert(t *testing.T) {
...
@@ -680,3 +680,177 @@ func TestDeleteCreateRevert(t *testing.T) {
t
.
Fatalf
(
"self-destructed contract came alive"
)
t
.
Fatalf
(
"self-destructed contract came alive"
)
}
}
}
}
func
TestStateDBAccessList
(
t
*
testing
.
T
)
{
// Some helpers
addr
:=
func
(
a
string
)
common
.
Address
{
return
common
.
HexToAddress
(
a
)
}
slot
:=
func
(
a
string
)
common
.
Hash
{
return
common
.
HexToHash
(
a
)
}
memDb
:=
rawdb
.
NewMemoryDatabase
()
db
:=
NewDatabase
(
memDb
)
state
,
_
:=
New
(
common
.
Hash
{},
db
)
state
.
accessList
=
newAccessList
()
verifyAddrs
:=
func
(
astrings
...
string
)
{
t
.
Helper
()
// convert to common.Address form
var
addresses
[]
common
.
Address
var
addressMap
=
make
(
map
[
common
.
Address
]
struct
{})
for
_
,
astring
:=
range
astrings
{
address
:=
addr
(
astring
)
addresses
=
append
(
addresses
,
address
)
addressMap
[
address
]
=
struct
{}{}
}
// Check that the given addresses are in the access list
for
_
,
address
:=
range
addresses
{
if
!
state
.
AddressInAccessList
(
address
)
{
t
.
Fatalf
(
"expected %x to be in access list"
,
address
)
}
}
// Check that only the expected addresses are present in the acesslist
for
address
:=
range
state
.
accessList
.
addresses
{
if
_
,
exist
:=
addressMap
[
address
];
!
exist
{
t
.
Fatalf
(
"extra address %x in access list"
,
address
)
}
}
}
verifySlots
:=
func
(
addrString
string
,
slotStrings
...
string
)
{
if
!
state
.
AddressInAccessList
(
addr
(
addrString
))
{
t
.
Fatalf
(
"scope missing address/slots %v"
,
addrString
)
}
var
address
=
addr
(
addrString
)
// convert to common.Hash form
var
slots
[]
common
.
Hash
var
slotMap
=
make
(
map
[
common
.
Hash
]
struct
{})
for
_
,
slotString
:=
range
slotStrings
{
s
:=
slot
(
slotString
)
slots
=
append
(
slots
,
s
)
slotMap
[
s
]
=
struct
{}{}
}
// Check that the expected items are in the access list
for
i
,
s
:=
range
slots
{
if
_
,
slotPresent
:=
state
.
SlotInAccessList
(
address
,
s
);
!
slotPresent
{
t
.
Fatalf
(
"input %d: scope missing slot %v (address %v)"
,
i
,
s
,
addrString
)
}
}
// Check that no extra elements are in the access list
index
:=
state
.
accessList
.
addresses
[
address
]
if
index
>=
0
{
stateSlots
:=
state
.
accessList
.
slots
[
index
]
for
s
:=
range
stateSlots
{
if
_
,
slotPresent
:=
slotMap
[
s
];
!
slotPresent
{
t
.
Fatalf
(
"scope has extra slot %v (address %v)"
,
s
,
addrString
)
}
}
}
}
state
.
AddAddressToAccessList
(
addr
(
"aa"
))
// 1
state
.
AddSlotToAccessList
(
addr
(
"bb"
),
slot
(
"01"
))
// 2,3
state
.
AddSlotToAccessList
(
addr
(
"bb"
),
slot
(
"02"
))
// 4
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"bb"
,
"01"
,
"02"
)
// Make a copy
stateCopy1
:=
state
.
Copy
()
if
exp
,
got
:=
4
,
state
.
journal
.
length
();
exp
!=
got
{
t
.
Fatalf
(
"journal length mismatch: have %d, want %d"
,
got
,
exp
)
}
// same again, should cause no journal entries
state
.
AddSlotToAccessList
(
addr
(
"bb"
),
slot
(
"01"
))
state
.
AddSlotToAccessList
(
addr
(
"bb"
),
slot
(
"02"
))
state
.
AddAddressToAccessList
(
addr
(
"aa"
))
if
exp
,
got
:=
4
,
state
.
journal
.
length
();
exp
!=
got
{
t
.
Fatalf
(
"journal length mismatch: have %d, want %d"
,
got
,
exp
)
}
// some new ones
state
.
AddSlotToAccessList
(
addr
(
"bb"
),
slot
(
"03"
))
// 5
state
.
AddSlotToAccessList
(
addr
(
"aa"
),
slot
(
"01"
))
// 6
state
.
AddSlotToAccessList
(
addr
(
"cc"
),
slot
(
"01"
))
// 7,8
state
.
AddAddressToAccessList
(
addr
(
"cc"
))
if
exp
,
got
:=
8
,
state
.
journal
.
length
();
exp
!=
got
{
t
.
Fatalf
(
"journal length mismatch: have %d, want %d"
,
got
,
exp
)
}
verifyAddrs
(
"aa"
,
"bb"
,
"cc"
)
verifySlots
(
"aa"
,
"01"
)
verifySlots
(
"bb"
,
"01"
,
"02"
,
"03"
)
verifySlots
(
"cc"
,
"01"
)
// now start rolling back changes
state
.
journal
.
revert
(
state
,
7
)
if
_
,
ok
:=
state
.
SlotInAccessList
(
addr
(
"cc"
),
slot
(
"01"
));
ok
{
t
.
Fatalf
(
"slot present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
,
"cc"
)
verifySlots
(
"aa"
,
"01"
)
verifySlots
(
"bb"
,
"01"
,
"02"
,
"03"
)
state
.
journal
.
revert
(
state
,
6
)
if
state
.
AddressInAccessList
(
addr
(
"cc"
))
{
t
.
Fatalf
(
"addr present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"aa"
,
"01"
)
verifySlots
(
"bb"
,
"01"
,
"02"
,
"03"
)
state
.
journal
.
revert
(
state
,
5
)
if
_
,
ok
:=
state
.
SlotInAccessList
(
addr
(
"aa"
),
slot
(
"01"
));
ok
{
t
.
Fatalf
(
"slot present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"bb"
,
"01"
,
"02"
,
"03"
)
state
.
journal
.
revert
(
state
,
4
)
if
_
,
ok
:=
state
.
SlotInAccessList
(
addr
(
"bb"
),
slot
(
"03"
));
ok
{
t
.
Fatalf
(
"slot present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"bb"
,
"01"
,
"02"
)
state
.
journal
.
revert
(
state
,
3
)
if
_
,
ok
:=
state
.
SlotInAccessList
(
addr
(
"bb"
),
slot
(
"02"
));
ok
{
t
.
Fatalf
(
"slot present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"bb"
,
"01"
)
state
.
journal
.
revert
(
state
,
2
)
if
_
,
ok
:=
state
.
SlotInAccessList
(
addr
(
"bb"
),
slot
(
"01"
));
ok
{
t
.
Fatalf
(
"slot present, expected missing"
)
}
verifyAddrs
(
"aa"
,
"bb"
)
state
.
journal
.
revert
(
state
,
1
)
if
state
.
AddressInAccessList
(
addr
(
"bb"
))
{
t
.
Fatalf
(
"addr present, expected missing"
)
}
verifyAddrs
(
"aa"
)
state
.
journal
.
revert
(
state
,
0
)
if
state
.
AddressInAccessList
(
addr
(
"aa"
))
{
t
.
Fatalf
(
"addr present, expected missing"
)
}
if
got
,
exp
:=
len
(
state
.
accessList
.
addresses
),
0
;
got
!=
exp
{
t
.
Fatalf
(
"expected empty, got %d"
,
got
)
}
if
got
,
exp
:=
len
(
state
.
accessList
.
slots
),
0
;
got
!=
exp
{
t
.
Fatalf
(
"expected empty, got %d"
,
got
)
}
// Check the copy
// Make a copy
state
=
stateCopy1
verifyAddrs
(
"aa"
,
"bb"
)
verifySlots
(
"bb"
,
"01"
,
"02"
)
if
got
,
exp
:=
len
(
state
.
accessList
.
addresses
),
2
;
got
!=
exp
{
t
.
Fatalf
(
"expected empty, got %d"
,
got
)
}
if
got
,
exp
:=
len
(
state
.
accessList
.
slots
),
1
;
got
!=
exp
{
t
.
Fatalf
(
"expected empty, got %d"
,
got
)
}
}
l2geth/core/vm/interface.go
View file @
634eb065
...
@@ -57,6 +57,16 @@ type StateDB interface {
...
@@ -57,6 +57,16 @@ type StateDB interface {
// is defined according to EIP161 (balance = nonce = code = 0).
// is defined according to EIP161 (balance = nonce = code = 0).
Empty
(
common
.
Address
)
bool
Empty
(
common
.
Address
)
bool
PrepareAccessList
(
sender
common
.
Address
,
dest
*
common
.
Address
,
precompiles
[]
common
.
Address
,
txAccesses
types
.
AccessList
)
AddressInAccessList
(
addr
common
.
Address
)
bool
SlotInAccessList
(
addr
common
.
Address
,
slot
common
.
Hash
)
(
addressOk
bool
,
slotOk
bool
)
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddAddressToAccessList
(
addr
common
.
Address
)
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList
(
addr
common
.
Address
,
slot
common
.
Hash
)
RevertToSnapshot
(
int
)
RevertToSnapshot
(
int
)
Snapshot
()
int
Snapshot
()
int
...
...
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