diff --git a/bindings/go/evmc/evmc.go b/bindings/go/evmc/evmc.go index 2ad14ffda..48357d88f 100644 --- a/bindings/go/evmc/evmc.go +++ b/bindings/go/evmc/evmc.go @@ -44,12 +44,12 @@ static struct evmc_result execute_wrapper(struct evmc_vm* vm, *value, {{0}}, // create2_salt: not required for execution {{0}}, // code_address: not required for execution - 0, // code - 0, // code_size + 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); + return evmc_execute(vm, &evmc_go_host, context, rev, &msg); } */ import "C" diff --git a/bindings/rust/evmc-declare-tests/src/lib.rs b/bindings/rust/evmc-declare-tests/src/lib.rs index 10eb373dc..8fb5763aa 100644 --- a/bindings/rust/evmc-declare-tests/src/lib.rs +++ b/bindings/rust/evmc-declare-tests/src/lib.rs @@ -31,7 +31,6 @@ impl EvmcVm for FooVM { fn execute( &self, _revision: evmc_sys::evmc_revision, - _code: &[u8], _message: &ExecutionMessage, _context: Option<&mut ExecutionContext>, ) -> ExecutionResult { diff --git a/bindings/rust/evmc-declare/src/lib.rs b/bindings/rust/evmc-declare/src/lib.rs index fec568bde..607acba99 100644 --- a/bindings/rust/evmc-declare/src/lib.rs +++ b/bindings/rust/evmc-declare/src/lib.rs @@ -21,7 +21,7 @@ //! ExampleVM {} //! } //! -//! fn execute(&self, revision: evmc_vm::ffi::evmc_revision, code: &[u8], message: &evmc_vm::ExecutionMessage, context: Option<&mut evmc_vm::ExecutionContext>) -> evmc_vm::ExecutionResult { +//! fn execute(&self, revision: evmc_vm::ffi::evmc_revision, message: &evmc_vm::ExecutionMessage, context: Option<&mut evmc_vm::ExecutionContext>) -> evmc_vm::ExecutionResult { //! evmc_vm::ExecutionResult::success(1337, 0, None) //! } //! } @@ -395,19 +395,11 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { 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, - code: *const u8, - code_size: usize + msg: *const ::evmc_vm::ffi::evmc_message ) -> ::evmc_vm::ffi::evmc_result { use evmc_vm::EvmcVm; - // TODO: context is optional in case of the "precompiles" capability - if instance.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()); assert!(!msg.is_null()); @@ -415,16 +407,6 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { msg.as_ref().expect("EVMC message is null").into() }; - let empty_code = [0u8;0]; - let code_ref: &[u8] = if code.is_null() { - assert_eq!(code_size, 0); - &empty_code - } else { - unsafe { - ::std::slice::from_raw_parts(code, code_size) - } - }; - let container = unsafe { // Acquire ownership from EVMC. ::evmc_vm::EvmcContainer::<#type_name_ident>::from_ffi_pointer(instance) @@ -432,7 +414,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { let result = ::std::panic::catch_unwind(|| { if host.is_null() { - container.execute(revision, code_ref, &execution_message, None) + container.execute(revision, &execution_message, None) } else { let mut execution_context = unsafe { ::evmc_vm::ExecutionContext::new( @@ -440,7 +422,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { context, ) }; - container.execute(revision, code_ref, &execution_message, Some(&mut execution_context)) + container.execute(revision, &execution_message, Some(&mut execution_context)) } }); diff --git a/bindings/rust/evmc-vm/src/container.rs b/bindings/rust/evmc-vm/src/container.rs index ada3d252e..2339b1ee6 100644 --- a/bindings/rust/evmc-vm/src/container.rs +++ b/bindings/rust/evmc-vm/src/container.rs @@ -81,7 +81,6 @@ mod tests { fn execute( &self, _revision: evmc_sys::evmc_revision, - _code: &[u8], _message: &ExecutionMessage, _context: Option<&mut ExecutionContext>, ) -> ExecutionResult { @@ -120,8 +119,6 @@ mod tests { set_option: None, }; - let code = [0u8; 0]; - let message = ::evmc_sys::evmc_message { kind: ::evmc_sys::evmc_call_kind::EVMC_CALL, flags: 0, @@ -165,7 +162,6 @@ mod tests { container .execute( evmc_sys::evmc_revision::EVMC_PETERSBURG, - &code, &message, Some(&mut context) ) @@ -181,7 +177,6 @@ mod tests { container .execute( evmc_sys::evmc_revision::EVMC_PETERSBURG, - &code, &message, Some(&mut context) ) diff --git a/bindings/rust/evmc-vm/src/lib.rs b/bindings/rust/evmc-vm/src/lib.rs index 1f8378964..44825c47a 100644 --- a/bindings/rust/evmc-vm/src/lib.rs +++ b/bindings/rust/evmc-vm/src/lib.rs @@ -29,7 +29,6 @@ pub trait EvmcVm { fn execute<'a>( &self, revision: Revision, - code: &'a [u8], message: &'a ExecutionMessage, context: Option<&'a mut ExecutionContext<'a>>, ) -> ExecutionResult; @@ -368,7 +367,7 @@ impl<'a> ExecutionContext<'a> { create2_salt: *message.create2_salt(), code_address: *message.code_address(), code: code_data, - code_size, + code_size: code_size, }; unsafe { assert!((*self.host).call.is_some()); diff --git a/examples/example-rust-vm/src/lib.rs b/examples/example-rust-vm/src/lib.rs index 2fe215a1b..caa7218db 100644 --- a/examples/example-rust-vm/src/lib.rs +++ b/examples/example-rust-vm/src/lib.rs @@ -36,7 +36,6 @@ impl EvmcVm for ExampleRustVM { fn execute<'a>( &self, _revision: Revision, - _code: &'a [u8], message: &'a ExecutionMessage, _context: Option<&'a mut ExecutionContext<'a>>, ) -> ExecutionResult { @@ -53,7 +52,7 @@ impl EvmcVm for ExampleRustVM { return ExecutionResult::failure(); } - if _code.is_empty() { + if message.code().unwrap().is_empty() { return ExecutionResult::failure(); } @@ -63,7 +62,7 @@ impl EvmcVm for ExampleRustVM { 0x43, 0x60, 0x00, 0x55, 0x43, 0x60, 0x00, 0x52, 0x59, 0x60, 0x00, 0xf3, ]; - if save_return_block_number != _code { + if save_return_block_number != *message.code().unwrap() { return ExecutionResult::failure(); } diff --git a/examples/example.c b/examples/example.c index 5b9f2148d..07ca13199 100644 --- a/examples/example.c +++ b/examples/example.c @@ -58,8 +58,10 @@ int main(int argc, char* argv[]) .input_size = sizeof(input), .gas = gas, .depth = 0, + .code = code, + .code_size = code_size, }; - struct evmc_result result = evmc_execute(vm, host, ctx, EVMC_HOMESTEAD, &msg, code, code_size); + struct evmc_result result = evmc_execute(vm, host, ctx, EVMC_HOMESTEAD, &msg); printf("Execution result:\n"); int exit_code = 0; if (result.status_code != EVMC_SUCCESS) diff --git a/examples/example_precompiles_vm/example_precompiles_vm.cpp b/examples/example_precompiles_vm/example_precompiles_vm.cpp index 8c6cf3e38..b705fb519 100644 --- a/examples/example_precompiles_vm/example_precompiles_vm.cpp +++ b/examples/example_precompiles_vm/example_precompiles_vm.cpp @@ -52,9 +52,7 @@ evmc_result execute(evmc_vm* /*vm*/, const evmc_host_interface* /*host*/, evmc_host_context* /*context*/, enum evmc_revision rev, - const evmc_message* msg, - const uint8_t* /*code*/, - size_t /*code_size*/) + const evmc_message* msg) { // The EIP-1352 (https://eips.ethereum.org/EIPS/eip-1352) defines // the range 0 - 0xffff (2 bytes) of addresses reserved for precompiled contracts. diff --git a/examples/example_vm/example_vm.cpp b/examples/example_vm/example_vm.cpp index ecb99c8fc..43bb0b5ce 100644 --- a/examples/example_vm/example_vm.cpp +++ b/examples/example_vm/example_vm.cpp @@ -163,9 +163,7 @@ evmc_result execute(evmc_vm* instance, const evmc_host_interface* host, evmc_host_context* context, enum evmc_revision rev, - const evmc_message* msg, - const uint8_t* code, - size_t code_size) + const evmc_message* msg) { auto* vm = static_cast(instance); @@ -176,14 +174,14 @@ evmc_result execute(evmc_vm* instance, Stack stack; Memory memory; - for (size_t pc = 0; pc < code_size; ++pc) + for (size_t pc = 0; pc < msg->code_size; ++pc) { // Check remaining gas, assume each instruction costs 1. gas_left -= 1; if (gas_left < 0) return evmc_make_result(EVMC_OUT_OF_GAS, 0, 0, nullptr, 0); - switch (code[pc]) + switch (msg->code[pc]) { default: return evmc_make_result(EVMC_UNDEFINED_INSTRUCTION, 0, 0, nullptr, 0); @@ -296,9 +294,9 @@ evmc_result execute(evmc_vm* instance, case OP_PUSH32: { evmc_uint256be value = {}; - size_t num_push_bytes = size_t{code[pc]} - OP_PUSH1 + 1; + size_t num_push_bytes = size_t{msg->code[pc]} - OP_PUSH1 + 1; size_t offset = sizeof(value) - num_push_bytes; - std::memcpy(&value.bytes[offset], &code[pc + 1], num_push_bytes); + std::memcpy(&value.bytes[offset], &msg->code[pc + 1], num_push_bytes); pc += num_push_bytes; stack.push(value); break; diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index f8558902c..dd17e4818 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -1056,17 +1056,13 @@ enum evmc_revision * 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. - * @param code_size The length of the code. If @p code is NULL this argument MUST be 0. * @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, - uint8_t const* code, - size_t code_size); + const struct evmc_message* msg); /** * Possible capabilities of a VM. diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index 91386c46f..ab16312f7 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -720,21 +720,15 @@ class VM 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 + const evmc_message& msg) noexcept { - return Result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)}; + return Result{m_instance->execute(m_instance, &host, ctx, rev, &msg)}; } /// Convenient variant of the VM::execute() that takes reference to evmc::Host class. - Result execute(Host& host, - evmc_revision rev, - const evmc_message& msg, - const uint8_t* code, - size_t code_size) noexcept + Result execute(Host& host, evmc_revision rev, const evmc_message& msg) noexcept { - return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size); + return execute(Host::get_interface(), host.to_context(), rev, msg); } /// Executes code without the Host context. @@ -745,13 +739,9 @@ class VM /// but without providing the Host context and interface. /// This method is for experimental precompiles support where execution is /// guaranteed not to require any Host access. - Result execute(evmc_revision rev, - const evmc_message& msg, - const uint8_t* code, - size_t code_size) noexcept + Result execute(evmc_revision rev, const evmc_message& msg) noexcept { - return Result{ - m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; + return Result{m_instance->execute(m_instance, nullptr, nullptr, rev, &msg)}; } /// Returns the pointer to C EVMC struct representing the VM. diff --git a/include/evmc/helpers.h b/include/evmc/helpers.h index 683567ef1..e50a569ab 100644 --- a/include/evmc/helpers.h +++ b/include/evmc/helpers.h @@ -93,11 +93,9 @@ 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) + const struct evmc_message* msg) { - return vm->execute(vm, host, context, rev, msg, code, code_size); + return vm->execute(vm, host, context, rev, msg); } /// The evmc_result release function using free() for releasing the memory. diff --git a/lib/tooling/run.cpp b/lib/tooling/run.cpp index ce8be55e1..eef3255b1 100644 --- a/lib/tooling/run.cpp +++ b/lib/tooling/run.cpp @@ -23,7 +23,6 @@ auto bench(MockedHost& host, evmc::VM& vm, evmc_revision rev, const evmc_message& msg, - bytes_view code, const evmc::Result& expected_result, std::ostream& out) { @@ -37,7 +36,7 @@ auto bench(MockedHost& host, // Probe run: execute once again the already warm code to estimate a single run time. const auto probe_start = clock::now(); - const auto result = vm.execute(host, rev, msg, code.data(), code.size()); + const auto result = vm.execute(host, rev, msg); const auto bench_start = clock::now(); const auto probe_time = bench_start - probe_start; @@ -50,7 +49,7 @@ auto bench(MockedHost& host, // Benchmark loop. const auto num_iterations = std::max(static_cast(target_bench_time / probe_time), 1); for (int i = 0; i < num_iterations; ++i) - vm.execute(host, rev, msg, code.data(), code.size()); + vm.execute(host, rev, msg); const auto bench_time = (clock::now() - bench_start) / num_iterations; out << "Time: " << std::chrono::duration_cast(bench_time).count() << unit_name @@ -77,16 +76,19 @@ int run(VM& vm, msg.gas = gas; msg.input_data = input.data(); msg.input_size = input.size(); + msg.code = code.data(); + msg.code_size = code.size(); - bytes_view exec_code = code; if (create) { evmc_message create_msg{}; create_msg.kind = EVMC_CREATE; create_msg.recipient = create_address; create_msg.gas = create_gas; + create_msg.code = code.data(); + create_msg.code_size = code.size(); - const auto create_result = vm.execute(host, rev, create_msg, code.data(), code.size()); + const auto create_result = vm.execute(host, rev, create_msg); if (create_result.status_code != EVMC_SUCCESS) { out << "Contract creation failed: " << create_result.status_code << "\n"; @@ -97,14 +99,15 @@ int run(VM& vm, created_account.code = bytes(create_result.output_data, create_result.output_size); msg.recipient = create_address; - exec_code = created_account.code; + msg.code = created_account.code.data(); + msg.code_size = created_account.code.size(); } out << "\n"; - const auto result = vm.execute(host, rev, msg, exec_code.data(), exec_code.size()); + const auto result = vm.execute(host, rev, msg); if (bench) - tooling::bench(host, vm, rev, msg, exec_code, result, out); + tooling::bench(host, vm, rev, msg, result, out); const auto gas_used = msg.gas - result.gas_left; out << "Result: " << result.status_code << "\nGas used: " << gas_used << "\n"; diff --git a/test/unittests/cpp_test.cpp b/test/unittests/cpp_test.cpp index 942487a3e..904528d86 100644 --- a/test/unittests/cpp_test.cpp +++ b/test/unittests/cpp_test.cpp @@ -495,7 +495,7 @@ TEST(cpp, vm) const auto host = evmc_host_interface{}; auto msg = evmc_message{}; msg.gas = 1; - auto res = vm.execute(host, nullptr, EVMC_MAX_REVISION, msg, nullptr, 0); + auto res = vm.execute(host, nullptr, EVMC_MAX_REVISION, msg); EXPECT_EQ(res.status_code, EVMC_SUCCESS); EXPECT_EQ(res.gas_left, 1); } @@ -616,7 +616,7 @@ TEST(cpp, vm_execute_precompiles) msg.input_size = input.size(); msg.gas = 18; - auto res = vm.execute(EVMC_MAX_REVISION, msg, nullptr, 0); + auto res = vm.execute(EVMC_MAX_REVISION, msg); EXPECT_EQ(res.status_code, EVMC_SUCCESS); EXPECT_EQ(res.gas_left, 0); ASSERT_EQ(res.output_size, input.size()); @@ -632,7 +632,7 @@ TEST(cpp, vm_execute_with_null_host) auto vm = evmc::VM{evmc_create_example_vm()}; const evmc_message msg{}; - auto res = vm.execute(host, EVMC_FRONTIER, msg, nullptr, 0); + auto res = vm.execute(host, EVMC_FRONTIER, msg); EXPECT_EQ(res.status_code, EVMC_SUCCESS); EXPECT_EQ(res.gas_left, 0); } diff --git a/test/unittests/example_vm_test.cpp b/test/unittests/example_vm_test.cpp index 801d711b2..e8b428957 100644 --- a/test/unittests/example_vm_test.cpp +++ b/test/unittests/example_vm_test.cpp @@ -51,8 +51,10 @@ class example_vm : public testing::Test msg.gas = gas; msg.input_data = input.data(); msg.input_size = input.size(); + msg.code = code.data(); + msg.code_size = code.size(); - return vm.execute(host, rev, msg, code.data(), code.size()); + return vm.execute(host, rev, msg); } }; diff --git a/tools/vmtester/tests.cpp b/tools/vmtester/tests.cpp index dbd903f6d..df7b37652 100644 --- a/tools/vmtester/tests.cpp +++ b/tools/vmtester/tests.cpp @@ -55,12 +55,13 @@ TEST_F(evmc_vm_test, capabilities) TEST_F(evmc_vm_test, execute_call) { evmc::MockedHost mockedHost; - const evmc_message msg{}; + evmc_message msg{}; std::array code = {{0xfe, 0x00}}; + msg.code = code.data(); + msg.code_size = code.size(); - const evmc_result result = - vm->execute(vm, &evmc::MockedHost::get_interface(), mockedHost.to_context(), - EVMC_MAX_REVISION, &msg, code.data(), code.size()); + const evmc_result result = vm->execute(vm, &evmc::MockedHost::get_interface(), + mockedHost.to_context(), EVMC_MAX_REVISION, &msg); // Validate some constraints if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT) @@ -86,6 +87,7 @@ TEST_F(evmc_vm_test, execute_call) TEST_F(evmc_vm_test, execute_create) { + std::array code = {{0xfe, 0x00}}; evmc::MockedHost mockedHost; const evmc_message msg{EVMC_CREATE, 0, @@ -98,13 +100,11 @@ TEST_F(evmc_vm_test, execute_create) evmc_uint256be{}, evmc_bytes32{}, evmc_address{}, - nullptr, - 0}; - std::array code = {{0xfe, 0x00}}; + code.data(), + code.size()}; - const evmc_result result = - vm->execute(vm, &evmc::MockedHost::get_interface(), mockedHost.to_context(), - EVMC_MAX_REVISION, &msg, code.data(), code.size()); + const evmc_result result = vm->execute(vm, &evmc::MockedHost::get_interface(), + mockedHost.to_context(), EVMC_MAX_REVISION, &msg); // Validate some constraints if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT) @@ -194,8 +194,7 @@ TEST_F(evmc_vm_test, precompile_test) nullptr, 0}; - const evmc_result result = - vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0); + const evmc_result result = vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg); // Validate some constraints