From fbc618b7efd89d508fa386eba1ac9f4730e87cc1 Mon Sep 17 00:00:00 2001 From: Mikhail Aksenov Date: Wed, 17 Apr 2024 11:22:48 +0300 Subject: [PATCH 1/2] Initial implementation of call in test host --- .../include/nil/blueprint/assigner.hpp | 4 +- lib/assigner/test/CMakeLists.txt | 4 +- lib/assigner/test/assigner_test.cpp | 161 ++++++++++++++++-- lib/assigner/test/test_host.cpp | 88 ++++++++++ lib/assigner/test/test_host.h | 54 +++--- lib/evmone/instructions.hpp | 22 +-- lib/evmone/instructions_storage.cpp | 6 +- 7 files changed, 284 insertions(+), 55 deletions(-) create mode 100644 lib/assigner/test/test_host.cpp diff --git a/lib/assigner/include/nil/blueprint/assigner.hpp b/lib/assigner/include/nil/blueprint/assigner.hpp index a129e8e..57ff52b 100644 --- a/lib/assigner/include/nil/blueprint/assigner.hpp +++ b/lib/assigner/include/nil/blueprint/assigner.hpp @@ -29,7 +29,7 @@ namespace nil { handler_ptr = std::make_shared>(desc, assignments); } - void evaluate(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_context* ctx, + evmc::Result evaluate(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_context* ctx, evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) { auto vm = static_cast(c_vm); @@ -40,7 +40,7 @@ namespace nil { state->set_handler(handler_ptr); auto res = execute(*vm, msg->gas, *state, code_analysis); - // TODO check res + return evmc::Result{res}; } private: diff --git a/lib/assigner/test/CMakeLists.txt b/lib/assigner/test/CMakeLists.txt index ec4b696..f8a4307 100644 --- a/lib/assigner/test/CMakeLists.txt +++ b/lib/assigner/test/CMakeLists.txt @@ -4,7 +4,9 @@ include(GoogleTest) find_package(GTest CONFIG REQUIRED) -add_executable(assigner_tests assigner_test.cpp) +add_executable(assigner_tests + assigner_test.cpp + test_host.cpp) target_link_libraries( assigner_tests diff --git a/lib/assigner/test/assigner_test.cpp b/lib/assigner/test/assigner_test.cpp index bbde481..b84a996 100644 --- a/lib/assigner/test/assigner_test.cpp +++ b/lib/assigner/test/assigner_test.cpp @@ -13,7 +13,6 @@ class AssignerTest : public testing::Test { public: - using BlueprintFieldType = typename nil::crypto3::algebra::curves::pallas::base_field_type; using ArithmetizationType = nil::crypto3::zk::snark::plonk_constraint_system; static void SetUpTestSuite() { @@ -54,18 +53,19 @@ class AssignerTest : public testing::Test .input_data = input, .input_size = sizeof(input), .value = value, - .create2_salt = 0, + .create2_salt = {0}, .code_address = code_addr }; host_interface = &evmc::Host::get_interface(); - ctx = example_host_create_context(tx_context); + ctx = test_host_create_context(tx_context, assigner_ptr.get()); } static void TearDownTestSuite() { assigner_ptr.reset(); + test_host_destroy_context(ctx); } static std::unique_ptr> assigner_ptr; @@ -77,7 +77,7 @@ class AssignerTest : public testing::Test static struct evmc_message msg; }; -std::unique_ptr> +std::unique_ptr> AssignerTest::assigner_ptr; std::vector> AssignerTest::assignments; @@ -87,6 +87,8 @@ struct evmc_vm* AssignerTest::vm; evmc_revision AssignerTest::rev = {}; struct evmc_message AssignerTest::msg; +using intx::operator""_u256; + TEST_F(AssignerTest, conversions) { intx::uint256 intx_number; @@ -118,7 +120,7 @@ TEST_F(AssignerTest, mul) { assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); EXPECT_EQ(assignments[0].witness(0, 0), 8); - EXPECT_EQ(assignments[0].witness(1, 0), 4); + EXPECT_EQ(assignments[0].witness(0, 1), 4); } TEST_F(AssignerTest, callvalue_calldataload) @@ -131,9 +133,9 @@ TEST_F(AssignerTest, callvalue_calldataload) evmone::OP_CALLDATALOAD, }; assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); - EXPECT_EQ(nil::blueprint::handler::to_uint256(assignments[1].witness(0, 0)), + EXPECT_EQ(nil::blueprint::handler::to_uint256(assignments[0].witness(1, 0)), intx::be::load(msg.value)); - EXPECT_EQ(assignments[1].witness(0, 2), index); + EXPECT_EQ(assignments[0].witness(1, 1), index); } // TODO: test dataload instruction (for now its cost is not defined) @@ -145,7 +147,7 @@ TEST_F(AssignerTest, DISABLED_dataload) { evmone::OP_DATALOAD, }; assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); - EXPECT_EQ(assignments[1].witness(0, 1), index); + EXPECT_EQ(assignments[0].witness(1, 2), index); } TEST_F(AssignerTest, mstore_load) @@ -163,9 +165,9 @@ TEST_F(AssignerTest, mstore_load) evmone::OP_MLOAD, }; assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); - EXPECT_EQ(assignments[2].witness(0, 0), value); - EXPECT_EQ(assignments[2].witness(0, 1), index); - EXPECT_EQ(assignments[2].witness(0, 2), value); + EXPECT_EQ(assignments[0].witness(2, 0), value); + EXPECT_EQ(assignments[0].witness(2, 1), index); + EXPECT_EQ(assignments[0].witness(2, 2), value); } TEST_F(AssignerTest, sstore_load) @@ -183,9 +185,9 @@ TEST_F(AssignerTest, sstore_load) evmone::OP_SLOAD, }; assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); - EXPECT_EQ(assignments[3].witness(0, 0), value); - EXPECT_EQ(assignments[3].witness(0, 1), key); - EXPECT_EQ(assignments[3].witness(0, 2), value); + EXPECT_EQ(assignments[0].witness(3, 0), value); + EXPECT_EQ(assignments[0].witness(3, 1), key); + EXPECT_EQ(assignments[0].witness(3, 2), value); } // TODO: test transient storage opcodes (for now their costs are not defined) @@ -203,7 +205,132 @@ TEST_F(AssignerTest, DISABLED_tstore_load) { evmone::OP_TLOAD, }; assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); - EXPECT_EQ(assignments[3].witness(1, 0), value); - EXPECT_EQ(assignments[3].witness(1, 1), key); - EXPECT_EQ(assignments[3].witness(1, 2), value); + EXPECT_EQ(assignments[0].witness(4, 0), value); + EXPECT_EQ(assignments[0].witness(4, 1), key); + EXPECT_EQ(assignments[0].witness(4, 2), value); +} + +TEST_F(AssignerTest, create) { + + std::vector code = { + // Create an account with 0 wei and no code + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_CREATE, + + // Create an account with 9 wei and no code + evmone::OP_PUSH1, + 1, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 9, + evmone::OP_CREATE, + + // Create an account with 0 wei and 4 FF as code + evmone::OP_PUSH13, + // code 0x63FFFFFFFF60005260046000F3 will be inserted later + + evmone::OP_PUSH1, + 0, + evmone::OP_MSTORE, + evmone::OP_PUSH1, + 2, + evmone::OP_PUSH1, + 13, + evmone::OP_PUSH1, + 19, + evmone::OP_PUSH1, + 0, + evmone::OP_CREATE, + }; + + auto push13_it = std::find(code.begin(), code.end(), evmone::OP_PUSH13); + ASSERT_NE(push13_it, code.end()); + size_t push13_idx = push13_it - code.begin(); + + auto contract_code = 0x63FFFFFFFF60005260046000F3_u256; + auto byte_container = intx::be::store(contract_code); + // Code is in the last 13 bytes of the container + code.insert(code.begin() + push13_idx + 1, &byte_container.bytes[32-13], &byte_container.bytes[32]); + + assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); + // Check stored witnesses of MSTORE instruction at depth 1 + EXPECT_EQ(assignments[1].witness(2, 1), 0); + EXPECT_EQ(assignments[1].witness(2, 0), 0xFFFFFFFF); +} + +TEST_F(AssignerTest, call) { + + std::vector code = { + // Create a contract that creates an exception if first word of calldata is 0 + evmone::OP_PUSH17, + // code 0x67600035600757FE5B60005260086018F3 will be inserted later + evmone::OP_PUSH1, + 0, + + evmone::OP_MSTORE, + evmone::OP_PUSH1, + 17, + evmone::OP_PUSH1, + 15, + evmone::OP_PUSH1, + 0, + evmone::OP_CREATE, + + // Call with no parameters, return 0 + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_DUP6, + evmone::OP_PUSH2, + 0xFF, + 0xFF, + evmone::OP_CALL, + + // Call with non 0 calldata, returns success + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 32, + evmone::OP_PUSH1, + 0, + evmone::OP_PUSH1, + 0, + evmone::OP_DUP7, + evmone::OP_PUSH2, + 0xFF, + 0xFF, + evmone::OP_CALL, + }; + + auto push17_it = std::find(code.begin(), code.end(), evmone::OP_PUSH17); + ASSERT_NE(push17_it, code.end()); + size_t push17_idx = push17_it - code.begin(); + + auto contract_code = 0x67600035600757FE5B60005260086018F3_u256; + auto bytes = intx::be::store(contract_code); + // Code is in the last 13 bytes of the container + code.insert(code.begin() + push17_idx + 1, &bytes.bytes[32-17], &bytes.bytes[32]); + + assigner_ptr->evaluate(vm, host_interface, ctx, rev, &msg, code.data(), code.size()); + // Check stored witness of CALLDATALOAD instruction at depth 1 + EXPECT_EQ(assignments[1].witness(1, 1), 0); } diff --git a/lib/assigner/test/test_host.cpp b/lib/assigner/test/test_host.cpp new file mode 100644 index 0000000..b20863f --- /dev/null +++ b/lib/assigner/test/test_host.cpp @@ -0,0 +1,88 @@ +#include "test_host.h" + +#include +#include + +extern "C" { + +evmc_host_context* test_host_create_context(evmc_tx_context tx_context, AssignerType *assigner) +{ + auto host = new TestHost{tx_context, assigner}; + return host->to_context(); +} + +void test_host_destroy_context(evmc_host_context* context) +{ + delete evmc::Host::from_context(context); +} +} + +evmc::Result TestHost::handle_call(const evmc_message& msg) +{ + evmc_vm * vm = evmc_create_evmone(); + auto account_iter = accounts.find(msg.code_address); + auto &sender_acc = accounts[msg.sender]; + if (account_iter == accounts.end()) + { + // Create account + accounts[msg.code_address] = {}; + } + auto& acc = account_iter->second; + if (msg.kind == EVMC_CALL) { + auto value_to_transfer = intx::be::load(msg.value); + auto balance = intx::be::load(sender_acc.balance); + // Balance was already checked in evmone, so simply adjust it + sender_acc.balance = intx::be::store(balance - value_to_transfer); + acc.balance = intx::be::store( + value_to_transfer + intx::be::load(acc.balance)); + } + if (acc.code.empty()) + { + return evmc::Result{EVMC_SUCCESS, msg.gas, 0, msg.input_data, msg.input_size}; + } + // TODO: handle precompiled contracts + auto res = assigner->evaluate(vm, &get_interface(), to_context(), + EVMC_LATEST_STABLE_REVISION, &msg, acc.code.data(), acc.code.size()); + return res; +} + +evmc::Result TestHost::handle_create(const evmc_message& msg) +{ + evmc::address new_contract_address = calculate_address(msg); + accounts[new_contract_address] = {}; + if (msg.input_size == 0) + { + return evmc::Result{EVMC_SUCCESS, msg.gas, 0, new_contract_address}; + } + evmc::VM vm{evmc_create_evmone()}; + evmc_message init_msg(msg); + init_msg.kind = EVMC_CALL; + init_msg.recipient = new_contract_address; + init_msg.sender = msg.sender; + init_msg.input_size = 0; + auto res = assigner->evaluate(vm.get_raw_pointer(), &get_interface(), to_context(), + EVMC_LATEST_STABLE_REVISION, &init_msg, msg.input_data, msg.input_size); + + if (res.status_code == EVMC_SUCCESS) + { + accounts[new_contract_address].code = + std::vector(res.output_data, res.output_data + res.output_size); + } + res.create_address = new_contract_address; + return res; +} + +evmc::address TestHost::calculate_address(const evmc_message& msg) +{ + // TODO: Implement for CREATE opcode, for now the result is only correct for CREATE2 + // CREATE requires rlp encoding + auto seed = intx::be::load(msg.create2_salt); + auto hash = intx::be::load(ethash::keccak256(msg.input_data, msg.input_size)); + auto sender = intx::be::load(msg.sender); + auto sum = 0xff + seed + hash + sender; + auto rehash = ethash::keccak256(reinterpret_cast(&sum), sizeof(sum)); + // Result address is the last 20 bytes of the hash + evmc::address res; + std::memcpy(res.bytes, rehash.bytes + 12, 20); + return res; +} diff --git a/lib/assigner/test/test_host.h b/lib/assigner/test/test_host.h index eccd5c8..6b61bfb 100644 --- a/lib/assigner/test/test_host.h +++ b/lib/assigner/test/test_host.h @@ -4,6 +4,7 @@ // Based on example host #include +#include #include #include @@ -36,16 +37,23 @@ using accounts = std::map; } // namespace evmc -class ExampleHost : public evmc::Host +using BlueprintFieldType = typename nil::crypto3::algebra::curves::pallas::base_field_type; +using AssignerType = nil::blueprint::assigner; + +class TestHost : public evmc::Host { evmc::accounts accounts; evmc_tx_context tx_context{}; + AssignerType *assigner; public: - ExampleHost() = default; - explicit ExampleHost(evmc_tx_context& _tx_context) noexcept : tx_context{_tx_context} {} - ExampleHost(evmc_tx_context& _tx_context, evmc::accounts& _accounts) noexcept - : accounts{_accounts}, tx_context{_tx_context} + TestHost() = default; + explicit TestHost(evmc_tx_context& _tx_context, AssignerType* _assigner) noexcept + : tx_context{_tx_context}, assigner(_assigner) + {} + + TestHost(evmc_tx_context& _tx_context, AssignerType* _assigner, evmc::accounts& _accounts) noexcept + : accounts{_accounts}, tx_context{_tx_context}, assigner(_assigner) {} bool account_exists(const evmc::address& addr) const noexcept final @@ -131,7 +139,19 @@ class ExampleHost : public evmc::Host evmc::Result call(const evmc_message& msg) noexcept final { - return evmc::Result{EVMC_REVERT, msg.gas, 0, msg.input_data, msg.input_size}; + switch (msg.kind) + { + case EVMC_CALL: + case EVMC_CALLCODE: + case EVMC_DELEGATECALL: + return handle_call(msg); + case EVMC_CREATE: + case EVMC_CREATE2: + return handle_create(msg); + default: + // Unexpected opcode + return evmc::Result{EVMC_INTERNAL_ERROR}; + } } evmc_tx_context get_tx_context() const noexcept final { return tx_context; } @@ -192,26 +212,18 @@ class ExampleHost : public evmc::Host { accounts[addr].transient_storage[key] = value; } + +private: + evmc::Result handle_call(const evmc_message& msg); + evmc::Result handle_create(const evmc_message& msg); + evmc::address calculate_address(const evmc_message& msg); }; 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) -{ - auto host = new ExampleHost{tx_context}; - return host->to_context(); -} - -void example_host_destroy_context(evmc_host_context* context) -{ - delete evmc::Host::from_context(context); -} +evmc_host_context* test_host_create_context(evmc_tx_context tx_context, AssignerType *assigner); +void test_host_destroy_context(evmc_host_context* context); } #endif // EVM1_ASSIGNER_LIB_ASSIGNER_TEST_TEST_HOST_H_ diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 5d4860e..64bfe07 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -168,8 +168,8 @@ inline void add(StackTop stack) noexcept inline void mul(StackTop stack, ExecutionState& state) noexcept { - state.m_handler->set_witness(0, 0, 0, stack[0]); - state.m_handler->set_witness(0, 1, 0, stack[1]); + state.m_handler->set_witness(static_cast(state.msg->depth), 0, 0, stack[0]); + state.m_handler->set_witness(static_cast(state.msg->depth), 0, 1, stack[1]); stack.top() *= stack.pop(); } @@ -412,14 +412,14 @@ inline void caller(StackTop stack, ExecutionState& state) noexcept inline void callvalue(StackTop stack, ExecutionState& state) noexcept { auto val = intx::be::load(state.msg->value); - state.m_handler->set_witness(1, 0, 0, val); + state.m_handler->set_witness(static_cast(state.msg->depth), 1, 0, val); stack.push(val); } inline void calldataload(StackTop stack, ExecutionState& state) noexcept { auto& index = stack.top(); - state.m_handler->set_witness(1, 0, 2, index); + state.m_handler->set_witness(static_cast(state.msg->depth), 1, 1, index); if (state.msg->input_size < index) index = 0; @@ -685,7 +685,7 @@ inline Result mload(StackTop stack, int64_t gas_left, ExecutionState& state) noe return {EVMC_OUT_OF_GAS, gas_left}; index = intx::be::unsafe::load(&state.memory[static_cast(index)]); - state.m_handler->set_witness(2, 0, 2, index); + state.m_handler->set_witness(static_cast(state.msg->depth), 2, 2, index); return {EVMC_SUCCESS, gas_left}; } @@ -695,8 +695,8 @@ inline Result mstore(StackTop stack, int64_t gas_left, ExecutionState& state) no const auto& index = stack.pop(); const auto& value = stack.pop(); - state.m_handler->set_witness(2, 0, 0, value); - state.m_handler->set_witness(2, 0, 1, index); + state.m_handler->set_witness(static_cast(state.msg->depth), 2, 0, value); + state.m_handler->set_witness(static_cast(state.msg->depth), 2, 1, index); if (!check_memory(gas_left, state.memory, index, 32)) return {EVMC_OUT_OF_GAS, gas_left}; @@ -805,7 +805,7 @@ inline void tload(StackTop stack, ExecutionState& state) noexcept const auto key = intx::be::store(x); const auto value = state.host.get_transient_storage(state.msg->recipient, key); x = intx::be::load(value); - state.m_handler->set_witness(3, 1, 2, x); + state.m_handler->set_witness(static_cast(state.msg->depth), 4, 2, x); } inline Result tstore(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept @@ -813,8 +813,8 @@ inline Result tstore(StackTop stack, int64_t gas_left, ExecutionState& state) no if (state.in_static_mode()) return {EVMC_STATIC_MODE_VIOLATION, 0}; - state.m_handler->set_witness(3, 1, 0, stack[1]); - state.m_handler->set_witness(3, 1, 1, stack[0]); + state.m_handler->set_witness(static_cast(state.msg->depth), 4, 0, stack[1]); + state.m_handler->set_witness(static_cast(state.msg->depth), 4, 1, stack[0]); const auto key = intx::be::store(stack.pop()); const auto value = intx::be::store(stack.pop()); state.host.set_transient_storage(state.msg->recipient, key, value); @@ -1003,7 +1003,7 @@ inline Result mcopy(StackTop stack, int64_t gas_left, ExecutionState& state) noe inline void dataload(StackTop stack, ExecutionState& state) noexcept { auto& index = stack.top(); - state.m_handler->set_witness(1, 0, 1, index); + state.m_handler->set_witness(static_cast(state.msg->depth), 1, 2, index); if (state.data.size() < index) index = 0; diff --git a/lib/evmone/instructions_storage.cpp b/lib/evmone/instructions_storage.cpp index 5c1bbd9..75ec6e2 100644 --- a/lib/evmone/instructions_storage.cpp +++ b/lib/evmone/instructions_storage.cpp @@ -109,7 +109,7 @@ Result sload(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept } x = intx::be::load(state.host.get_storage(state.msg->recipient, key)); - state.m_handler->set_witness(3, 0, 2, x); + state.m_handler->set_witness(static_cast(state.msg->depth), 3, 2, x); return {EVMC_SUCCESS, gas_left}; } @@ -122,8 +122,8 @@ Result sstore(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept if (state.rev >= EVMC_ISTANBUL && gas_left <= 2300) return {EVMC_OUT_OF_GAS, gas_left}; - state.m_handler->set_witness(3, 0, 0, stack[1]); - state.m_handler->set_witness(3, 0, 1, stack[0]); + state.m_handler->set_witness(static_cast(state.msg->depth), 3, 0, stack[1]); + state.m_handler->set_witness(static_cast(state.msg->depth), 3, 1, stack[0]); const auto key = intx::be::store(stack.pop()); const auto value = intx::be::store(stack.pop()); From c515f832295f1239c43bf364d9ac3f2cf53fa9c9 Mon Sep 17 00:00:00 2001 From: Mikhail Aksenov Date: Thu, 18 Apr 2024 19:19:02 +0300 Subject: [PATCH 2/2] Move host implementation to assigner library --- flake.nix | 1 + lib/assigner/CMakeLists.txt | 6 +++--- .../{test/test_host.h => include/vm_host.h} | 18 ++++++++-------- .../{test/test_host.cpp => src/vm_host.cpp} | 21 ++++++++++++------- lib/assigner/test/CMakeLists.txt | 3 +-- lib/assigner/test/assigner_test.cpp | 6 +++--- 6 files changed, 30 insertions(+), 25 deletions(-) rename lib/assigner/{test/test_host.h => include/vm_host.h} (91%) rename lib/assigner/{test/test_host.cpp => src/vm_host.cpp} (81%) diff --git a/flake.nix b/flake.nix index 3099496..f0f13b7 100644 --- a/flake.nix +++ b/flake.nix @@ -136,6 +136,7 @@ clang_17 ethash deps.intx + deps.evmc crypto3 blueprint ]; diff --git a/lib/assigner/CMakeLists.txt b/lib/assigner/CMakeLists.txt index d06f6b2..fbc47a1 100644 --- a/lib/assigner/CMakeLists.txt +++ b/lib/assigner/CMakeLists.txt @@ -5,9 +5,9 @@ cmake_policy(SET CMP0063 NEW) option(BUILD_ASSIGNER_TESTS "Build unit tests" FALSE) -add_library(${PROJECT_NAME} INTERFACE) +add_library(${PROJECT_NAME} STATIC src/vm_host.cpp) -target_include_directories(${PROJECT_NAME} INTERFACE +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${include_dir}/evmone ${CMAKE_CURRENT_SOURCE_DIR}/../evmone @@ -16,7 +16,7 @@ target_include_directories(${PROJECT_NAME} INTERFACE # TODO: link to blueprint and crypto3 here after fixing this in crypto3: # https://github.com/NilFoundation/crypto3/issues/175 -target_link_libraries(${PROJECT_NAME} INTERFACE +target_link_libraries(${PROJECT_NAME} PUBLIC evmone) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/nil/blueprint/ diff --git a/lib/assigner/test/test_host.h b/lib/assigner/include/vm_host.h similarity index 91% rename from lib/assigner/test/test_host.h rename to lib/assigner/include/vm_host.h index 6b61bfb..7ea341b 100644 --- a/lib/assigner/test/test_host.h +++ b/lib/assigner/include/vm_host.h @@ -1,5 +1,5 @@ -#ifndef EVM1_ASSIGNER_LIB_ASSIGNER_TEST_TEST_HOST_H_ -#define EVM1_ASSIGNER_LIB_ASSIGNER_TEST_TEST_HOST_H_ +#ifndef EVM_ASSIGNER_LIB_ASSIGNER_INCLUDE_VM_HOST_H_ +#define EVM_ASSIGNER_LIB_ASSIGNER_INCLUDE_VM_HOST_H_ // Based on example host @@ -40,19 +40,19 @@ using accounts = std::map; using BlueprintFieldType = typename nil::crypto3::algebra::curves::pallas::base_field_type; using AssignerType = nil::blueprint::assigner; -class TestHost : public evmc::Host +class VMHost : public evmc::Host { evmc::accounts accounts; evmc_tx_context tx_context{}; AssignerType *assigner; public: - TestHost() = default; - explicit TestHost(evmc_tx_context& _tx_context, AssignerType* _assigner) noexcept + VMHost() = default; + explicit VMHost(evmc_tx_context& _tx_context, AssignerType* _assigner) noexcept : tx_context{_tx_context}, assigner(_assigner) {} - TestHost(evmc_tx_context& _tx_context, AssignerType* _assigner, evmc::accounts& _accounts) noexcept + VMHost(evmc_tx_context& _tx_context, AssignerType* _assigner, evmc::accounts& _accounts) noexcept : accounts{_accounts}, tx_context{_tx_context}, assigner(_assigner) {} @@ -222,8 +222,8 @@ class TestHost : public evmc::Host extern "C" { -evmc_host_context* test_host_create_context(evmc_tx_context tx_context, AssignerType *assigner); -void test_host_destroy_context(evmc_host_context* context); +evmc_host_context* vm_host_create_context(evmc_tx_context tx_context, AssignerType *assigner); +void vm_host_destroy_context(evmc_host_context* context); } -#endif // EVM1_ASSIGNER_LIB_ASSIGNER_TEST_TEST_HOST_H_ +#endif // EVM_ASSIGNER_LIB_ASSIGNER_INCLUDE_VM_HOST_H_ diff --git a/lib/assigner/test/test_host.cpp b/lib/assigner/src/vm_host.cpp similarity index 81% rename from lib/assigner/test/test_host.cpp rename to lib/assigner/src/vm_host.cpp index b20863f..2489fa1 100644 --- a/lib/assigner/test/test_host.cpp +++ b/lib/assigner/src/vm_host.cpp @@ -1,23 +1,23 @@ -#include "test_host.h" +#include "vm_host.h" #include #include extern "C" { -evmc_host_context* test_host_create_context(evmc_tx_context tx_context, AssignerType *assigner) +evmc_host_context* vm_host_create_context(evmc_tx_context tx_context, AssignerType *assigner) { - auto host = new TestHost{tx_context, assigner}; + auto host = new VMHost{tx_context, assigner}; return host->to_context(); } -void test_host_destroy_context(evmc_host_context* context) +void vm_host_destroy_context(evmc_host_context* context) { - delete evmc::Host::from_context(context); + delete evmc::Host::from_context(context); } } -evmc::Result TestHost::handle_call(const evmc_message& msg) +evmc::Result VMHost::handle_call(const evmc_message& msg) { evmc_vm * vm = evmc_create_evmone(); auto account_iter = accounts.find(msg.code_address); @@ -46,9 +46,14 @@ evmc::Result TestHost::handle_call(const evmc_message& msg) return res; } -evmc::Result TestHost::handle_create(const evmc_message& msg) +evmc::Result VMHost::handle_create(const evmc_message& msg) { evmc::address new_contract_address = calculate_address(msg); + if (accounts.find(new_contract_address) != accounts.end()) + { + // Address collision + return evmc::Result{EVMC_FAILURE}; + } accounts[new_contract_address] = {}; if (msg.input_size == 0) { @@ -72,7 +77,7 @@ evmc::Result TestHost::handle_create(const evmc_message& msg) return res; } -evmc::address TestHost::calculate_address(const evmc_message& msg) +evmc::address VMHost::calculate_address(const evmc_message& msg) { // TODO: Implement for CREATE opcode, for now the result is only correct for CREATE2 // CREATE requires rlp encoding diff --git a/lib/assigner/test/CMakeLists.txt b/lib/assigner/test/CMakeLists.txt index f8a4307..1f4fe71 100644 --- a/lib/assigner/test/CMakeLists.txt +++ b/lib/assigner/test/CMakeLists.txt @@ -5,8 +5,7 @@ include(GoogleTest) find_package(GTest CONFIG REQUIRED) add_executable(assigner_tests - assigner_test.cpp - test_host.cpp) + assigner_test.cpp) target_link_libraries( assigner_tests diff --git a/lib/assigner/test/assigner_test.cpp b/lib/assigner/test/assigner_test.cpp index b84a996..60d75b3 100644 --- a/lib/assigner/test/assigner_test.cpp +++ b/lib/assigner/test/assigner_test.cpp @@ -6,7 +6,7 @@ #include #include #include "instructions_opcodes.hpp" -#include "test_host.h" +#include "vm_host.h" #include @@ -59,13 +59,13 @@ class AssignerTest : public testing::Test host_interface = &evmc::Host::get_interface(); - ctx = test_host_create_context(tx_context, assigner_ptr.get()); + ctx = vm_host_create_context(tx_context, assigner_ptr.get()); } static void TearDownTestSuite() { assigner_ptr.reset(); - test_host_destroy_context(ctx); + vm_host_destroy_context(ctx); } static std::unique_ptr> assigner_ptr;