mirror of https://github.com/status-im/evmc.git
Merge pull request #427 from ethereum/host_interface
Move evmc_host_interface out of evmc_host_context
This commit is contained in:
commit
a15e493a26
|
@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning].
|
|||
[[#430](https://github.com/ethereum/evmc/pull/430)]
|
||||
- The `evmc_context` renamed to `evmc_host_context`.
|
||||
[[#426](https://github.com/ethereum/evmc/pull/426)]
|
||||
- The `evmc_host_interface` is now separated from `evmc_host_context`.
|
||||
This simplifies language bindings which implement the `evmc_host_interface`.
|
||||
[[#427](https://github.com/ethereum/evmc/pull/427)]
|
||||
- The `evmc::vm` renamed to `evmc::VM` in C++ API.
|
||||
[[#252](https://github.com/ethereum/evmc/pull/252)]
|
||||
- Previously deprecated `helpers.hpp` header file has been removed.
|
||||
|
|
|
@ -23,16 +23,10 @@ static inline enum evmc_set_option_result set_option(struct evmc_vm* vm, char* n
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct extended_context
|
||||
{
|
||||
struct evmc_host_context context;
|
||||
int64_t index;
|
||||
};
|
||||
|
||||
extern const struct evmc_host_interface evmc_go_host;
|
||||
|
||||
static struct evmc_result execute_wrapper(struct evmc_vm* vm,
|
||||
int64_t context_index, enum evmc_revision rev,
|
||||
uintptr_t context_index, enum evmc_revision rev,
|
||||
enum evmc_call_kind kind, uint32_t flags, int32_t depth, int64_t gas,
|
||||
const evmc_address* destination, const evmc_address* sender,
|
||||
const uint8_t* input_data, size_t input_size, const evmc_uint256be* value,
|
||||
|
@ -51,8 +45,8 @@ static struct evmc_result execute_wrapper(struct evmc_vm* vm,
|
|||
*create2_salt,
|
||||
};
|
||||
|
||||
struct extended_context ctx = {{&evmc_go_host}, context_index};
|
||||
return evmc_execute(vm, &ctx.context, rev, &msg, code, code_size);
|
||||
struct evmc_host_context* context = (struct evmc_host_context*)context_index;
|
||||
return evmc_execute(vm, &evmc_go_host, context, rev, &msg, code, code_size);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
@ -242,7 +236,7 @@ func (vm *VM) Execute(ctx HostContext, rev Revision,
|
|||
evmcSender := evmcAddress(sender)
|
||||
evmcValue := evmcBytes32(value)
|
||||
evmcCreate2Salt := evmcBytes32(create2Salt)
|
||||
result := C.execute_wrapper(vm.handle, C.int64_t(ctxId), uint32(rev),
|
||||
result := C.execute_wrapper(vm.handle, C.uintptr_t(ctxId), uint32(rev),
|
||||
C.enum_evmc_call_kind(kind), flags, C.int32_t(depth), C.int64_t(gas),
|
||||
&evmcDestination, &evmcSender, bytesPtr(input), C.size_t(len(input)), &evmcValue,
|
||||
bytesPtr(code), C.size_t(len(code)), &evmcCreate2Salt)
|
||||
|
@ -262,12 +256,12 @@ func (vm *VM) Execute(ctx HostContext, rev Revision,
|
|||
}
|
||||
|
||||
var (
|
||||
hostContextCounter int
|
||||
hostContextMap = map[int]HostContext{}
|
||||
hostContextCounter uintptr
|
||||
hostContextMap = map[uintptr]HostContext{}
|
||||
hostContextMapMu sync.Mutex
|
||||
)
|
||||
|
||||
func addHostContext(ctx HostContext) int {
|
||||
func addHostContext(ctx HostContext) uintptr {
|
||||
hostContextMapMu.Lock()
|
||||
id := hostContextCounter
|
||||
hostContextCounter++
|
||||
|
@ -276,13 +270,13 @@ func addHostContext(ctx HostContext) int {
|
|||
return id
|
||||
}
|
||||
|
||||
func removeHostContext(id int) {
|
||||
func removeHostContext(id uintptr) {
|
||||
hostContextMapMu.Lock()
|
||||
delete(hostContextMap, id)
|
||||
hostContextMapMu.Unlock()
|
||||
}
|
||||
|
||||
func getHostContext(idx int) HostContext {
|
||||
func getHostContext(idx uintptr) HostContext {
|
||||
hostContextMapMu.Lock()
|
||||
ctx := hostContextMap[idx]
|
||||
hostContextMapMu.Unlock()
|
||||
|
|
|
@ -10,12 +10,6 @@ package evmc
|
|||
#include <evmc/evmc.h>
|
||||
#include <evmc/helpers.h>
|
||||
|
||||
struct extended_context
|
||||
{
|
||||
struct evmc_host_context context;
|
||||
int64_t index;
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
|
@ -99,50 +93,43 @@ type HostContext interface {
|
|||
|
||||
//export accountExists
|
||||
func accountExists(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.bool {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return C.bool(ctx.AccountExists(goAddress(*pAddr)))
|
||||
}
|
||||
|
||||
//export getStorage
|
||||
func getStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.evmc_bytes32) C.evmc_bytes32 {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return evmcBytes32(ctx.GetStorage(goAddress(*pAddr), goHash(*pKey)))
|
||||
}
|
||||
|
||||
//export setStorage
|
||||
func setStorage(pCtx unsafe.Pointer, pAddr *C.evmc_address, pKey *C.evmc_bytes32, pVal *C.evmc_bytes32) C.enum_evmc_storage_status {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return C.enum_evmc_storage_status(ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal)))
|
||||
}
|
||||
|
||||
//export getBalance
|
||||
func getBalance(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_uint256be {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return evmcBytes32(ctx.GetBalance(goAddress(*pAddr)))
|
||||
}
|
||||
|
||||
//export getCodeSize
|
||||
func getCodeSize(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.size_t {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return C.size_t(ctx.GetCodeSize(goAddress(*pAddr)))
|
||||
}
|
||||
|
||||
//export getCodeHash
|
||||
func getCodeHash(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_bytes32 {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return evmcBytes32(ctx.GetCodeHash(goAddress(*pAddr)))
|
||||
}
|
||||
|
||||
//export copyCode
|
||||
func copyCode(pCtx unsafe.Pointer, pAddr *C.evmc_address, offset C.size_t, p *C.uint8_t, size C.size_t) C.size_t {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
code := ctx.GetCode(goAddress(*pAddr))
|
||||
length := C.size_t(len(code))
|
||||
|
||||
|
@ -162,15 +149,13 @@ func copyCode(pCtx unsafe.Pointer, pAddr *C.evmc_address, offset C.size_t, p *C.
|
|||
|
||||
//export selfdestruct
|
||||
func selfdestruct(pCtx unsafe.Pointer, pAddr *C.evmc_address, pBeneficiary *C.evmc_address) {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
ctx.Selfdestruct(goAddress(*pAddr), goAddress(*pBeneficiary))
|
||||
}
|
||||
|
||||
//export getTxContext
|
||||
func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
|
||||
txContext := ctx.GetTxContext()
|
||||
|
||||
|
@ -188,15 +173,13 @@ func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context {
|
|||
|
||||
//export getBlockHash
|
||||
func getBlockHash(pCtx unsafe.Pointer, number int64) C.evmc_bytes32 {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
return evmcBytes32(ctx.GetBlockHash(number))
|
||||
}
|
||||
|
||||
//export emitLog
|
||||
func emitLog(pCtx unsafe.Pointer, pAddr *C.evmc_address, pData unsafe.Pointer, dataSize C.size_t, pTopics unsafe.Pointer, topicsCount C.size_t) {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
|
||||
// FIXME: Optimize memory copy
|
||||
data := C.GoBytes(pData, C.int(dataSize))
|
||||
|
@ -213,8 +196,7 @@ func emitLog(pCtx unsafe.Pointer, pAddr *C.evmc_address, pData unsafe.Pointer, d
|
|||
|
||||
//export call
|
||||
func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result {
|
||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||
ctx := getHostContext(idx)
|
||||
ctx := getHostContext(uintptr(pCtx))
|
||||
|
||||
kind := CallKind(msg.kind)
|
||||
output, gasLeft, createAddr, err := ctx.Call(kind, goAddress(msg.destination), goAddress(msg.sender), goHash(msg.value).Big(),
|
||||
|
|
|
@ -335,6 +335,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream {
|
|||
quote! {
|
||||
extern "C" fn __evmc_execute(
|
||||
instance: *mut ::evmc_vm::ffi::evmc_vm,
|
||||
host: *const ::evmc_vm::ffi::evmc_host_interface,
|
||||
context: *mut ::evmc_vm::ffi::evmc_host_context,
|
||||
revision: ::evmc_vm::ffi::evmc_revision,
|
||||
msg: *const ::evmc_vm::ffi::evmc_message,
|
||||
|
@ -345,14 +346,14 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream {
|
|||
use evmc_vm::EvmcVm;
|
||||
|
||||
// TODO: context is optional in case of the "precompiles" capability
|
||||
if instance.is_null() || context.is_null() || msg.is_null() || (code.is_null() && code_size != 0) {
|
||||
if instance.is_null() || host.is_null() || msg.is_null() || (code.is_null() && code_size != 0) {
|
||||
// These are irrecoverable errors that violate the EVMC spec.
|
||||
std::process::abort();
|
||||
}
|
||||
|
||||
assert!(!instance.is_null());
|
||||
// TODO: context is optional in case of the "precompiles" capability
|
||||
assert!(!context.is_null());
|
||||
// TODO: host is optional in case of the "precompiles" capability
|
||||
assert!(!host.is_null());
|
||||
assert!(!msg.is_null());
|
||||
|
||||
let execution_message: ::evmc_vm::ExecutionMessage = unsafe {
|
||||
|
@ -376,7 +377,10 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream {
|
|||
|
||||
let result = ::std::panic::catch_unwind(|| {
|
||||
let mut execution_context = unsafe {
|
||||
::evmc_vm::ExecutionContext::new(context.as_mut().expect("EVMC context is null"))
|
||||
::evmc_vm::ExecutionContext::new(
|
||||
host.as_ref().expect("EVMC host is null"),
|
||||
context,
|
||||
)
|
||||
};
|
||||
container.execute(revision, code_ref, &execution_message, &mut execution_context)
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ fn gen_bindings() {
|
|||
.rustified_enum("*")
|
||||
// force deriving the Hash trait on basic types (address, bytes32)
|
||||
.derive_hash(true)
|
||||
.opaque_type("evmc_host_context")
|
||||
.generate()
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ mod tests {
|
|||
use crate::{ExecutionContext, ExecutionMessage, ExecutionResult};
|
||||
|
||||
struct TestVm {}
|
||||
|
||||
impl EvmcVm for TestVm {
|
||||
fn init() -> Self {
|
||||
TestVm {}
|
||||
|
@ -131,9 +132,9 @@ mod tests {
|
|||
get_block_hash: None,
|
||||
emit_log: None,
|
||||
};
|
||||
let mut backing_context = ::evmc_sys::evmc_host_context { host: &host };
|
||||
let host_context = std::ptr::null_mut();
|
||||
|
||||
let mut context = ExecutionContext::new(&mut backing_context);
|
||||
let mut context = ExecutionContext::new(&host, host_context);
|
||||
let container = EvmcContainer::<TestVm>::new(instance);
|
||||
assert_eq!(
|
||||
container
|
||||
|
@ -141,7 +142,7 @@ mod tests {
|
|||
evmc_sys::evmc_revision::EVMC_PETERSBURG,
|
||||
&code,
|
||||
&message,
|
||||
&mut context
|
||||
&mut context,
|
||||
)
|
||||
.status_code(),
|
||||
::evmc_sys::evmc_status_code::EVMC_FAILURE
|
||||
|
@ -149,7 +150,7 @@ mod tests {
|
|||
|
||||
let ptr = unsafe { EvmcContainer::into_ffi_pointer(container) };
|
||||
|
||||
let mut context = ExecutionContext::new(&mut backing_context);
|
||||
let mut context = ExecutionContext::new(&host, host_context);
|
||||
let container = unsafe { EvmcContainer::<TestVm>::from_ffi_pointer(ptr) };
|
||||
assert_eq!(
|
||||
container
|
||||
|
@ -157,7 +158,7 @@ mod tests {
|
|||
evmc_sys::evmc_revision::EVMC_PETERSBURG,
|
||||
&code,
|
||||
&message,
|
||||
&mut context
|
||||
&mut context,
|
||||
)
|
||||
.status_code(),
|
||||
::evmc_sys::evmc_status_code::EVMC_FAILURE
|
||||
|
|
|
@ -58,7 +58,8 @@ pub type ExecutionTxContext = ffi::evmc_tx_context;
|
|||
/// EVMC context structure. Exposes the EVMC host functions, message data, and transaction context
|
||||
/// to the executing VM.
|
||||
pub struct ExecutionContext<'a> {
|
||||
context: &'a mut ffi::evmc_host_context,
|
||||
host: &'a ffi::evmc_host_interface,
|
||||
context: *mut ffi::evmc_host_context,
|
||||
tx_context: ExecutionTxContext,
|
||||
}
|
||||
|
||||
|
@ -194,14 +195,14 @@ impl ExecutionMessage {
|
|||
}
|
||||
|
||||
impl<'a> ExecutionContext<'a> {
|
||||
pub fn new(_context: &'a mut ffi::evmc_host_context) -> Self {
|
||||
assert!(_context.host != std::ptr::null());
|
||||
pub fn new(host: &'a ffi::evmc_host_interface, _context: *mut ffi::evmc_host_context) -> Self {
|
||||
let _tx_context = unsafe {
|
||||
assert!((*(_context.host)).get_tx_context.is_some());
|
||||
(*(_context.host)).get_tx_context.unwrap()(_context as *mut ffi::evmc_host_context)
|
||||
assert!((*host).get_tx_context.is_some());
|
||||
(*host).get_tx_context.unwrap()(_context)
|
||||
};
|
||||
|
||||
ExecutionContext {
|
||||
host: host,
|
||||
context: _context,
|
||||
tx_context: _tx_context,
|
||||
}
|
||||
|
@ -215,20 +216,17 @@ impl<'a> ExecutionContext<'a> {
|
|||
/// Check if an account exists.
|
||||
pub fn account_exists(&mut self, address: &Address) -> bool {
|
||||
unsafe {
|
||||
assert!((*self.context.host).account_exists.is_some());
|
||||
(*self.context.host).account_exists.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
address as *const Address,
|
||||
)
|
||||
assert!((*self.host).account_exists.is_some());
|
||||
(*self.host).account_exists.unwrap()(self.context, address as *const Address)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from a storage key.
|
||||
pub fn get_storage(&mut self, address: &Address, key: &Bytes32) -> Bytes32 {
|
||||
unsafe {
|
||||
assert!((*self.context.host).get_storage.is_some());
|
||||
(*self.context.host).get_storage.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
assert!((*self.host).get_storage.is_some());
|
||||
(*self.host).get_storage.unwrap()(
|
||||
self.context,
|
||||
address as *const Address,
|
||||
key as *const Bytes32,
|
||||
)
|
||||
|
@ -243,9 +241,9 @@ impl<'a> ExecutionContext<'a> {
|
|||
value: &Bytes32,
|
||||
) -> ffi::evmc_storage_status {
|
||||
unsafe {
|
||||
assert!((*self.context.host).set_storage.is_some());
|
||||
(*self.context.host).set_storage.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
assert!((*self.host).set_storage.is_some());
|
||||
(*self.host).set_storage.unwrap()(
|
||||
self.context,
|
||||
address as *const Address,
|
||||
key as *const Bytes32,
|
||||
value as *const Bytes32,
|
||||
|
@ -256,42 +254,33 @@ impl<'a> ExecutionContext<'a> {
|
|||
/// Get balance of an account.
|
||||
pub fn get_balance(&mut self, address: &Address) -> Uint256 {
|
||||
unsafe {
|
||||
assert!((*self.context.host).get_balance.is_some());
|
||||
(*self.context.host).get_balance.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
address as *const Address,
|
||||
)
|
||||
assert!((*self.host).get_balance.is_some());
|
||||
(*self.host).get_balance.unwrap()(self.context, address as *const Address)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get code size of an account.
|
||||
pub fn get_code_size(&mut self, address: &Address) -> usize {
|
||||
unsafe {
|
||||
assert!((*self.context.host).get_code_size.is_some());
|
||||
(*self.context.host).get_code_size.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
address as *const Address,
|
||||
)
|
||||
assert!((*self.host).get_code_size.is_some());
|
||||
(*self.host).get_code_size.unwrap()(self.context, address as *const Address)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get code hash of an account.
|
||||
pub fn get_code_hash(&mut self, address: &Address) -> Bytes32 {
|
||||
unsafe {
|
||||
assert!((*self.context.host).get_code_size.is_some());
|
||||
(*self.context.host).get_code_hash.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
address as *const Address,
|
||||
)
|
||||
assert!((*self.host).get_code_size.is_some());
|
||||
(*self.host).get_code_hash.unwrap()(self.context, address as *const Address)
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy code of an account.
|
||||
pub fn copy_code(&mut self, address: &Address, code_offset: usize, buffer: &mut [u8]) -> usize {
|
||||
unsafe {
|
||||
assert!((*self.context.host).copy_code.is_some());
|
||||
(*self.context.host).copy_code.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
assert!((*self.host).copy_code.is_some());
|
||||
(*self.host).copy_code.unwrap()(
|
||||
self.context,
|
||||
address as *const Address,
|
||||
code_offset,
|
||||
// FIXME: ensure that alignment of the array elements is OK
|
||||
|
@ -304,9 +293,9 @@ impl<'a> ExecutionContext<'a> {
|
|||
/// Self-destruct the current account.
|
||||
pub fn selfdestruct(&mut self, address: &Address, beneficiary: &Address) {
|
||||
unsafe {
|
||||
assert!((*self.context.host).selfdestruct.is_some());
|
||||
(*self.context.host).selfdestruct.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
assert!((*self.host).selfdestruct.is_some());
|
||||
(*self.host).selfdestruct.unwrap()(
|
||||
self.context,
|
||||
address as *const Address,
|
||||
beneficiary as *const Address,
|
||||
)
|
||||
|
@ -343,32 +332,25 @@ impl<'a> ExecutionContext<'a> {
|
|||
create2_salt: *message.create2_salt(),
|
||||
};
|
||||
unsafe {
|
||||
assert!((*self.context.host).call.is_some());
|
||||
(*self.context.host).call.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
&message as *const ffi::evmc_message,
|
||||
)
|
||||
.into()
|
||||
assert!((*self.host).call.is_some());
|
||||
(*self.host).call.unwrap()(self.context, &message as *const ffi::evmc_message).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get block hash of an account.
|
||||
pub fn get_block_hash(&mut self, num: i64) -> Bytes32 {
|
||||
unsafe {
|
||||
assert!((*self.context.host).get_block_hash.is_some());
|
||||
(*self.context.host).get_block_hash.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
num,
|
||||
)
|
||||
assert!((*self.host).get_block_hash.is_some());
|
||||
(*self.host).get_block_hash.unwrap()(self.context, num)
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a log.
|
||||
pub fn emit_log(&mut self, address: &Address, data: &[u8], topics: &[Bytes32]) {
|
||||
unsafe {
|
||||
assert!((*self.context.host).emit_log.is_some());
|
||||
(*self.context.host).emit_log.unwrap()(
|
||||
self.context as *mut ffi::evmc_host_context,
|
||||
assert!((*self.host).emit_log.is_some());
|
||||
(*self.host).emit_log.unwrap()(
|
||||
self.context,
|
||||
address as *const Address,
|
||||
// FIXME: ensure that alignment of the array elements is OK
|
||||
data.as_ptr(),
|
||||
|
@ -801,74 +783,59 @@ mod tests {
|
|||
}
|
||||
|
||||
// Update these when needed for tests
|
||||
fn get_dummy_context() -> ffi::evmc_host_context {
|
||||
ffi::evmc_host_context {
|
||||
host: Box::into_raw(Box::new(ffi::evmc_host_interface {
|
||||
account_exists: None,
|
||||
get_storage: None,
|
||||
set_storage: None,
|
||||
get_balance: None,
|
||||
get_code_size: Some(get_dummy_code_size),
|
||||
get_code_hash: None,
|
||||
copy_code: None,
|
||||
selfdestruct: None,
|
||||
call: Some(execute_call),
|
||||
get_tx_context: Some(get_dummy_tx_context),
|
||||
get_block_hash: None,
|
||||
emit_log: None,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to safely dispose of the dummy context, and not bring up false positives in the
|
||||
// sanitizers.
|
||||
fn dummy_context_dispose(context: ffi::evmc_host_context) {
|
||||
unsafe {
|
||||
Box::from_raw(context.host as *mut ffi::evmc_host_interface);
|
||||
fn get_dummy_host_interface() -> ffi::evmc_host_interface {
|
||||
ffi::evmc_host_interface {
|
||||
account_exists: None,
|
||||
get_storage: None,
|
||||
set_storage: None,
|
||||
get_balance: None,
|
||||
get_code_size: Some(get_dummy_code_size),
|
||||
get_code_hash: None,
|
||||
copy_code: None,
|
||||
selfdestruct: None,
|
||||
call: Some(execute_call),
|
||||
get_tx_context: Some(get_dummy_tx_context),
|
||||
get_block_hash: None,
|
||||
emit_log: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execution_context() {
|
||||
let mut context_raw = get_dummy_context();
|
||||
// Make a copy here so we don't let get_dummy_context() go out of scope when called again
|
||||
// in get_dummy_tx_context() and cause LLVM
|
||||
// sanitizers to complain
|
||||
let mut context_raw_copy = context_raw.clone();
|
||||
|
||||
let exe_context = ExecutionContext::new(&mut context_raw);
|
||||
let host_context = std::ptr::null_mut();
|
||||
let host_interface = get_dummy_host_interface();
|
||||
let exe_context = ExecutionContext::new(&host_interface, host_context);
|
||||
let a = exe_context.get_tx_context();
|
||||
let b =
|
||||
unsafe { get_dummy_tx_context(&mut context_raw_copy as *mut ffi::evmc_host_context) };
|
||||
|
||||
let b = unsafe { get_dummy_tx_context(host_context) };
|
||||
|
||||
assert_eq!(a.block_gas_limit, b.block_gas_limit);
|
||||
assert_eq!(a.block_timestamp, b.block_timestamp);
|
||||
assert_eq!(a.block_number, b.block_number);
|
||||
|
||||
dummy_context_dispose(context_raw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_code_size() {
|
||||
// This address is useless. Just a dummy parameter for the interface function.
|
||||
let test_addr = Address { bytes: [0u8; 20] };
|
||||
let mut context_raw = get_dummy_context();
|
||||
let mut exe_context = ExecutionContext::new(&mut context_raw);
|
||||
let host = get_dummy_host_interface();
|
||||
let host_context = std::ptr::null_mut();
|
||||
|
||||
let mut exe_context = ExecutionContext::new(&host, host_context);
|
||||
|
||||
let a: usize = 105023;
|
||||
let b = exe_context.get_code_size(&test_addr);
|
||||
|
||||
assert_eq!(a, b);
|
||||
|
||||
dummy_context_dispose(context_raw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_empty_data() {
|
||||
// This address is useless. Just a dummy parameter for the interface function.
|
||||
let test_addr = ffi::evmc_address { bytes: [0u8; 20] };
|
||||
let mut context_raw = get_dummy_context();
|
||||
let mut exe_context = ExecutionContext::new(&mut context_raw);
|
||||
let host = get_dummy_host_interface();
|
||||
let host_context = std::ptr::null_mut();
|
||||
let mut exe_context = ExecutionContext::new(&host, host_context);
|
||||
|
||||
let message = ExecutionMessage::new(
|
||||
ffi::evmc_call_kind::EVMC_CALL,
|
||||
|
@ -889,16 +856,15 @@ mod tests {
|
|||
assert!(b.output().is_none());
|
||||
assert!(b.create_address().is_some());
|
||||
assert_eq!(b.create_address().unwrap(), &ffi::evmc_address::default());
|
||||
|
||||
dummy_context_dispose(context_raw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_with_data() {
|
||||
// This address is useless. Just a dummy parameter for the interface function.
|
||||
let test_addr = ffi::evmc_address { bytes: [0u8; 20] };
|
||||
let mut context_raw = get_dummy_context();
|
||||
let mut exe_context = ExecutionContext::new(&mut context_raw);
|
||||
let host = get_dummy_host_interface();
|
||||
let host_context = std::ptr::null_mut();
|
||||
let mut exe_context = ExecutionContext::new(&host, host_context);
|
||||
|
||||
let data = vec![0xc0, 0xff, 0xfe];
|
||||
|
||||
|
@ -922,7 +888,5 @@ mod tests {
|
|||
assert_eq!(b.output().unwrap(), &data);
|
||||
assert!(b.create_address().is_some());
|
||||
assert_eq!(b.create_address().unwrap(), &ffi::evmc_address::default());
|
||||
|
||||
dummy_context_dispose(context_raw);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ int main(int argc, char* argv[])
|
|||
tx_context.block_number = 42;
|
||||
tx_context.block_timestamp = 66;
|
||||
tx_context.block_gas_limit = gas * 2;
|
||||
const struct evmc_host_interface* host = example_host_get_interface();
|
||||
struct evmc_host_context* ctx = example_host_create_context(tx_context);
|
||||
struct evmc_message msg;
|
||||
msg.kind = EVMC_CALL;
|
||||
|
@ -58,7 +59,7 @@ int main(int argc, char* argv[])
|
|||
msg.input_size = sizeof(input);
|
||||
msg.gas = gas;
|
||||
msg.depth = 0;
|
||||
struct evmc_result result = evmc_execute(vm, ctx, EVMC_HOMESTEAD, &msg, code, code_size);
|
||||
struct evmc_result result = evmc_execute(vm, host, ctx, EVMC_HOMESTEAD, &msg, code, code_size);
|
||||
printf("Execution result:\n");
|
||||
int exit_code = 0;
|
||||
if (result.status_code != EVMC_SUCCESS)
|
||||
|
@ -77,7 +78,7 @@ int main(int argc, char* argv[])
|
|||
printf("%02x", result.output_data[i]);
|
||||
printf("\n");
|
||||
const evmc_bytes32 storage_key = {{0}};
|
||||
evmc_bytes32 storage_value = ctx->host->get_storage(ctx, &msg.destination, &storage_key);
|
||||
evmc_bytes32 storage_value = host->get_storage(ctx, &msg.destination, &storage_key);
|
||||
printf(" Storage at 0x00..00: ");
|
||||
for (i = 0; i < sizeof(storage_value.bytes) / sizeof(storage_value.bytes[0]); i++)
|
||||
printf("%02x", storage_value.bytes[i]);
|
||||
|
|
|
@ -160,13 +160,19 @@ public:
|
|||
|
||||
extern "C" {
|
||||
|
||||
const evmc_host_interface* example_host_get_interface()
|
||||
{
|
||||
return evmc::Host::get_interface();
|
||||
}
|
||||
|
||||
evmc_host_context* example_host_create_context(evmc_tx_context tx_context)
|
||||
{
|
||||
return new ExampleHost(tx_context);
|
||||
auto host = new ExampleHost{tx_context};
|
||||
return host->to_context();
|
||||
}
|
||||
|
||||
void example_host_destroy_context(evmc_host_context* context)
|
||||
{
|
||||
delete static_cast<ExampleHost*>(context);
|
||||
delete evmc::Host::from_context<ExampleHost>(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
const struct evmc_host_interface* example_host_get_interface();
|
||||
|
||||
struct evmc_host_context* example_host_create_context(struct evmc_tx_context tx_context);
|
||||
|
||||
void example_host_destroy_context(struct evmc_host_context* context);
|
||||
|
|
|
@ -48,8 +48,9 @@ static evmc_result not_implemented()
|
|||
return result;
|
||||
}
|
||||
|
||||
static evmc_result execute(evmc_vm*,
|
||||
evmc_host_context*,
|
||||
static evmc_result execute(evmc_vm* /*unused*/,
|
||||
const evmc_host_interface* /*unused*/,
|
||||
evmc_host_context* /*unused*/,
|
||||
enum evmc_revision rev,
|
||||
const evmc_message* msg,
|
||||
const uint8_t*,
|
||||
|
|
|
@ -75,6 +75,7 @@ static void free_result_output_data(const struct evmc_result* result)
|
|||
|
||||
/// The example implementation of the evmc_vm::execute() method.
|
||||
static struct evmc_result execute(struct evmc_vm* instance,
|
||||
const struct evmc_host_interface* host,
|
||||
struct evmc_host_context* context,
|
||||
enum evmc_revision rev,
|
||||
const struct evmc_message* msg,
|
||||
|
@ -142,16 +143,16 @@ static struct evmc_result execute(struct evmc_vm* instance,
|
|||
strncmp((const char*)code, counter, code_size) == 0)
|
||||
{
|
||||
const evmc_bytes32 key = {{0}};
|
||||
evmc_bytes32 value = context->host->get_storage(context, &msg->destination, &key);
|
||||
evmc_bytes32 value = host->get_storage(context, &msg->destination, &key);
|
||||
value.bytes[31]++;
|
||||
context->host->set_storage(context, &msg->destination, &key, &value);
|
||||
host->set_storage(context, &msg->destination, &key, &value);
|
||||
ret.status_code = EVMC_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
else if (code_size == (sizeof(return_block_number) - 1) &&
|
||||
strncmp((const char*)code, return_block_number, code_size) == 0)
|
||||
{
|
||||
const struct evmc_tx_context tx_context = context->host->get_tx_context(context);
|
||||
const struct evmc_tx_context tx_context = host->get_tx_context(context);
|
||||
const size_t output_size = 20;
|
||||
|
||||
uint8_t* output_data = (uint8_t*)calloc(1, output_size);
|
||||
|
@ -166,7 +167,7 @@ static struct evmc_result execute(struct evmc_vm* instance,
|
|||
else if (code_size == (sizeof(save_return_block_number) - 1) &&
|
||||
strncmp((const char*)code, save_return_block_number, code_size) == 0)
|
||||
{
|
||||
const struct evmc_tx_context tx_context = context->host->get_tx_context(context);
|
||||
const struct evmc_tx_context tx_context = host->get_tx_context(context);
|
||||
const size_t output_size = 20;
|
||||
|
||||
// Store block number.
|
||||
|
@ -174,7 +175,7 @@ static struct evmc_result execute(struct evmc_vm* instance,
|
|||
evmc_bytes32 value = {{0}};
|
||||
// NOTE: assume block number is <= 255
|
||||
value.bytes[31] = (uint8_t)tx_context.block_number;
|
||||
context->host->set_storage(context, &msg->destination, &key, &value);
|
||||
host->set_storage(context, &msg->destination, &key, &value);
|
||||
|
||||
// Return block number.
|
||||
uint8_t* output_data = (uint8_t*)calloc(1, output_size);
|
||||
|
@ -195,7 +196,7 @@ static struct evmc_result execute(struct evmc_vm* instance,
|
|||
call_msg.depth = msg->depth + 1;
|
||||
call_msg.gas = msg->gas - (msg->gas / 64);
|
||||
call_msg.sender = msg->destination;
|
||||
return context->host->call(context, &call_msg);
|
||||
return host->call(context, &call_msg);
|
||||
}
|
||||
|
||||
ret.status_code = EVMC_FAILURE;
|
||||
|
|
|
@ -156,6 +156,11 @@ struct evmc_tx_context
|
|||
evmc_uint256be chain_id; /**< The blockchain's ChainID. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct evmc_host_context
|
||||
* The opaque data type representing the Host execution context.
|
||||
* @see evmc_execute_fn().
|
||||
*/
|
||||
struct evmc_host_context;
|
||||
|
||||
/**
|
||||
|
@ -653,22 +658,6 @@ struct evmc_host_interface
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execution context managed by the Host.
|
||||
*
|
||||
* The Host MUST pass the pointer to the execution context to ::evmc_execute_fn.
|
||||
* The VM MUST pass the same pointer back to the Host in every callback function.
|
||||
* The context MUST contain at least the function table defining
|
||||
* the context callback interface.
|
||||
* Optionally, the Host MAY include in the context additional data.
|
||||
*/
|
||||
struct evmc_host_context
|
||||
{
|
||||
/** The Host interface. */
|
||||
const struct evmc_host_interface* host;
|
||||
};
|
||||
|
||||
|
||||
/* Forward declaration. */
|
||||
struct evmc_vm;
|
||||
|
||||
|
@ -791,10 +780,12 @@ enum evmc_revision
|
|||
* This function MAY be invoked multiple times for a single VM instance.
|
||||
*
|
||||
* @param vm The VM instance. This argument MUST NOT be NULL.
|
||||
* @param context The pointer to the Host execution context to be passed
|
||||
* to the Host interface methods (::evmc_host_interface).
|
||||
* This argument MUST NOT be NULL unless
|
||||
* @param host The Host interface. This argument MUST NOT be NULL unless
|
||||
* the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability.
|
||||
* @param context The opaque pointer to the Host execution context.
|
||||
* This argument MAY be NULL. The VM MUST pass the same
|
||||
* pointer to the methods of the @p host interface.
|
||||
* The VM MUST NOT dereference the pointer.
|
||||
* @param rev The requested EVM specification revision.
|
||||
* @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL.
|
||||
* @param code The reference to the code to be executed. This argument MAY be NULL.
|
||||
|
@ -802,6 +793,7 @@ enum evmc_revision
|
|||
* @return The execution result.
|
||||
*/
|
||||
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm,
|
||||
const struct evmc_host_interface* host,
|
||||
struct evmc_host_context* context,
|
||||
enum evmc_revision rev,
|
||||
const struct evmc_message* msg,
|
||||
|
|
|
@ -398,13 +398,14 @@ public:
|
|||
}
|
||||
|
||||
/// @copydoc evmc_execute()
|
||||
result execute(evmc_host_context& ctx,
|
||||
result execute(const evmc_host_interface& host,
|
||||
evmc_host_context* ctx,
|
||||
evmc_revision rev,
|
||||
const evmc_message& msg,
|
||||
const uint8_t* code,
|
||||
size_t code_size) noexcept
|
||||
{
|
||||
return result{m_instance->execute(m_instance, &ctx, rev, &msg, code, code_size)};
|
||||
return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -478,43 +479,46 @@ public:
|
|||
/// To be used by VM implementations as better alternative to using ::evmc_host_context directly.
|
||||
class HostContext : public HostInterface
|
||||
{
|
||||
const evmc_host_interface* host = nullptr;
|
||||
evmc_host_context* context = nullptr;
|
||||
evmc_tx_context tx_context = {};
|
||||
|
||||
public:
|
||||
/// Implicit converting constructor from evmc_host_context.
|
||||
HostContext(evmc_host_context* ctx) noexcept : context{ctx} {} // NOLINT
|
||||
HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept
|
||||
: host{interface}, context{ctx}
|
||||
{}
|
||||
|
||||
bool account_exists(const address& address) noexcept final
|
||||
{
|
||||
return context->host->account_exists(context, &address);
|
||||
return host->account_exists(context, &address);
|
||||
}
|
||||
|
||||
bytes32 get_storage(const address& address, const bytes32& key) noexcept final
|
||||
{
|
||||
return context->host->get_storage(context, &address, &key);
|
||||
return host->get_storage(context, &address, &key);
|
||||
}
|
||||
|
||||
evmc_storage_status set_storage(const address& address,
|
||||
const bytes32& key,
|
||||
const bytes32& value) noexcept final
|
||||
{
|
||||
return context->host->set_storage(context, &address, &key, &value);
|
||||
return host->set_storage(context, &address, &key, &value);
|
||||
}
|
||||
|
||||
uint256be get_balance(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_balance(context, &address);
|
||||
return host->get_balance(context, &address);
|
||||
}
|
||||
|
||||
size_t get_code_size(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_code_size(context, &address);
|
||||
return host->get_code_size(context, &address);
|
||||
}
|
||||
|
||||
bytes32 get_code_hash(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_code_hash(context, &address);
|
||||
return host->get_code_hash(context, &address);
|
||||
}
|
||||
|
||||
size_t copy_code(const address& address,
|
||||
|
@ -522,17 +526,17 @@ public:
|
|||
uint8_t* buffer_data,
|
||||
size_t buffer_size) noexcept final
|
||||
{
|
||||
return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
|
||||
return host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
|
||||
}
|
||||
|
||||
void selfdestruct(const address& addr, const address& beneficiary) noexcept final
|
||||
{
|
||||
context->host->selfdestruct(context, &addr, &beneficiary);
|
||||
host->selfdestruct(context, &addr, &beneficiary);
|
||||
}
|
||||
|
||||
result call(const evmc_message& message) noexcept final
|
||||
{
|
||||
return result{context->host->call(context, &message)};
|
||||
return result{host->call(context, &message)};
|
||||
}
|
||||
|
||||
/// @copydoc HostInterface::get_tx_context()
|
||||
|
@ -544,13 +548,13 @@ public:
|
|||
evmc_tx_context get_tx_context() noexcept final
|
||||
{
|
||||
if (tx_context.block_timestamp == 0)
|
||||
tx_context = context->host->get_tx_context(context);
|
||||
tx_context = host->get_tx_context(context);
|
||||
return tx_context;
|
||||
}
|
||||
|
||||
bytes32 get_block_hash(int64_t number) noexcept final
|
||||
{
|
||||
return context->host->get_block_hash(context, number);
|
||||
return host->get_block_hash(context, number);
|
||||
}
|
||||
|
||||
void emit_log(const address& addr,
|
||||
|
@ -559,7 +563,7 @@ public:
|
|||
const bytes32 topics[],
|
||||
size_t topics_count) noexcept final
|
||||
{
|
||||
context->host->emit_log(context, &addr, data, data_size, topics, topics_count);
|
||||
host->emit_log(context, &addr, data, data_size, topics, topics_count);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -567,70 +571,101 @@ public:
|
|||
///
|
||||
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
|
||||
/// This way your implementation will be simpler by avoiding manual handling
|
||||
/// of the ::evmc_host_context and the ::evmc_host_context::host.
|
||||
class Host : public HostInterface, public evmc_host_context
|
||||
/// of the ::evmc_host_context and the ::evmc_host_interface.
|
||||
class Host : public HostInterface
|
||||
{
|
||||
public:
|
||||
inline Host() noexcept;
|
||||
/// Provides access to the global host interface.
|
||||
/// @returns Pointer to the host interface object.
|
||||
static const evmc_host_interface* get_interface() noexcept;
|
||||
|
||||
/// Converts the Host object to the opaque host context pointer.
|
||||
/// @returns Pointer to evmc_host_context.
|
||||
evmc_host_context* to_context() noexcept { return reinterpret_cast<evmc_host_context*>(this); }
|
||||
|
||||
/// Converts the opaque host context pointer back to the original Host object.
|
||||
/// @tparam DerivedClass The class derived from the Host class.
|
||||
/// @param context The opaque host context pointer.
|
||||
/// @returns The pointer to DerivedClass.
|
||||
template <typename DerivedClass = Host>
|
||||
static DerivedClass* from_context(evmc_host_context* context) noexcept
|
||||
{
|
||||
// Get pointer of the Host base class.
|
||||
auto* h = reinterpret_cast<Host*>(context);
|
||||
|
||||
// Additional downcast, only possible if DerivedClass inherits from Host.
|
||||
return static_cast<DerivedClass*>(h);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->account_exists(*addr);
|
||||
return Host::from_context(h)->account_exists(*addr);
|
||||
}
|
||||
|
||||
inline evmc_bytes32 get_storage(evmc_host_context* h,
|
||||
const evmc_address* addr,
|
||||
const evmc_bytes32* key) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_storage(*addr, *key);
|
||||
return Host::from_context(h)->get_storage(*addr, *key);
|
||||
}
|
||||
|
||||
inline evmc_storage_status set_storage(evmc_host_context* h,
|
||||
const evmc_address* addr,
|
||||
const evmc_bytes32* key,
|
||||
const evmc_bytes32* value) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->set_storage(*addr, *key, *value);
|
||||
return Host::from_context(h)->set_storage(*addr, *key, *value);
|
||||
}
|
||||
|
||||
inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_balance(*addr);
|
||||
return Host::from_context(h)->get_balance(*addr);
|
||||
}
|
||||
|
||||
inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_code_size(*addr);
|
||||
return Host::from_context(h)->get_code_size(*addr);
|
||||
}
|
||||
|
||||
inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_code_hash(*addr);
|
||||
return Host::from_context(h)->get_code_hash(*addr);
|
||||
}
|
||||
|
||||
inline size_t copy_code(evmc_host_context* h,
|
||||
const evmc_address* addr,
|
||||
size_t code_offset,
|
||||
uint8_t* buffer_data,
|
||||
size_t buffer_size) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->copy_code(*addr, code_offset, buffer_data, buffer_size);
|
||||
return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size);
|
||||
}
|
||||
|
||||
inline void selfdestruct(evmc_host_context* h,
|
||||
const evmc_address* addr,
|
||||
const evmc_address* beneficiary) noexcept
|
||||
{
|
||||
static_cast<Host*>(h)->selfdestruct(*addr, *beneficiary);
|
||||
Host::from_context(h)->selfdestruct(*addr, *beneficiary);
|
||||
}
|
||||
|
||||
inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->call(*msg).release_raw();
|
||||
return Host::from_context(h)->call(*msg).release_raw();
|
||||
}
|
||||
|
||||
inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_tx_context();
|
||||
return Host::from_context(h)->get_tx_context();
|
||||
}
|
||||
|
||||
inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept
|
||||
{
|
||||
return static_cast<Host*>(h)->get_block_hash(block_number);
|
||||
return Host::from_context(h)->get_block_hash(block_number);
|
||||
}
|
||||
|
||||
inline void emit_log(evmc_host_context* h,
|
||||
const evmc_address* addr,
|
||||
const uint8_t* data,
|
||||
|
@ -638,17 +673,22 @@ inline void emit_log(evmc_host_context* h,
|
|||
const evmc_bytes32 topics[],
|
||||
size_t num_topics) noexcept
|
||||
{
|
||||
static_cast<Host*>(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics),
|
||||
Host::from_context(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics),
|
||||
num_topics);
|
||||
}
|
||||
|
||||
constexpr evmc_host_interface interface{
|
||||
account_exists, get_storage, set_storage, get_balance, get_code_size, get_code_hash,
|
||||
copy_code, selfdestruct, call, get_tx_context, get_block_hash, emit_log};
|
||||
} // namespace internal
|
||||
|
||||
inline Host::Host() noexcept : evmc_host_context{&evmc::internal::interface} {}
|
||||
|
||||
inline const evmc_host_interface* Host::get_interface() noexcept
|
||||
{
|
||||
static constexpr evmc_host_interface interface{
|
||||
::evmc::internal::account_exists, ::evmc::internal::get_storage,
|
||||
::evmc::internal::set_storage, ::evmc::internal::get_balance,
|
||||
::evmc::internal::get_code_size, ::evmc::internal::get_code_hash,
|
||||
::evmc::internal::copy_code, ::evmc::internal::selfdestruct,
|
||||
::evmc::internal::call, ::evmc::internal::get_tx_context,
|
||||
::evmc::internal::get_block_hash, ::evmc::internal::emit_log};
|
||||
return &interface;
|
||||
}
|
||||
} // namespace evmc
|
||||
|
||||
|
||||
|
|
|
@ -85,13 +85,14 @@ static inline enum evmc_set_option_result evmc_set_option(struct evmc_vm* vm,
|
|||
* @see evmc_execute_fn.
|
||||
*/
|
||||
static inline struct evmc_result evmc_execute(struct evmc_vm* vm,
|
||||
const struct evmc_host_interface* host,
|
||||
struct evmc_host_context* context,
|
||||
enum evmc_revision rev,
|
||||
const struct evmc_message* msg,
|
||||
uint8_t const* code,
|
||||
size_t code_size)
|
||||
{
|
||||
return vm->execute(vm, context, rev, msg, code, code_size);
|
||||
return vm->execute(vm, host, context, rev, msg, code, code_size);
|
||||
}
|
||||
|
||||
/// The evmc_result release function using free() for releasing the memory.
|
||||
|
|
|
@ -268,8 +268,8 @@ TEST(cpp, vm)
|
|||
EXPECT_EQ(vm.name(), std::string{"example_vm"});
|
||||
EXPECT_NE(vm.version()[0], 0);
|
||||
|
||||
auto ctx = evmc_host_context{};
|
||||
auto res = vm.execute(ctx, EVMC_MAX_REVISION, {}, nullptr, 0);
|
||||
const auto host = evmc_host_interface{};
|
||||
auto res = vm.execute(host, nullptr, EVMC_MAX_REVISION, {}, nullptr, 0);
|
||||
EXPECT_EQ(res.status_code, EVMC_FAILURE);
|
||||
|
||||
EXPECT_TRUE(vm.get_capabilities() & EVMC_CAPABILITY_EVM1);
|
||||
|
@ -348,8 +348,9 @@ TEST(cpp, host)
|
|||
{
|
||||
// Use example host to execute all methods from the C++ host wrapper.
|
||||
|
||||
auto* host_interface = example_host_get_interface();
|
||||
auto* host_context = example_host_create_context(evmc_tx_context{});
|
||||
auto host = evmc::HostContext{host_context};
|
||||
auto host = evmc::HostContext{host_interface, host_context};
|
||||
|
||||
const auto a = evmc::address{{{1}}};
|
||||
const auto v = evmc::bytes32{{{7, 7, 7}}};
|
||||
|
@ -382,8 +383,9 @@ TEST(cpp, host_call)
|
|||
{
|
||||
// Use example host to test Host::call() method.
|
||||
|
||||
auto* host_interface = example_host_get_interface();
|
||||
auto* host_context = example_host_create_context(evmc_tx_context{});
|
||||
auto host = evmc::HostContext{host_context};
|
||||
auto host = evmc::HostContext{host_interface, host_context};
|
||||
|
||||
EXPECT_EQ(host.call({}).gas_left, 0);
|
||||
|
||||
|
|
|
@ -59,12 +59,13 @@ TEST_F(evmc_vm_test, capabilities)
|
|||
|
||||
TEST_F(evmc_vm_test, execute_call)
|
||||
{
|
||||
const evmc_host_interface* host = example_host_get_interface();
|
||||
evmc_host_context* context = example_host_create_context(evmc_tx_context{});
|
||||
evmc_message msg{};
|
||||
std::array<uint8_t, 2> code = {{0xfe, 0x00}};
|
||||
|
||||
evmc_result result =
|
||||
vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
||||
vm->execute(vm, host, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
||||
|
||||
// Validate some constraints
|
||||
if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT)
|
||||
|
@ -92,6 +93,7 @@ TEST_F(evmc_vm_test, execute_call)
|
|||
|
||||
TEST_F(evmc_vm_test, execute_create)
|
||||
{
|
||||
const evmc_host_interface* host = example_host_get_interface();
|
||||
evmc_host_context* context = example_host_create_context(evmc_tx_context{});
|
||||
evmc_message msg{
|
||||
EVMC_CREATE, 0, 0, 65536, evmc_address{}, evmc_address{}, nullptr, 0, evmc_uint256be{},
|
||||
|
@ -99,7 +101,7 @@ TEST_F(evmc_vm_test, execute_create)
|
|||
std::array<uint8_t, 2> code = {{0xfe, 0x00}};
|
||||
|
||||
evmc_result result =
|
||||
vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
||||
vm->execute(vm, host, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
||||
|
||||
// Validate some constraints
|
||||
if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT)
|
||||
|
@ -181,7 +183,7 @@ TEST_F(evmc_vm_test, precompile_test)
|
|||
EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, nullptr, 0, evmc_uint256be{},
|
||||
evmc_bytes32{}};
|
||||
|
||||
evmc_result result = vm->execute(vm, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);
|
||||
evmc_result result = vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);
|
||||
|
||||
// Validate some constraints
|
||||
|
||||
|
|
Loading…
Reference in New Issue