access list implementation

This commit is contained in:
jangko 2020-12-09 12:24:37 +07:00
parent 08c8b12821
commit f2b483d6ad
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 138 additions and 3 deletions

41
nimbus/db/access_list.nim Normal file
View 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])

View File

@ -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.}

View File

@ -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()