mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
access list implementation
This commit is contained in:
parent
08c8b12821
commit
f2b483d6ad
41
nimbus/db/access_list.nim
Normal file
41
nimbus/db/access_list.nim
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import
|
||||||
|
tables, sets,
|
||||||
|
stint,
|
||||||
|
eth/common
|
||||||
|
|
||||||
|
type
|
||||||
|
SlotSet = HashSet[UInt256]
|
||||||
|
|
||||||
|
AccessList* = object
|
||||||
|
slots: Table[EthAddress, SlotSet]
|
||||||
|
|
||||||
|
proc init*(ac: var AccessList) =
|
||||||
|
ac.slots = initTable[EthAddress, SlotSet]()
|
||||||
|
|
||||||
|
proc init*(_: type AccessList): AccessList {.inline.} =
|
||||||
|
result.init()
|
||||||
|
|
||||||
|
func contains*(ac: AccessList, address: EthAddress): bool {.inline.} =
|
||||||
|
address in ac.slots
|
||||||
|
|
||||||
|
# returnValue: (addressPresent, slotPresent)
|
||||||
|
func contains*(ac: var AccessList, address: EthAddress, slot: UInt256): bool =
|
||||||
|
ac.slots.withValue(address, val):
|
||||||
|
result = slot in val[]
|
||||||
|
|
||||||
|
proc merge*(ac: var AccessList, other: AccessList) {.inline.} =
|
||||||
|
for k, v in other.slots:
|
||||||
|
ac.slots.withValue(k, val):
|
||||||
|
val[].incl v
|
||||||
|
do:
|
||||||
|
ac.slots[k] = v
|
||||||
|
|
||||||
|
proc add*(ac: var AccessList, address: EthAddress) =
|
||||||
|
if address notin ac.slots:
|
||||||
|
ac.slots[address] = initHashSet[UInt256]()
|
||||||
|
|
||||||
|
proc add*(ac: var AccessList, address: EthAddress, slot: UInt256) =
|
||||||
|
ac.slots.withValue(address, val):
|
||||||
|
val[].incl slot
|
||||||
|
do:
|
||||||
|
ac.slots[address] = toHashSet([slot])
|
@ -2,7 +2,8 @@ import
|
|||||||
tables, hashes, sets,
|
tables, hashes, sets,
|
||||||
eth/[common, rlp], eth/trie/[hexary, db, trie_defs],
|
eth/[common, rlp], eth/trie/[hexary, db, trie_defs],
|
||||||
../constants, ../utils, storage_types,
|
../constants, ../utils, storage_types,
|
||||||
../../stateless/multi_keys
|
../../stateless/multi_keys,
|
||||||
|
./access_list
|
||||||
|
|
||||||
type
|
type
|
||||||
AccountFlag = enum
|
AccountFlag = enum
|
||||||
@ -45,6 +46,7 @@ type
|
|||||||
SavePoint* = ref object
|
SavePoint* = ref object
|
||||||
parentSavepoint: SavePoint
|
parentSavepoint: SavePoint
|
||||||
cache: Table[EthAddress, RefAccount]
|
cache: Table[EthAddress, RefAccount]
|
||||||
|
accessList: access_list.AccessList
|
||||||
state: TransactionState
|
state: TransactionState
|
||||||
|
|
||||||
const
|
const
|
||||||
@ -83,6 +85,7 @@ proc rootHash*(ac: AccountsCache): KeccakHash =
|
|||||||
proc beginSavepoint*(ac: var AccountsCache): SavePoint =
|
proc beginSavepoint*(ac: var AccountsCache): SavePoint =
|
||||||
new result
|
new result
|
||||||
result.cache = initTable[EthAddress, RefAccount]()
|
result.cache = initTable[EthAddress, RefAccount]()
|
||||||
|
result.accessList.init()
|
||||||
result.state = Pending
|
result.state = Pending
|
||||||
result.parentSavepoint = ac.savePoint
|
result.parentSavepoint = ac.savePoint
|
||||||
ac.savePoint = result
|
ac.savePoint = result
|
||||||
@ -106,6 +109,8 @@ proc commit*(ac: var AccountsCache, sp: Savepoint) =
|
|||||||
ac.savePoint = sp.parentSavepoint
|
ac.savePoint = sp.parentSavepoint
|
||||||
for k, v in sp.cache:
|
for k, v in sp.cache:
|
||||||
sp.parentSavepoint.cache[k] = v
|
sp.parentSavepoint.cache[k] = v
|
||||||
|
|
||||||
|
ac.savePoint.accessList.merge(sp.accessList)
|
||||||
sp.state = Committed
|
sp.state = Committed
|
||||||
|
|
||||||
proc dispose*(ac: var AccountsCache, sp: Savepoint) {.inline.} =
|
proc dispose*(ac: var AccountsCache, sp: Savepoint) {.inline.} =
|
||||||
@ -514,6 +519,28 @@ proc makeMultiKeys*(ac: AccountsCache): MultikeysRef =
|
|||||||
result.add(k, v.codeTouched, multiKeys(v.storageKeys))
|
result.add(k, v.codeTouched, multiKeys(v.storageKeys))
|
||||||
result.sort()
|
result.sort()
|
||||||
|
|
||||||
|
proc accessList*(ac: var AccountsCache, address: EthAddress) {.inline.} =
|
||||||
|
ac.savePoint.accessList.add(address)
|
||||||
|
|
||||||
|
proc accessList*(ac: var AccountsCache, address: EthAddress, slot: UInt256) {.inline.} =
|
||||||
|
ac.savePoint.accessList.add(address, slot)
|
||||||
|
|
||||||
|
func inAccessList*(ac: AccountsCache, address: EthAddress): bool =
|
||||||
|
var sp = ac.savePoint
|
||||||
|
while sp != nil:
|
||||||
|
result = sp.accessList.contains(address)
|
||||||
|
if result:
|
||||||
|
return
|
||||||
|
sp = sp.parentSavepoint
|
||||||
|
|
||||||
|
func inAccessList*(ac: AccountsCache, address: EthAddress, slot: UInt256): bool =
|
||||||
|
var sp = ac.savePoint
|
||||||
|
while sp != nil:
|
||||||
|
result = sp.accessList.contains(address, slot)
|
||||||
|
if result:
|
||||||
|
return
|
||||||
|
sp = sp.parentSavepoint
|
||||||
|
|
||||||
proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
|
proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
|
||||||
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
|
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
|
||||||
proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
|
proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
|
||||||
@ -527,3 +554,5 @@ proc accountExists*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
|||||||
proc isDeadAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
proc isDeadAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||||
proc isEmptyAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
proc isEmptyAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||||
proc getCommittedStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): UInt256 {.borrow.}
|
proc getCommittedStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): UInt256 {.borrow.}
|
||||||
|
func inAccessList*(ac: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
|
||||||
|
func inAccessList*(ac: ReadOnlyStateDB, address: EthAddress, slot: UInt256): bool {.borrow.}
|
||||||
|
@ -6,12 +6,13 @@
|
|||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import unittest2, eth/trie/[hexary, db],
|
import unittest2, eth/trie/[hexary, db],
|
||||||
../nimbus/db/state_db, stew/byteutils, eth/common
|
../nimbus/db/state_db, stew/[byteutils, endians2], eth/common
|
||||||
|
|
||||||
include ../nimbus/db/accounts_cache
|
include ../nimbus/db/accounts_cache
|
||||||
|
|
||||||
func initAddr(z: int): EthAddress =
|
func initAddr(z: int): EthAddress =
|
||||||
result[^1] = z.byte
|
const L = sizeof(result)
|
||||||
|
result[L-sizeof(uint32)..^1] = toBytesBE(z.uint32)
|
||||||
|
|
||||||
proc stateDBMain*() =
|
proc stateDBMain*() =
|
||||||
suite "Account State DB":
|
suite "Account State DB":
|
||||||
@ -149,5 +150,69 @@ proc stateDBMain*() =
|
|||||||
let key = contractHashKey(hexary.keccak(code))
|
let key = contractHashKey(hexary.keccak(code))
|
||||||
check acDB.get(key.toOpenArray) == code
|
check acDB.get(key.toOpenArray) == code
|
||||||
|
|
||||||
|
test "accessList operations":
|
||||||
|
proc verifyAddrs(ac: AccountsCache, addrs: varargs[int]): bool =
|
||||||
|
for c in addrs:
|
||||||
|
if not ac.inAccessList(c.initAddr):
|
||||||
|
return false
|
||||||
|
true
|
||||||
|
|
||||||
|
proc verifySlots(ac: AccountsCache, address: int, slots: varargs[int]): bool =
|
||||||
|
let a = address.initAddr
|
||||||
|
if not ac.inAccessList(a):
|
||||||
|
return false
|
||||||
|
|
||||||
|
for c in slots:
|
||||||
|
if not ac.inAccessList(a, c.u256):
|
||||||
|
return false
|
||||||
|
true
|
||||||
|
|
||||||
|
proc accessList(ac: var AccountsCache, address: int) {.inline.} =
|
||||||
|
ac.accessList(address.initAddr)
|
||||||
|
|
||||||
|
proc accessList(ac: var AccountsCache, address, slot: int) {.inline.} =
|
||||||
|
ac.accessList(address.initAddr, slot.u256)
|
||||||
|
|
||||||
|
var ac = init(AccountsCache, acDB)
|
||||||
|
|
||||||
|
ac.accessList(0xaa)
|
||||||
|
ac.accessList(0xbb, 0x01)
|
||||||
|
ac.accessList(0xbb, 0x02)
|
||||||
|
check ac.verifyAddrs(0xaa, 0xbb)
|
||||||
|
check ac.verifySlots(0xbb, 0x01, 0x02)
|
||||||
|
check ac.verifySlots(0xaa, 0x01) == false
|
||||||
|
check ac.verifySlots(0xaa, 0x02) == false
|
||||||
|
|
||||||
|
var sp = ac.beginSavepoint
|
||||||
|
# some new ones
|
||||||
|
ac.accessList(0xbb, 0x03)
|
||||||
|
ac.accessList(0xaa, 0x01)
|
||||||
|
ac.accessList(0xcc, 0x01)
|
||||||
|
ac.accessList(0xcc)
|
||||||
|
|
||||||
|
check ac.verifyAddrs(0xaa, 0xbb, 0xcc)
|
||||||
|
check ac.verifySlots(0xaa, 0x01)
|
||||||
|
check ac.verifySlots(0xbb, 0x01, 0x02, 0x03)
|
||||||
|
check ac.verifySlots(0xcc, 0x01)
|
||||||
|
|
||||||
|
ac.rollback(sp)
|
||||||
|
check ac.verifyAddrs(0xaa, 0xbb)
|
||||||
|
check ac.verifyAddrs(0xcc) == false
|
||||||
|
check ac.verifySlots(0xcc, 0x01) == false
|
||||||
|
|
||||||
|
sp = ac.beginSavepoint
|
||||||
|
ac.accessList(0xbb, 0x03)
|
||||||
|
ac.accessList(0xaa, 0x01)
|
||||||
|
ac.accessList(0xcc, 0x01)
|
||||||
|
ac.accessList(0xcc)
|
||||||
|
ac.accessList(0xdd, 0x04)
|
||||||
|
ac.commit(sp)
|
||||||
|
|
||||||
|
check ac.verifyAddrs(0xaa, 0xbb, 0xcc)
|
||||||
|
check ac.verifySlots(0xaa, 0x01)
|
||||||
|
check ac.verifySlots(0xbb, 0x01, 0x02, 0x03)
|
||||||
|
check ac.verifySlots(0xcc, 0x01)
|
||||||
|
check ac.verifySlots(0xdd, 0x04)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
stateDBMain()
|
stateDBMain()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user