From 74f53c77615e837ba2984c358ce0943b21650db9 Mon Sep 17 00:00:00 2001 From: Jamie Lokier Date: Thu, 5 Aug 2021 02:52:40 +0100 Subject: [PATCH] EVMC: Add missing EIP-2929 (Berlin) functions to EVMC host The update for London (EIP-1559) in 1cdb30df ("bump nim-emvc with evmc revision 8.0.0 to 9.0.0") really bumped EVMC ABI version from 7.5 up to 9. In other words, it skipped Berlin, going direct from Istanbul to London. That was accompanied by EVMC changes in 05e9b891 ("EIP-3198: add baseFee op code in nim-evm"), which added the API changes needed for London. But the missing Berlin functions weren't added in the move to London. As a result, our EVMC host became incompatible with Berlin, London, and really all revisions of the ABI, and if a third party EVM was loaded, it crashed. This commit adds the missing Berlin host support, and makes our ABI binary-compatible with real EVMC again. Signed-off-by: Jamie Lokier --- nimbus/transaction/evmc_host_glue.nim | 10 ++++++++++ nimbus/transaction/host_services.nim | 17 +++++++++++++++++ nimbus/transaction/host_types.nim | 3 ++- nimbus/vm/evmc_api.nim | 13 +++++++++++++ nimbus/vm/evmc_host.nim | 20 ++++++++++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/nimbus/transaction/evmc_host_glue.nim b/nimbus/transaction/evmc_host_glue.nim index 96cc065e0..b1f936123 100644 --- a/nimbus/transaction/evmc_host_glue.nim +++ b/nimbus/transaction/evmc_host_glue.nim @@ -64,6 +64,14 @@ proc emitLog(p: evmc_host_context, address: var evmc_address, toHost(p).emitLog(address.fromEvmc, data, data_size, cast[ptr HostTopic](topics), topics_count) +proc accessAccount(p: evmc_host_context, + address: var evmc_address): evmc_access_status {.cdecl.} = + toHost(p).accessAccount(address.fromEvmc) + +proc accessStorage(p: evmc_host_context, address: var evmc_address, + key: var evmc_bytes32): evmc_access_status {.cdecl.} = + toHost(p).accessStorage(address.fromEvmc, key.fromEvmc) + proc evmcGetHostInterface(): ref evmc_host_interface = var theHostInterface {.global, threadvar.}: ref evmc_host_interface if theHostInterface.isNil: @@ -80,6 +88,8 @@ proc evmcGetHostInterface(): ref evmc_host_interface = get_tx_context: getTxContext, get_block_hash: getBlockHash, emit_log: emitLog, + access_account: accessAccount, + access_storage: accessStorage, ) return theHostInterface diff --git a/nimbus/transaction/host_services.nim b/nimbus/transaction/host_services.nim index f0dd40358..9245fc6b5 100644 --- a/nimbus/transaction/host_services.nim +++ b/nimbus/transaction/host_services.nim @@ -272,6 +272,23 @@ proc emitLog(host: TransactionHost, address: HostAddress, host.computation.logEntries.add(log) #host.logEntries.add(log) +proc accessAccount(host: TransactionHost, address: HostAddress): EvmcAccessStatus {.show.} = + host.vmState.mutateStateDB: + if not db.inAccessList(address): + db.accessList(address) + return EVMC_ACCESS_COLD + else: + return EVMC_ACCESS_WARM + +proc accessStorage(host: TransactionHost, address: HostAddress, + key: HostKey): EvmcAccessStatus {.show.} = + host.vmState.mutateStateDB: + if not db.inAccessList(address, key): + db.accessList(address, key) + return EVMC_ACCESS_COLD + else: + return EVMC_ACCESS_WARM + when use_evmc_glue: {.pop: inline.} const included_from_host_services = true diff --git a/nimbus/transaction/host_types.nim b/nimbus/transaction/host_types.nim index 73eca3dd9..5b81f3c91 100644 --- a/nimbus/transaction/host_types.nim +++ b/nimbus/transaction/host_types.nim @@ -46,6 +46,7 @@ type EvmcStatusCode* = evmc_status_code EvmcCallKind* = evmc_call_kind EvmcStorageStatus* = evmc_storage_status + EvmcAccessStatus* = evmc_access_status EvmcTxContext* = evmc_tx_context EvmcMessage* = evmc_message EvmcResult* = evmc_result @@ -95,4 +96,4 @@ template isStatic*(msg: EvmcMessage): bool = # `evmc_flags` won't export the flags, `evmc_flag_bit_shifts` must be used. export evmc_status_code, evmc_call_kind, - evmc_flag_bit_shifts, evmc_storage_status + evmc_flag_bit_shifts, evmc_storage_status, evmc_access_status diff --git a/nimbus/vm/evmc_api.nim b/nimbus/vm/evmc_api.nim index 789af5f84..fb73d3647 100644 --- a/nimbus/vm/evmc_api.nim +++ b/nimbus/vm/evmc_api.nim @@ -66,6 +66,10 @@ type emit_log*: proc(context: evmc_host_context, address: EthAddress, data: ptr byte, data_size: uint, topics: ptr evmc_bytes32, topics_count: uint) {.cdecl, gcsafe.} + access_account*: proc(context: evmc_host_context, + address: EthAddress): evmc_access_status {.cdecl, gcsafe.} + access_storage*: proc(context: evmc_host_context, address: EthAddress, + key: var evmc_bytes32): evmc_access_status {.cdecl, gcsafe.} proc nim_host_get_interface*(): ptr nimbus_host_interface {.importc, cdecl.} proc nim_host_create_context*(vmstate: pointer, msg: ptr evmc_message): evmc_host_context {.importc, cdecl.} @@ -139,6 +143,15 @@ proc emitLog*(ctx: HostContext, address: EthAddress, data: openArray[byte], proc call*(ctx: HostContext, msg: nimbus_message): nimbus_result {.inline.} = ctx.host.call(ctx.context, msg.unsafeAddr) +proc accessAccount*(ctx: HostContext, + address: EthAddress): evmc_access_status {.inline.} = + ctx.host.access_account(ctx.context, address) + +proc accessStorage*(ctx: HostContext, address: EthAddress, + key: Uint256): evmc_access_status {.inline.} = + var key = toEvmc(key) + ctx.host.access_storage(ctx.context, address, key) + #proc vmHost*(vmState: BaseVMState, gasPrice: GasInt, origin: EthAddress): HostContext = # let host = nim_host_get_interface() # let context = nim_host_create_context(cast[pointer](vmState), gasPrice, toEvmc(origin)) diff --git a/nimbus/vm/evmc_host.nim b/nimbus/vm/evmc_host.nim index 692a915f8..12abf1285 100644 --- a/nimbus/vm/evmc_host.nim +++ b/nimbus/vm/evmc_host.nim @@ -124,6 +124,24 @@ proc hostEmitLogImpl(ctx: Computation, address: EthAddress, log.address = address ctx.addLogEntry(log) +proc hostAccessAccountImpl(ctx: Computation, address: EthAddress): evmc_access_status {.cdecl.} = + ctx.vmState.mutateStateDB: + if not db.inAccessList(address): + db.accessList(address) + return EVMC_ACCESS_COLD + else: + return EVMC_ACCESS_WARM + +proc hostAccessStorageImpl(ctx: Computation, address: EthAddress, + key: var evmc_bytes32): evmc_access_status {.cdecl.} = + let slot = Uint256.fromEvmc(key) + ctx.vmState.mutateStateDB: + if not db.inAccessList(address, slot): + db.accessList(address, slot) + return EVMC_ACCESS_COLD + else: + return EVMC_ACCESS_WARM + proc enterCreateImpl(c: Computation, m: nimbus_message): Computation = # TODO: use evmc_message to evoid copy let childMsg = Message( @@ -215,6 +233,8 @@ proc initHostInterface(): evmc_host_interface = result.get_tx_context = cast[evmc_get_tx_context_fn](hostGetTxContextImpl) result.get_block_hash = cast[evmc_get_block_hash_fn](hostGetBlockHashImpl) result.emit_log = cast[evmc_emit_log_fn](hostEmitLogImpl) + result.access_account = cast[evmc_access_account_fn](hostAccessAccountImpl) + result.access_storage = cast[evmc_access_storage_fn](hostAccessStorageImpl) proc vmSetOptionImpl(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_result {.cdecl.} = return EVMC_SET_OPTION_INVALID_NAME