@@ -14,16 +14,17 @@ import
1414 chronicles,
1515 stint,
1616 results,
17- eth/ common/ [hashes, addresses, accounts, headers],
18- ../../ execution_chain/ db/ ledger,
17+ eth/ common/ [base, hashes, addresses, accounts, headers, transactions ],
18+ ../../ execution_chain/ db/ [ ledger, access_list] ,
1919 ../../ execution_chain/ common/ common,
2020 ../../ execution_chain/ transaction/ call_evm,
2121 ../../ execution_chain/ evm/ [types, state, evm_errors]
2222
2323from web3/ eth_api_types import TransactionArgs
2424
2525export
26- results, chronos, hashes, addresses, accounts, headers, TransactionArgs , CallResult
26+ results, chronos, hashes, addresses, accounts, headers, TransactionArgs , CallResult ,
27+ transactions.AccessList , GasInt
2728
2829logScope:
2930 topics = " async_evm"
@@ -132,9 +133,15 @@ proc init*(
132133
133134 AsyncEvm (com: com, backend: backend)
134135
135- proc call * (
136- evm: AsyncEvm , header: Header , tx: TransactionArgs , optimisticStateFetch = true
137- ): Future [Result [CallResult , string ]] {.async : (raises: [CancelledError ]).} =
136+ proc call (
137+ evm: AsyncEvm ,
138+ header: Header ,
139+ tx: TransactionArgs ,
140+ optimisticStateFetch: bool ,
141+ collectAccessList: bool ,
142+ ): Future [Result [(CallResult , transactions.AccessList ), string ]] {.
143+ async : (raises: [CancelledError ])
144+ .} =
138145 let
139146 to = tx.to.valueOr:
140147 return err (" to address is required" )
@@ -179,7 +186,7 @@ proc call*(
179186 var
180187 lastWitnessKeys: WitnessTable
181188 witnessKeys = vmState.ledger.getWitnessKeys ()
182- callResult : EvmResult [CallResult ]
189+ evmResult : EvmResult [CallResult ]
183190 evmCallCount = 0
184191
185192 # Limit the max number of calls to prevent infinite loops and/or DOS in the
@@ -188,7 +195,7 @@ proc call*(
188195 debug " Starting AsyncEvm execution" , evmCallCount
189196
190197 let sp = vmState.ledger.beginSavepoint ()
191- callResult = rpcCallEvm (tx, header, vmState, EVM_CALL_GAS_CAP )
198+ evmResult = rpcCallEvm (tx, header, vmState, EVM_CALL_GAS_CAP )
192199 inc evmCallCount
193200 vmState.ledger.rollback (sp) # all state changes from the call are reverted
194201
@@ -213,6 +220,8 @@ proc call*(
213220 var stateFetchDone = false
214221 for k, v in witnessKeys:
215222 let (adr, _) = k
223+ if adr == default (Address ):
224+ continue
216225
217226 if v.storageMode:
218227 let slotIdx = (adr, v.storageSlot)
@@ -224,7 +233,7 @@ proc call*(
224233 storageQueries.add (StorageQuery .init (adr, v.storageSlot, storageFut))
225234 if not optimisticStateFetch:
226235 stateFetchDone = true
227- elif adr != default ( Address ) :
236+ else :
228237 doAssert (adr == v.address)
229238
230239 if adr notin fetchedAccounts:
@@ -280,7 +289,57 @@ proc call*(
280289 # TODO : why do the above futures throw a CatchableError and not CancelledError?
281290 raiseAssert (e.msg)
282291
283- callResult.mapErr (
284- proc (e: EvmErrorObj ): string =
285- " EVM execution failed: " & $ e.code
286- )
292+ # If collectAccessList is enabled then build the access list from the
293+ # witness keys and then execute the transaction one last time using the final
294+ # access list which will impact the gas used value returned in the callResult.
295+ var tx = tx
296+ if evmResult.isOk () and collectAccessList:
297+ let fromAdr = tx.`from`.get (default (Address ))
298+
299+ var al = access_list.AccessList .init ()
300+ for lookupKey, witnessKey in witnessKeys:
301+ let (adr, _) = lookupKey
302+ if adr == fromAdr:
303+ continue
304+
305+ if witnessKey.storageMode:
306+ al.add (adr, witnessKey.storageSlot)
307+ else :
308+ al.add (adr)
309+
310+ tx.accessList = Opt .some (al.getAccessList ()) # converts to transactions.AccessList
311+
312+ let sp = vmState.ledger.beginSavepoint ()
313+ evmResult = rpcCallEvm (tx, header, vmState, EVM_CALL_GAS_CAP )
314+ inc evmCallCount
315+ vmState.ledger.rollback (sp) # all state changes from the call are reverted
316+
317+ let callResult =
318+ ? evmResult.mapErr (
319+ proc (e: EvmErrorObj ): string =
320+ " EVM execution failed: " & $ e.code
321+ )
322+
323+ if callResult.error.len () > 0 :
324+ err (" EVM execution failed: " & callResult.error)
325+ else :
326+ ok ((callResult, tx.accessList.get (@ [])))
327+
328+ proc call * (
329+ evm: AsyncEvm , header: Header , tx: TransactionArgs , optimisticStateFetch = true
330+ ): Future [Result [CallResult , string ]] {.async : (raises: [CancelledError ]).} =
331+ let (callResult, _) =
332+ ? (await evm.call (header, tx, optimisticStateFetch, collectAccessList = false ))
333+ ok (callResult)
334+
335+ proc createAccessList * (
336+ evm: AsyncEvm , header: Header , tx: TransactionArgs , optimisticStateFetch = true
337+ ): Future [Result [(transactions.AccessList , GasInt ), string ]] {.
338+ async : (raises: [CancelledError ])
339+ .} =
340+ let (callResult, accessList) =
341+ ? (await evm.call (header, tx, optimisticStateFetch, collectAccessList = true ))
342+
343+ # TODO : Do we need to use the estimate gas calculation here to get a more acturate
344+ # estimation of the gas requirement?
345+ ok ((accessList, callResult.gasUsed))
0 commit comments