mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 04:46:00 +00:00
74f53c7761
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 <jamie@shareable.org>
162 lines
7.4 KiB
Nim
162 lines
7.4 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2019 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
import evmc/evmc, ./evmc_helpers, eth/common, ../constants
|
|
|
|
type
|
|
# we are not using EVMC original signature here
|
|
# because we want to trick the compiler
|
|
# and reduce unnecessary conversion/typecast
|
|
# TODO: move this type definition to nim-evmc
|
|
# after we have implemented ABI compatibility test
|
|
# TODO: investigate the possibility to use Big Endian VMWord
|
|
# directly if it's not involving stint computation
|
|
# and we can reduce unecessary conversion further
|
|
nimbus_tx_context* = object
|
|
tx_gas_price* : evmc_uint256be # The transaction gas price.
|
|
tx_origin* : EthAddress # The transaction origin account.
|
|
block_coinbase* : EthAddress # The miner of the block.
|
|
block_number* : int64 # The block number.
|
|
block_timestamp* : int64 # The block timestamp.
|
|
block_gas_limit* : int64 # The block gas limit.
|
|
block_difficulty*: evmc_uint256be # The block difficulty.
|
|
chain_id* : evmc_uint256be # The blockchain's ChainID.
|
|
block_base_fee* : evmc_uint256be # The block base fee.
|
|
|
|
nimbus_message* = object
|
|
kind*: evmc_call_kind
|
|
flags*: uint32
|
|
depth*: int32
|
|
gas*: int64
|
|
destination*: EthAddress
|
|
sender*: EthAddress
|
|
input_data*: ptr byte
|
|
input_size*: uint
|
|
value*: evmc_uint256be
|
|
create2_salt*: evmc_bytes32
|
|
|
|
nimbus_result* = object
|
|
status_code*: evmc_status_code
|
|
gas_left*: int64
|
|
output_data*: ptr byte
|
|
output_size*: uint
|
|
release*: proc(result: var nimbus_result) {.cdecl, gcsafe.}
|
|
create_address*: EthAddress
|
|
padding*: array[4, byte]
|
|
|
|
nimbus_host_interface* = object
|
|
account_exists*: proc(context: evmc_host_context, address: EthAddress): bool {.cdecl, gcsafe.}
|
|
get_storage*: proc(context: evmc_host_context, address: EthAddress, key: ptr evmc_uint256be): evmc_uint256be {.cdecl, gcsafe.}
|
|
set_storage*: proc(context: evmc_host_context, address: EthAddress,
|
|
key, value: ptr evmc_uint256be): evmc_storage_status {.cdecl, gcsafe.}
|
|
get_balance*: proc(context: evmc_host_context, address: EthAddress): evmc_uint256be {.cdecl, gcsafe.}
|
|
get_code_size*: proc(context: evmc_host_context, address: EthAddress): uint {.cdecl, gcsafe.}
|
|
get_code_hash*: proc(context: evmc_host_context, address: EthAddress): Hash256 {.cdecl, gcsafe.}
|
|
copy_code*: proc(context: evmc_host_context, address: EthAddress,
|
|
code_offset: int, buffer_data: ptr byte,
|
|
buffer_size: int): int {.cdecl, gcsafe.}
|
|
selfdestruct*: proc(context: evmc_host_context, address, beneficiary: EthAddress) {.cdecl, gcsafe.}
|
|
call*: proc(context: evmc_host_context, msg: ptr nimbus_message): nimbus_result {.cdecl, gcsafe.}
|
|
get_tx_context*: proc(context: evmc_host_context): nimbus_tx_context {.cdecl, gcsafe.}
|
|
get_block_hash*: proc(context: evmc_host_context, number: int64): Hash256 {.cdecl, gcsafe.}
|
|
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.}
|
|
proc nim_host_destroy_context*(ctx: evmc_host_context) {.importc, cdecl.}
|
|
proc nim_create_nimbus_vm*(): ptr evmc_vm {.importc, cdecl.}
|
|
|
|
type
|
|
HostContext* = object
|
|
host*: ptr nimbus_host_interface
|
|
context*: evmc_host_context
|
|
|
|
proc init*(x: var HostContext, host: ptr nimbus_host_interface, context: evmc_host_context) =
|
|
x.host = host
|
|
x.context = context
|
|
|
|
proc init*(x: typedesc[HostContext], host: ptr nimbus_host_interface, context: evmc_host_context): HostContext =
|
|
result.init(host, context)
|
|
|
|
proc getTxContext*(ctx: HostContext): nimbus_tx_context {.inline.} =
|
|
ctx.host.get_tx_context(ctx.context)
|
|
|
|
proc getBlockHash*(ctx: HostContext, number: Uint256): Hash256 =
|
|
let
|
|
blockNumber = ctx.getTxContext().block_number.u256
|
|
ancestorDepth = blockNumber - number - 1
|
|
if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH:
|
|
return
|
|
if number >= blockNumber:
|
|
return
|
|
ctx.host.get_block_hash(ctx.context, number.truncate(int64))
|
|
|
|
proc accountExists*(ctx: HostContext, address: EthAddress): bool {.inline.} =
|
|
ctx.host.account_exists(ctx.context, address)
|
|
|
|
proc getStorage*(ctx: HostContext, address: EthAddress, key: Uint256): Uint256 =
|
|
var key = toEvmc(key)
|
|
Uint256.fromEvmc ctx.host.get_storage(ctx.context, address, key.addr)
|
|
|
|
proc setStorage*(ctx: HostContext, address: EthAddress,
|
|
key, value: Uint256): evmc_storage_status {.inline.} =
|
|
var
|
|
key = toEvmc(key)
|
|
value = toEvmc(value)
|
|
ctx.host.set_storage(ctx.context, address, key.addr, value.addr)
|
|
|
|
proc getBalance*(ctx: HostContext, address: EthAddress): Uint256 {.inline.} =
|
|
Uint256.fromEvmc ctx.host.get_balance(ctx.context, address)
|
|
|
|
proc getCodeSize*(ctx: HostContext, address: EthAddress): uint {.inline.} =
|
|
ctx.host.get_code_size(ctx.context, address)
|
|
|
|
proc getCodeHash*(ctx: HostContext, address: EthAddress): Hash256 {.inline.} =
|
|
ctx.host.get_code_hash(ctx.context, address)
|
|
|
|
proc copyCode*(ctx: HostContext, address: EthAddress, codeOffset: int = 0): seq[byte] =
|
|
let size = ctx.getCodeSize(address).int
|
|
if size - codeOffset > 0:
|
|
result = newSeq[byte](size - codeOffset)
|
|
let read = ctx.host.copy_code(ctx.context, address,
|
|
codeOffset, result[0].addr, result.len)
|
|
doAssert(read == result.len)
|
|
|
|
proc selfdestruct*(ctx: HostContext, address, beneficiary: EthAddress) {.inline.} =
|
|
ctx.host.selfdestruct(ctx.context, address, beneficiary)
|
|
|
|
proc emitLog*(ctx: HostContext, address: EthAddress, data: openArray[byte],
|
|
topics: ptr evmc_bytes32, topicsCount: int) {.inline.} =
|
|
ctx.host.emit_log(ctx.context, address, if data.len > 0: data[0].unsafeAddr else: nil,
|
|
data.len.uint, topics, topicsCount.uint)
|
|
|
|
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))
|
|
# result.init(host, context)
|
|
#
|
|
#proc destroy*(hc: HostContext) =
|
|
# nim_host_destroy_context(hc.context)
|