Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --create option to evmc run #566

Merged
merged 2 commits into from
Mar 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 24 additions & 25 deletions test/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,42 @@
# 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 $<TARGET_FILE:evmc::example-vm> run 30600052596000f3 --gas 99
)
set_tests_properties(
${PREFIX}/example1 PROPERTIES PASS_REGULAR_EXPRESSION

add_evmc_tool_test(
example1
"--vm $<TARGET_FILE:evmc::example-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} \\($<TARGET_FILE:evmc::tool>\\)"
)

add_test(
NAME ${PREFIX}/version_vm
COMMAND evmc::tool --vm $<TARGET_FILE:evmc::example-vm> --version
)
set_tests_properties(
${PREFIX}/version_vm PROPERTIES PASS_REGULAR_EXPRESSION
add_evmc_tool_test(
version_vm
"--vm $<TARGET_FILE:evmc::example-vm> --version"
"example_vm ${PROJECT_VERSION} \\($<TARGET_FILE:evmc::example-vm>\\)[\r\n]EVMC ${PROJECT_VERSION} \\($<TARGET_FILE:evmc::tool>\\)"
)

add_test(
NAME ${PREFIX}/copy_input
COMMAND evmc::tool --vm $<TARGET_FILE:evmc::example-vm> run 600035600052596000f3 --input aabbccdd
)
set_tests_properties(
${PREFIX}/copy_input PROPERTIES PASS_REGULAR_EXPRESSION
add_evmc_tool_test(
copy_input
"--vm $<TARGET_FILE:evmc::example-vm> run 600035600052596000f3 --input aabbccdd"
"Result: +success[\r\n]+Gas used: +7[\r\n]+Output: +aabbccdd00000000000000000000000000000000000000000000000000000000[\r\n]"
)

add_evmc_tool_test(
create_return_2
axic marked this conversation as resolved.
Show resolved Hide resolved
"--vm $<TARGET_FILE:evmc::example-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)
59 changes: 52 additions & 7 deletions test/unittests/tool_commands_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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, ""));
}
Expand All @@ -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));
}
Expand All @@ -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,
Expand All @@ -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");
}
1 change: 1 addition & 0 deletions tools/commands/commands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 47 additions & 3 deletions tools/commands/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 5 additions & 1 deletion tools/evmc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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
{
Expand Down Expand Up @@ -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;
Expand Down