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,
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+
4253type
4354 AccountFlag = enum
4455 Alive
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
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] =
138151template 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
145160proc 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
360382proc 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 =
451472proc 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
509539proc 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
515553proc 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]) =
595641proc 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-
826840proc 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# ------------------------------------------------------------------------------
0 commit comments