Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
# Nimbus - Types and helpers used at the boundary of transactions/RPC and EVMC/EVM
|
|
|
|
#
|
|
|
|
# Copyright (c) 2019-2021 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
|
|
|
|
sets, stint, evmc/evmc, eth/common/eth_types, ../vm_types
|
|
|
|
|
|
|
|
# Object `TransactionHost` represents "EVMC host" to the EVM. "Host services"
|
|
|
|
# manage account state outside EVM such as balance transfers, storage, logs and
|
|
|
|
# gas refunds. This object holds transaction state hidden from the EVM, and
|
|
|
|
# the EVM passes this around as opaque `evmc_host_context`. To the application
|
|
|
|
# outside the EVM, this object represents a computation for a transaction.
|
|
|
|
#
|
|
|
|
# `Host..` types are like EVMC types, but used in `TransactionHost` code. They
|
|
|
|
# occupy the same positions in EVMC functions and objects as the type they map
|
|
|
|
# to/from. But `Host..` types match internal APIs in the rest of Nimbus, to
|
|
|
|
# minimise the amount of explicit conversions when using them. We could just
|
|
|
|
# use the Nimbus types, but these names document their use and also role.
|
|
|
|
#
|
|
|
|
# `Evmc..` types named here are actual EVMC types. They play a similar role to
|
|
|
|
# `Host..` types, except the `Evmc` prefix indicates they are the actual EVMC
|
|
|
|
# types and more care applies. Byte order (big/little-endian) may need to be
|
|
|
|
# swapped in object fields of these types, and enums respected.
|
|
|
|
#
|
|
|
|
# When crossing the EVMC API boundary, between internal APIs and EVMC binary
|
|
|
|
# interface there have to be type-conversions and some big/little-endian byte
|
|
|
|
# swapping. Those conversions are mostly kept out of `TransactionHost` logic
|
|
|
|
# and delegated to glue code.
|
|
|
|
|
|
|
|
type
|
|
|
|
HostAddress* = EthAddress # Mapped to/from evmc_address.
|
|
|
|
HostKey* = UInt256 # Mapped to/from evmc_bytes32.
|
|
|
|
HostValue* = UInt256 # Mapped to/from evmc_bytes32.
|
|
|
|
HostBalance* = UInt256 # Mapped to/from evmc_uint256be.
|
|
|
|
HostSize* = uint # Mapped to/from csize_t - unsigned!
|
|
|
|
HostHash* = Hash256 # Mapped to/from evmc_bytes32.
|
|
|
|
HostTopic* = Topic # Mapped to/from evmc_bytes32.
|
|
|
|
HostBlockNumber* = BlockNumber # Mapped to/from int64.
|
|
|
|
HostGasInt* = GasInt # Mapped to/from int64.
|
|
|
|
HostGasPrice* = GasInt # Mapped to/from evmc_uint256be.
|
|
|
|
|
|
|
|
EvmcStatusCode* = evmc_status_code
|
|
|
|
EvmcCallKind* = evmc_call_kind
|
|
|
|
EvmcStorageStatus* = evmc_storage_status
|
2021-08-05 01:52:40 +00:00
|
|
|
EvmcAccessStatus* = evmc_access_status
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
EvmcTxContext* = evmc_tx_context
|
|
|
|
EvmcMessage* = evmc_message
|
|
|
|
EvmcResult* = evmc_result
|
|
|
|
|
|
|
|
TransactionHost* = ref object
|
|
|
|
vmState*: BaseVMState
|
|
|
|
computation*: Computation
|
|
|
|
msg*: EvmcMessage
|
|
|
|
input*: seq[byte]
|
2021-05-18 22:53:14 +00:00
|
|
|
code*: seq[byte]
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
cachedTxContext*: bool
|
|
|
|
txContext*: EvmcTxContext
|
EVMC: Improve host call tracing and fix nested call C stack usage
This combines two things, a C stack usage change with EVM nested calls
via EVMC, and changes to host call tracing.
Feature-wise, the tracing is improved:
- Storage keys and values are make more sense.
- The message/result/context objects are shown with all relevant fields.
- `call` trace is split into entry/exit, so these can be shown around the
called contract's operations, instead of only showing the `call` parameters
after the nested call is finished.
- Nested calls are indented, which helps to highlight the flow.
- C stack usage considerably reduced in nested calls when more functionality
is enabled (either tracing here, or other things to come).
This will seem like a minor patch, but C stack usage was the real motivation,
after plenty of time in the debugger.
Nobody cares about stack when `showTxCalls` (you can just use a big stack when
debugging). But these subtle changes around the `call` path were found to be
necessary for passing all tests when the EVMC nested call code is completed,
and that's a prerequisite for many things: async EVM, dynamic EVM, Beam Sync,
and to fix https://github.com/status-im/nimbus-eth1/issues/345.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-08-09 14:54:38 +00:00
|
|
|
depth*: int
|
2021-08-17 16:18:07 +00:00
|
|
|
saveComputation*: seq[Computation]
|
|
|
|
hostInterface*: ptr evmc_host_interface
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
|
|
|
|
# These versions of `toEvmc` and `fromEvmc` don't flip big/little-endian like
|
|
|
|
# the older functions in `evmc_helpers`. New code only flips with _explicit_
|
|
|
|
# calls to `flip256` where it is wanted.
|
|
|
|
|
2022-04-08 04:54:11 +00:00
|
|
|
template toEvmc*(n: UInt256): evmc_uint256be =
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
cast[evmc_uint256be](n)
|
|
|
|
|
|
|
|
template toEvmc*(n: Hash256): evmc_bytes32 =
|
|
|
|
cast[evmc_bytes32](n)
|
|
|
|
|
|
|
|
template toEvmc*(address: EthAddress): evmc_address =
|
|
|
|
cast[evmc_address](address)
|
|
|
|
|
|
|
|
template fromEvmc*(n: evmc_uint256be): UInt256 =
|
|
|
|
cast[UInt256](n)
|
|
|
|
|
|
|
|
template fromEvmc*(address: evmc_address): EthAddress =
|
|
|
|
cast[EthAddress](address)
|
|
|
|
|
|
|
|
template flip256*(word256: evmc_uint256be): evmc_uint256be =
|
2023-09-13 02:32:38 +00:00
|
|
|
cast[evmc_uint256be](UInt256.fromBytesBE(word256.bytes).toBytes(cpuEndian))
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
|
|
|
|
template isCreate*(kind: EvmcCallKind): bool =
|
|
|
|
kind in {EVMC_CREATE, EVMC_CREATE2}
|
|
|
|
|
2022-02-01 08:35:30 +00:00
|
|
|
template isZero*(n: evmc_bytes32): bool =
|
|
|
|
n == default(evmc_bytes32)
|
|
|
|
|
Transaction: New object `TransactionHost` for "EVMC host services"
`TransactionHost` represents the interface to the EVM from the application once
we've fully transitioned to EVMC. It represents a managed EVM call, and the
"EVMC host" side of the host<->EVM boundary.
This holds transaction state which sits outside the EVM, but a pointer to this
is passed around by the EVM as _opaque_ type `evmc_host_context`.
To the EVM, this offers "host services", which manage account state that the
EVM cannot do, such as balance transfers, call costs, storage, logs, gas
refunds, nested calls and new contract addresses. The EVM has no direct access
to the account state database or network; it's all via "host services".
To the application (host side), this object represents a managed EVM call, with
inputs, a method to run, outputs, hidden transaction state, and later async
scheduling. It is to replace `Computation` on the application side, while
`Computation` will remain but just be for the EVM side.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-05-17 09:23:59 +00:00
|
|
|
# Nim quirks: Exporting `evmc_status_code` (etc) are needed to access the enum
|
|
|
|
# values, even though alias `EnumStatusCode` is already exported. Exporting
|
|
|
|
# `evmc_flags` won't export the flags, `evmc_flag_bit_shifts` must be used.
|
|
|
|
export
|
|
|
|
evmc_status_code, evmc_call_kind,
|
2021-08-05 01:52:40 +00:00
|
|
|
evmc_flag_bit_shifts, evmc_storage_status, evmc_access_status
|