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,
|
||||
eth/[common, rlp], eth/trie/[hexary, db, trie_defs],
|
||||
../constants, ../utils, storage_types,
|
||||
../../stateless/multi_keys
|
||||
../../stateless/multi_keys,
|
||||
./access_list
|
||||
|
||||
type
|
||||
AccountFlag = enum
|
||||
@ -45,6 +46,7 @@ type
|
||||
SavePoint* = ref object
|
||||
parentSavepoint: SavePoint
|
||||
cache: Table[EthAddress, RefAccount]
|
||||
accessList: access_list.AccessList
|
||||
state: TransactionState
|
||||
|
||||
const
|
||||
@ -83,6 +85,7 @@ proc rootHash*(ac: AccountsCache): KeccakHash =
|
||||
proc beginSavepoint*(ac: var AccountsCache): SavePoint =
|
||||
new result
|
||||
result.cache = initTable[EthAddress, RefAccount]()
|
||||
result.accessList.init()
|
||||
result.state = Pending
|
||||
result.parentSavepoint = ac.savePoint
|
||||
ac.savePoint = result
|
||||
@ -106,6 +109,8 @@ proc commit*(ac: var AccountsCache, sp: Savepoint) =
|
||||
ac.savePoint = sp.parentSavepoint
|
||||
for k, v in sp.cache:
|
||||
sp.parentSavepoint.cache[k] = v
|
||||
|
||||
ac.savePoint.accessList.merge(sp.accessList)
|
||||
sp.state = Committed
|
||||
|
||||
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.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 getCodeHash*(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 isEmptyAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.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.
|
||||
|
||||
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
|
||||
|
||||
func initAddr(z: int): EthAddress =
|
||||
result[^1] = z.byte
|
||||
const L = sizeof(result)
|
||||
result[L-sizeof(uint32)..^1] = toBytesBE(z.uint32)
|
||||
|
||||
proc stateDBMain*() =
|
||||
suite "Account State DB":
|
||||
@ -149,5 +150,69 @@ proc stateDBMain*() =
|
||||
let key = contractHashKey(hexary.keccak(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:
|
||||
stateDBMain()
|
||||
|
Loading…
x
Reference in New Issue
Block a user