From 6985aa640f28b8124443c81479ea398816cb10c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Feb 2021 18:37:11 +0100 Subject: [PATCH 1/2] test: Rework CMake test definitions --- test/tools/CMakeLists.txt | 43 ++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index a2fa8da70..f717a4545 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -2,41 +2,34 @@ # Copyright 2019-2020 The EVMC Authors. # Licensed under the Apache License, Version 2.0. -set(PREFIX ${PROJECT_NAME}/evmc-tool) +function(add_evmc_tool_test NAME ARGUMENTS EXPECTED_OUTPUT) + separate_arguments(ARGUMENTS) + add_test(NAME ${PROJECT_NAME}/evmc-tool/${NAME} COMMAND evmc::tool ${ARGUMENTS}) + set_tests_properties(${PROJECT_NAME}/evmc-tool/${NAME} PROPERTIES PASS_REGULAR_EXPRESSION ${EXPECTED_OUTPUT}) +endfunction() -add_test( - NAME ${PREFIX}/example1 - COMMAND evmc::tool --vm $ run 30600052596000f3 --gas 99 -) -set_tests_properties( - ${PREFIX}/example1 PROPERTIES PASS_REGULAR_EXPRESSION + +add_evmc_tool_test( + example1 + "--vm $ run 30600052596000f3 --gas 99" "Result: +success[\r\n]+Gas used: +6[\r\n]+Output: +0000000000000000000000000000000000000000000000000000000000000000[\r\n]" ) -add_test( - NAME ${PREFIX}/version - COMMAND evmc::tool --version -) -set_tests_properties( - ${PREFIX}/version PROPERTIES PASS_REGULAR_EXPRESSION +add_evmc_tool_test( + version + "--version" "EVMC ${PROJECT_VERSION} \\($\\)" ) -add_test( - NAME ${PREFIX}/version_vm - COMMAND evmc::tool --vm $ --version -) -set_tests_properties( - ${PREFIX}/version_vm PROPERTIES PASS_REGULAR_EXPRESSION +add_evmc_tool_test( + version_vm + "--vm $ --version" "example_vm ${PROJECT_VERSION} \\($\\)[\r\n]EVMC ${PROJECT_VERSION} \\($\\)" ) -add_test( - NAME ${PREFIX}/copy_input - COMMAND evmc::tool --vm $ run 600035600052596000f3 --input aabbccdd -) -set_tests_properties( - ${PREFIX}/copy_input PROPERTIES PASS_REGULAR_EXPRESSION +add_evmc_tool_test( + copy_input + "--vm $ run 600035600052596000f3 --input aabbccdd" "Result: +success[\r\n]+Gas used: +7[\r\n]+Output: +aabbccdd00000000000000000000000000000000000000000000000000000000[\r\n]" ) From 6330289b44f90de274e788c2bb25a8e249d7967e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 8 Mar 2021 13:24:06 +0100 Subject: [PATCH 2/2] tools: Add --create option to `evmc run` --- test/tools/CMakeLists.txt | 6 +++ test/unittests/tool_commands_test.cpp | 59 +++++++++++++++++++++++---- tools/commands/commands.hpp | 1 + tools/commands/run.cpp | 50 +++++++++++++++++++++-- tools/evmc/main.cpp | 6 ++- 5 files changed, 111 insertions(+), 11 deletions(-) diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index f717a4545..6c0423305 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -33,5 +33,11 @@ add_evmc_tool_test( "Result: +success[\r\n]+Gas used: +7[\r\n]+Output: +aabbccdd00000000000000000000000000000000000000000000000000000000[\r\n]" ) +add_evmc_tool_test( + create_return_2 + "--vm $ run --create 6960026000526001601ff3600052600a6016f3" + "Result: +success[\r\n]+Gas used: +6[\r\n]+Output: +02[\r\n]" +) + get_property(TOOLS_TESTS DIRECTORY PROPERTY TESTS) set_tests_properties(${TOOLS_TESTS} PROPERTIES ENVIRONMENT LLVM_PROFILE_FILE=${CMAKE_BINARY_DIR}/tools-%p.profraw) diff --git a/test/unittests/tool_commands_test.cpp b/test/unittests/tool_commands_test.cpp index 8b97b07a2..cd09903b7 100644 --- a/test/unittests/tool_commands_test.cpp +++ b/test/unittests/tool_commands_test.cpp @@ -15,12 +15,14 @@ std::string out_pattern(const char* rev, int gas_limit, const char* status, int gas_used, - const char* output = nullptr) + const char* output = nullptr, + bool create = false) { std::ostringstream s; - s << "Executing on " << rev << " with " << gas_limit << " gas limit\n\n" + s << (create ? "Creating and executing on " : "Executing on ") << rev << " with " << gas_limit + << " gas limit\n\n" << "Result: " << status << "\nGas used: " << gas_used << "\n"; - if (output) + if (output != nullptr) s << "Output: " << output << "\n"; return s.str(); } @@ -31,7 +33,7 @@ TEST(tool_commands, run_empty_code) auto vm = evmc::VM{evmc_create_example_vm()}; std::ostringstream out; - const auto exit_code = cmd::run(vm, EVMC_FRONTIER, 1, "", "", out); + const auto exit_code = cmd::run(vm, EVMC_FRONTIER, 1, "", "", false, out); EXPECT_EQ(exit_code, 0); EXPECT_EQ(out.str(), out_pattern("Frontier", 1, "success", 0, "")); } @@ -41,7 +43,7 @@ TEST(tool_commands, run_oog) auto vm = evmc::VM{evmc_create_example_vm()}; std::ostringstream out; - const auto exit_code = cmd::run(vm, EVMC_BERLIN, 2, "0x6002600201", "", out); + const auto exit_code = cmd::run(vm, EVMC_BERLIN, 2, "0x6002600201", "", false, out); EXPECT_EQ(exit_code, 0); EXPECT_EQ(out.str(), out_pattern("Berlin", 2, "out of gas", 2)); } @@ -51,7 +53,7 @@ TEST(tool_commands, run_return_my_address) auto vm = evmc::VM{evmc_create_example_vm()}; std::ostringstream out; - const auto exit_code = cmd::run(vm, EVMC_HOMESTEAD, 200, "30600052596000f3", "", out); + const auto exit_code = cmd::run(vm, EVMC_HOMESTEAD, 200, "30600052596000f3", "", false, out); EXPECT_EQ(exit_code, 0); EXPECT_EQ(out.str(), out_pattern("Homestead", 200, "success", 6, @@ -66,9 +68,52 @@ TEST(tool_commands, run_copy_input_to_output) const auto exit_code = cmd::run(vm, EVMC_TANGERINE_WHISTLE, 200, "600035600052596000f3", - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", out); + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", false, out); EXPECT_EQ(exit_code, 0); EXPECT_EQ(out.str(), out_pattern("Tangerine Whistle", 200, "success", 7, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")); } + +TEST(tool_commands, create_return_1) +{ + // Contract: mstore(0, 1) return(31, 1) + // Create: mstore(0, 0x60016000526001601ff3) return(22, 10) + auto vm = evmc::VM{evmc_create_example_vm()}; + std::ostringstream out; + + const auto exit_code = cmd::run(vm, EVMC_SPURIOUS_DRAGON, 200, + "6960016000526001601ff3600052600a6016f3", "", true, out); + EXPECT_EQ(exit_code, 0); + EXPECT_EQ(out.str(), out_pattern("Spurious Dragon", 200, "success", 6, "01", true)); +} + +TEST(tool_commands, create_copy_input_to_output) +{ + // Contract: mstore(0, calldataload(0)) return(0, msize()) + // Create: mstore(0, 0x600035600052596000f3) return(22, 10) + auto vm = evmc::VM{evmc_create_example_vm()}; + std::ostringstream out; + + const auto exit_code = cmd::run(vm, EVMC_SPURIOUS_DRAGON, 200, + "69600035600052596000f3600052600a6016f3", "0c49c4", true, out); + EXPECT_EQ(exit_code, 0); + EXPECT_EQ( + out.str(), + out_pattern("Spurious Dragon", 200, "success", 7, + "0c49c40000000000000000000000000000000000000000000000000000000000", true)); +} + +TEST(tool_commands, create_failure_stack_underflow) +{ + // Contract: n/a + // Create: abort() + auto vm = evmc::VM{evmc_create_example_vm()}; + std::ostringstream out; + + const auto exit_code = cmd::run(vm, EVMC_PETERSBURG, 0, "fe", "", true, out); + EXPECT_EQ(exit_code, EVMC_UNDEFINED_INSTRUCTION); + EXPECT_EQ(out.str(), + "Creating and executing on Petersburg with 0 gas limit\n" + "Contract creation failed: undefined instruction\n"); +} diff --git a/tools/commands/commands.hpp b/tools/commands/commands.hpp index 616d644d0..bd2c7a33e 100644 --- a/tools/commands/commands.hpp +++ b/tools/commands/commands.hpp @@ -15,6 +15,7 @@ int run(evmc::VM& vm, int64_t gas, const std::string& code_hex, const std::string& input_hex, + bool create, std::ostream& out); } } // namespace evmc diff --git a/tools/commands/run.cpp b/tools/commands/run.cpp index 58fb7ac13..563eb4d89 100644 --- a/tools/commands/run.cpp +++ b/tools/commands/run.cpp @@ -12,24 +12,68 @@ namespace evmc { namespace cmd { +namespace +{ +/// The address where a new contract is created with --create option. +constexpr auto create_address = 0xc9ea7ed000000000000000000000000000000001_address; + +/// The gas limit for contract creation. +constexpr auto create_gas = 10'000'000; +} // namespace + int run(evmc::VM& vm, evmc_revision rev, int64_t gas, const std::string& code_hex, const std::string& input_hex, + bool create, std::ostream& out) { - out << "Executing on " << rev << " with " << gas << " gas limit\n"; + out << (create ? "Creating and executing on " : "Executing on ") << rev << " with " << gas + << " gas limit\n"; const auto code = from_hex(code_hex); const auto input = from_hex(input_hex); + + MockedHost host; + evmc_message msg{}; msg.gas = gas; msg.input_data = input.data(); msg.input_size = input.size(); - MockedHost host; - const auto result = vm.execute(host, rev, msg, code.data(), code.size()); + const uint8_t* exec_code_data = nullptr; + size_t exec_code_size = 0; + + if (create) + { + evmc_message create_msg{}; + create_msg.kind = EVMC_CREATE; + create_msg.destination = create_address; + create_msg.gas = create_gas; + + const auto create_result = vm.execute(host, rev, create_msg, code.data(), code.size()); + if (create_result.status_code != EVMC_SUCCESS) + { + out << "Contract creation failed: " << create_result.status_code << "\n"; + return create_result.status_code; + } + + auto& created_account = host.accounts[create_address]; + created_account.code = bytes(create_result.output_data, create_result.output_size); + + msg.destination = create_address; + + exec_code_data = created_account.code.data(); + exec_code_size = created_account.code.size(); + } + else + { + exec_code_data = code.data(); + exec_code_size = code.size(); + } + + const auto result = vm.execute(host, rev, msg, exec_code_data, exec_code_size); const auto gas_used = msg.gas - result.gas_left; diff --git a/tools/evmc/main.cpp b/tools/evmc/main.cpp index f6e90e3d9..da0190c6b 100644 --- a/tools/evmc/main.cpp +++ b/tools/evmc/main.cpp @@ -15,6 +15,7 @@ int main(int argc, const char** argv) int64_t gas = 1000000; auto rev = EVMC_ISTANBUL; std::string input_hex; + auto create = false; CLI::App app{"EVMC tool"}; const auto& version_flag = *app.add_flag("--version", "Print version information and exit"); @@ -26,6 +27,9 @@ int main(int argc, const char** argv) run_cmd.add_option("--gas", gas, "Execution gas limit", true)->check(CLI::Range(0, 1000000000)); run_cmd.add_option("--rev", rev, "EVM revision", true); run_cmd.add_option("--input", input_hex, "Hex-encoded input bytes"); + run_cmd.add_flag( + "--create", create, + "Create new contract out of the code and then execute this contract with the input"); try { @@ -67,7 +71,7 @@ int main(int argc, const char** argv) throw CLI::RequiredError{vm_option.get_name()}; std::cout << "Config: " << vm_config << "\n"; - return cmd::run(vm, rev, gas, code_hex, input_hex, std::cout); + return cmd::run(vm, rev, gas, code_hex, input_hex, create, std::cout); } return 0;