Skip to content

Commit cb72975

Browse files
authored
Improve collection of witness keys in ledger (#3150)
* Remove existing witness code. * Implement collection of witness keys using ordered list.
1 parent 1c9fab7 commit cb72975

File tree

6 files changed

+175
-96
lines changed

6 files changed

+175
-96
lines changed

execution_chain/core/executor/process_block.nim

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ proc procBlkEpilogue(
191191

192192
# Reward beneficiary
193193
vmState.mutateLedger:
194-
if vmState.collectWitnessData:
195-
db.collectWitnessData()
196194

197195
# Clearing the account cache here helps manage its size when replaying
198196
# large ranges of blocks, implicitly limiting its size using the gas limit

execution_chain/core/executor/process_transaction.nim

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ proc processTransactionImpl(
120120
else:
121121
err(txRes.error)
122122

123-
if vmState.collectWitnessData:
124-
vmState.ledger.collectWitnessData()
125-
126123
vmState.ledger.persist(clearEmptyAccount = fork >= FkSpurious)
127124

128125
res

execution_chain/db/ledger.nim

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import
1818
minilru,
1919
../utils/mergeutils,
2020
../evm/code_bytes,
21-
../stateless/multi_keys,
2221
../core/eip7702,
2322
"/.."/[constants, utils/utils],
2423
./access_list as ac_access_list,
@@ -39,6 +38,18 @@ const
3938
# in greater detail.
4039
slotsLruSize = 16 * 1024
4140

41+
statelessEnabled = defined(stateless)
42+
43+
when statelessEnabled:
44+
type
45+
WitnessKey* = object
46+
storageMode*: bool
47+
address*: Address
48+
codeTouched*: bool
49+
storageSlot*: UInt256
50+
51+
WitnessTable* = OrderedTable[(Address, Hash32), WitnessKey]
52+
4253
type
4354
AccountFlag = enum
4455
Alive
@@ -59,14 +70,9 @@ type
5970
originalStorage: TableRef[UInt256, UInt256]
6071
overlayStorage: Table[UInt256, UInt256]
6172

62-
WitnessData* = object
63-
storageKeys*: HashSet[UInt256]
64-
codeTouched*: bool
65-
6673
LedgerRef* = ref object
6774
txFrame*: CoreDbTxRef
6875
savePoint: LedgerSpRef
69-
witnessCache: Table[Address, WitnessData]
7076
isDirty: bool
7177
ripemdSpecial: bool
7278
storeSlotHash*: bool
@@ -89,6 +95,13 @@ type
8995
## over and over again to the database to avoid the WAL and compation
9096
## write amplification that ensues
9197

98+
when statelessEnabled:
99+
witnessKeys: WitnessTable
100+
## Used to collect the keys of all read accounts, code and storage slots.
101+
## Maps a tuple of address and hash of the key (address or slot) to the
102+
## witness key which can be either a storage key or an account key
103+
104+
92105
ReadOnlyLedger* = distinct LedgerRef
93106

94107
TransactionState = enum
@@ -138,9 +151,11 @@ template logTxt(info: static[string]): static[string] =
138151
template toAccountKey(acc: AccountRef): Hash32 =
139152
acc.accPath
140153

141-
template toAccountKey(eAddr: Address): Hash32 =
154+
template toAccountKey*(eAddr: Address): Hash32 =
142155
eAddr.data.keccak256
143156

157+
template toSlotKey*(slot: UInt256): Hash32 =
158+
slot.toBytesBE.keccak256
144159

145160
proc beginSavepoint*(ac: LedgerRef): LedgerSpRef {.gcsafe.}
146161

@@ -157,6 +172,13 @@ proc getAccount(
157172
address: Address;
158173
shouldCreate = true;
159174
): AccountRef =
175+
when statelessEnabled:
176+
let lookupKey = (address, address.toAccountKey)
177+
if not ac.witnessKeys.contains(lookupKey):
178+
ac.witnessKeys[lookupKey] = WitnessKey(
179+
storageMode: false,
180+
address: address,
181+
codeTouched: false)
160182

161183
# search account from layers of cache
162184
var sp = ac.savePoint
@@ -360,7 +382,6 @@ proc makeDirty(ac: LedgerRef, address: Address, cloneStorage = true): AccountRef
360382
proc init*(x: typedesc[LedgerRef], db: CoreDbTxRef, storeSlotHash: bool): LedgerRef =
361383
new result
362384
result.txFrame = db
363-
result.witnessCache = Table[Address, WitnessData]()
364385
result.storeSlotHash = storeSlotHash
365386
result.code = typeof(result.code).init(codeLruSize)
366387
result.slots = typeof(result.slots).init(slotsLruSize)
@@ -451,6 +472,15 @@ proc getNonce*(ac: LedgerRef, address: Address): AccountNonce =
451472
proc getCode*(ac: LedgerRef,
452473
address: Address,
453474
returnHash: static[bool] = false): auto =
475+
when statelessEnabled:
476+
let lookupKey = (address, address.toAccountKey)
477+
# We overwrite any existing record here so that codeTouched is always set to
478+
# true even if an account was previously accessed without touching the code
479+
ac.witnessKeys[lookupKey] = WitnessKey(
480+
storageMode: false,
481+
address: address,
482+
codeTouched: true)
483+
454484
let acc = ac.getAccount(address, false)
455485
if acc.isNil:
456486
when returnHash:
@@ -508,12 +538,28 @@ proc resolveCode*(ac: LedgerRef, address: Address): CodeBytesRef =
508538

509539
proc getCommittedStorage*(ac: LedgerRef, address: Address, slot: UInt256): UInt256 =
510540
let acc = ac.getAccount(address, false)
541+
542+
when statelessEnabled:
543+
let lookupKey = (address, slot.toSlotKey)
544+
if not ac.witnessKeys.contains(lookupKey):
545+
ac.witnessKeys[lookupKey] = WitnessKey(
546+
storageMode: true,
547+
storageSlot: slot)
548+
511549
if acc.isNil:
512550
return
513551
acc.originalStorageValue(slot, ac)
514552

515553
proc getStorage*(ac: LedgerRef, address: Address, slot: UInt256): UInt256 =
516554
let acc = ac.getAccount(address, false)
555+
556+
when statelessEnabled:
557+
let lookupKey = (address, slot.toSlotKey)
558+
if not ac.witnessKeys.contains(lookupKey):
559+
ac.witnessKeys[lookupKey] = WitnessKey(
560+
storageMode: true,
561+
storageSlot: slot)
562+
517563
if acc.isNil:
518564
return
519565
acc.storageValue(slot, ac)
@@ -595,6 +641,14 @@ proc setCode*(ac: LedgerRef, address: Address, code: seq[byte]) =
595641
proc setStorage*(ac: LedgerRef, address: Address, slot, value: UInt256) =
596642
let acc = ac.getAccount(address)
597643
acc.flags.incl {Alive}
644+
645+
when statelessEnabled:
646+
let lookupKey = (address, slot.toSlotKey)
647+
if not ac.witnessKeys.contains(lookupKey):
648+
ac.witnessKeys[lookupKey] = WitnessKey(
649+
storageMode: true,
650+
storageSlot: slot)
651+
598652
let oldValue = acc.storageValue(slot, ac)
599653
if oldValue != value:
600654
var acc = ac.makeDirty(address)
@@ -783,46 +837,6 @@ proc getStorageRoot*(ac: LedgerRef, address: Address): Hash32 =
783837
if acc.isNil: EMPTY_ROOT_HASH
784838
else: ac.txFrame.slotStorageRoot(acc.toAccountKey).valueOr: EMPTY_ROOT_HASH
785839

786-
proc update(wd: var WitnessData, acc: AccountRef) =
787-
# once the code is touched make sure it doesn't get reset back to false in another update
788-
if not wd.codeTouched:
789-
wd.codeTouched = CodeChanged in acc.flags or acc.code != nil
790-
791-
if not acc.originalStorage.isNil:
792-
for k in acc.originalStorage.keys():
793-
wd.storageKeys.incl k
794-
795-
for k, v in acc.overlayStorage:
796-
wd.storageKeys.incl k
797-
798-
proc witnessData(acc: AccountRef): WitnessData =
799-
result.storageKeys = HashSet[UInt256]()
800-
update(result, acc)
801-
802-
proc collectWitnessData*(ac: LedgerRef) =
803-
# make sure all savepoint already committed
804-
doAssert(ac.savePoint.parentSavepoint.isNil)
805-
# usually witness data is collected before we call persist()
806-
for address, acc in ac.savePoint.cache:
807-
ac.witnessCache.withValue(address, val) do:
808-
update(val[], acc)
809-
do:
810-
ac.witnessCache[address] = witnessData(acc)
811-
812-
func multiKeys(slots: HashSet[UInt256]): MultiKeysRef =
813-
if slots.len == 0: return
814-
new result
815-
for x in slots:
816-
result.add x.toBytesBE
817-
result.sort()
818-
819-
proc makeMultiKeys*(ac: LedgerRef): MultiKeysRef =
820-
# this proc is called after we done executing a block
821-
new result
822-
for k, v in ac.witnessCache:
823-
result.add(k, v.codeTouched, multiKeys(v.storageKeys))
824-
result.sort()
825-
826840
proc accessList*(ac: LedgerRef, address: Address) =
827841
ac.savePoint.accessList.add(address)
828842

@@ -911,6 +925,13 @@ proc getStorageProof*(ac: LedgerRef, address: Address, slots: openArray[UInt256]
911925

912926
storageProof
913927

928+
when statelessEnabled:
929+
func getWitnessKeys*(ac: LedgerRef): WitnessTable =
930+
ac.witnessKeys
931+
932+
proc clearWitnessKeys*(ac: LedgerRef) =
933+
ac.witnessKeys.clear()
934+
914935
# ------------------------------------------------------------------------------
915936
# Public virtual read-only methods
916937
# ------------------------------------------------------------------------------

execution_chain/evm/state.nim

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,6 @@ proc `status=`*(vmState: BaseVMState, status: bool) =
237237
if status: vmState.flags.incl ExecutionOK
238238
else: vmState.flags.excl ExecutionOK
239239

240-
proc collectWitnessData*(vmState: BaseVMState): bool =
241-
CollectWitnessData in vmState.flags
242-
243-
proc `collectWitnessData=`*(vmState: BaseVMState, status: bool) =
244-
if status: vmState.flags.incl CollectWitnessData
245-
else: vmState.flags.excl CollectWitnessData
246-
247240
func tracingEnabled*(vmState: BaseVMState): bool =
248241
vmState.tracer.isNil.not
249242

execution_chain/evm/types.nim

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export stack, memory
2121
type
2222
VMFlag* = enum
2323
ExecutionOK
24-
CollectWitnessData
2524

2625
BlockContext* = object
2726
timestamp* : EthTime

0 commit comments

Comments
 (0)