Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 6330289

Browse files
committed
tools: Add --create option to evmc run
1 parent 6985aa6 commit 6330289

File tree

5 files changed

+111
-11
lines changed

5 files changed

+111
-11
lines changed

test/tools/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,11 @@ add_evmc_tool_test(
3333
"Result: +success[\r\n]+Gas used: +7[\r\n]+Output: +aabbccdd00000000000000000000000000000000000000000000000000000000[\r\n]"
3434
)
3535

36+
add_evmc_tool_test(
37+
create_return_2
38+
"--vm $<TARGET_FILE:evmc::example-vm> run --create 6960026000526001601ff3600052600a6016f3"
39+
"Result: +success[\r\n]+Gas used: +6[\r\n]+Output: +02[\r\n]"
40+
)
41+
3642
get_property(TOOLS_TESTS DIRECTORY PROPERTY TESTS)
3743
set_tests_properties(${TOOLS_TESTS} PROPERTIES ENVIRONMENT LLVM_PROFILE_FILE=${CMAKE_BINARY_DIR}/tools-%p.profraw)

test/unittests/tool_commands_test.cpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ std::string out_pattern(const char* rev,
1515
int gas_limit,
1616
const char* status,
1717
int gas_used,
18-
const char* output = nullptr)
18+
const char* output = nullptr,
19+
bool create = false)
1920
{
2021
std::ostringstream s;
21-
s << "Executing on " << rev << " with " << gas_limit << " gas limit\n\n"
22+
s << (create ? "Creating and executing on " : "Executing on ") << rev << " with " << gas_limit
23+
<< " gas limit\n\n"
2224
<< "Result: " << status << "\nGas used: " << gas_used << "\n";
23-
if (output)
25+
if (output != nullptr)
2426
s << "Output: " << output << "\n";
2527
return s.str();
2628
}
@@ -31,7 +33,7 @@ TEST(tool_commands, run_empty_code)
3133
auto vm = evmc::VM{evmc_create_example_vm()};
3234
std::ostringstream out;
3335

34-
const auto exit_code = cmd::run(vm, EVMC_FRONTIER, 1, "", "", out);
36+
const auto exit_code = cmd::run(vm, EVMC_FRONTIER, 1, "", "", false, out);
3537
EXPECT_EQ(exit_code, 0);
3638
EXPECT_EQ(out.str(), out_pattern("Frontier", 1, "success", 0, ""));
3739
}
@@ -41,7 +43,7 @@ TEST(tool_commands, run_oog)
4143
auto vm = evmc::VM{evmc_create_example_vm()};
4244
std::ostringstream out;
4345

44-
const auto exit_code = cmd::run(vm, EVMC_BERLIN, 2, "0x6002600201", "", out);
46+
const auto exit_code = cmd::run(vm, EVMC_BERLIN, 2, "0x6002600201", "", false, out);
4547
EXPECT_EQ(exit_code, 0);
4648
EXPECT_EQ(out.str(), out_pattern("Berlin", 2, "out of gas", 2));
4749
}
@@ -51,7 +53,7 @@ TEST(tool_commands, run_return_my_address)
5153
auto vm = evmc::VM{evmc_create_example_vm()};
5254
std::ostringstream out;
5355

54-
const auto exit_code = cmd::run(vm, EVMC_HOMESTEAD, 200, "30600052596000f3", "", out);
56+
const auto exit_code = cmd::run(vm, EVMC_HOMESTEAD, 200, "30600052596000f3", "", false, out);
5557
EXPECT_EQ(exit_code, 0);
5658
EXPECT_EQ(out.str(),
5759
out_pattern("Homestead", 200, "success", 6,
@@ -66,9 +68,52 @@ TEST(tool_commands, run_copy_input_to_output)
6668

6769
const auto exit_code =
6870
cmd::run(vm, EVMC_TANGERINE_WHISTLE, 200, "600035600052596000f3",
69-
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", out);
71+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", false, out);
7072
EXPECT_EQ(exit_code, 0);
7173
EXPECT_EQ(out.str(),
7274
out_pattern("Tangerine Whistle", 200, "success", 7,
7375
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"));
7476
}
77+
78+
TEST(tool_commands, create_return_1)
79+
{
80+
// Contract: mstore(0, 1) return(31, 1)
81+
// Create: mstore(0, 0x60016000526001601ff3) return(22, 10)
82+
auto vm = evmc::VM{evmc_create_example_vm()};
83+
std::ostringstream out;
84+
85+
const auto exit_code = cmd::run(vm, EVMC_SPURIOUS_DRAGON, 200,
86+
"6960016000526001601ff3600052600a6016f3", "", true, out);
87+
EXPECT_EQ(exit_code, 0);
88+
EXPECT_EQ(out.str(), out_pattern("Spurious Dragon", 200, "success", 6, "01", true));
89+
}
90+
91+
TEST(tool_commands, create_copy_input_to_output)
92+
{
93+
// Contract: mstore(0, calldataload(0)) return(0, msize())
94+
// Create: mstore(0, 0x600035600052596000f3) return(22, 10)
95+
auto vm = evmc::VM{evmc_create_example_vm()};
96+
std::ostringstream out;
97+
98+
const auto exit_code = cmd::run(vm, EVMC_SPURIOUS_DRAGON, 200,
99+
"69600035600052596000f3600052600a6016f3", "0c49c4", true, out);
100+
EXPECT_EQ(exit_code, 0);
101+
EXPECT_EQ(
102+
out.str(),
103+
out_pattern("Spurious Dragon", 200, "success", 7,
104+
"0c49c40000000000000000000000000000000000000000000000000000000000", true));
105+
}
106+
107+
TEST(tool_commands, create_failure_stack_underflow)
108+
{
109+
// Contract: n/a
110+
// Create: abort()
111+
auto vm = evmc::VM{evmc_create_example_vm()};
112+
std::ostringstream out;
113+
114+
const auto exit_code = cmd::run(vm, EVMC_PETERSBURG, 0, "fe", "", true, out);
115+
EXPECT_EQ(exit_code, EVMC_UNDEFINED_INSTRUCTION);
116+
EXPECT_EQ(out.str(),
117+
"Creating and executing on Petersburg with 0 gas limit\n"
118+
"Contract creation failed: undefined instruction\n");
119+
}

tools/commands/commands.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ int run(evmc::VM& vm,
1515
int64_t gas,
1616
const std::string& code_hex,
1717
const std::string& input_hex,
18+
bool create,
1819
std::ostream& out);
1920
}
2021
} // namespace evmc

tools/commands/run.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,68 @@ namespace evmc
1212
{
1313
namespace cmd
1414
{
15+
namespace
16+
{
17+
/// The address where a new contract is created with --create option.
18+
constexpr auto create_address = 0xc9ea7ed000000000000000000000000000000001_address;
19+
20+
/// The gas limit for contract creation.
21+
constexpr auto create_gas = 10'000'000;
22+
} // namespace
23+
1524
int run(evmc::VM& vm,
1625
evmc_revision rev,
1726
int64_t gas,
1827
const std::string& code_hex,
1928
const std::string& input_hex,
29+
bool create,
2030
std::ostream& out)
2131
{
22-
out << "Executing on " << rev << " with " << gas << " gas limit\n";
32+
out << (create ? "Creating and executing on " : "Executing on ") << rev << " with " << gas
33+
<< " gas limit\n";
2334

2435
const auto code = from_hex(code_hex);
2536
const auto input = from_hex(input_hex);
37+
38+
MockedHost host;
39+
2640
evmc_message msg{};
2741
msg.gas = gas;
2842
msg.input_data = input.data();
2943
msg.input_size = input.size();
30-
MockedHost host;
3144

32-
const auto result = vm.execute(host, rev, msg, code.data(), code.size());
45+
const uint8_t* exec_code_data = nullptr;
46+
size_t exec_code_size = 0;
47+
48+
if (create)
49+
{
50+
evmc_message create_msg{};
51+
create_msg.kind = EVMC_CREATE;
52+
create_msg.destination = create_address;
53+
create_msg.gas = create_gas;
54+
55+
const auto create_result = vm.execute(host, rev, create_msg, code.data(), code.size());
56+
if (create_result.status_code != EVMC_SUCCESS)
57+
{
58+
out << "Contract creation failed: " << create_result.status_code << "\n";
59+
return create_result.status_code;
60+
}
61+
62+
auto& created_account = host.accounts[create_address];
63+
created_account.code = bytes(create_result.output_data, create_result.output_size);
64+
65+
msg.destination = create_address;
66+
67+
exec_code_data = created_account.code.data();
68+
exec_code_size = created_account.code.size();
69+
}
70+
else
71+
{
72+
exec_code_data = code.data();
73+
exec_code_size = code.size();
74+
}
75+
76+
const auto result = vm.execute(host, rev, msg, exec_code_data, exec_code_size);
3377

3478
const auto gas_used = msg.gas - result.gas_left;
3579

tools/evmc/main.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ int main(int argc, const char** argv)
1515
int64_t gas = 1000000;
1616
auto rev = EVMC_ISTANBUL;
1717
std::string input_hex;
18+
auto create = false;
1819

1920
CLI::App app{"EVMC tool"};
2021
const auto& version_flag = *app.add_flag("--version", "Print version information and exit");
@@ -26,6 +27,9 @@ int main(int argc, const char** argv)
2627
run_cmd.add_option("--gas", gas, "Execution gas limit", true)->check(CLI::Range(0, 1000000000));
2728
run_cmd.add_option("--rev", rev, "EVM revision", true);
2829
run_cmd.add_option("--input", input_hex, "Hex-encoded input bytes");
30+
run_cmd.add_flag(
31+
"--create", create,
32+
"Create new contract out of the code and then execute this contract with the input");
2933

3034
try
3135
{
@@ -67,7 +71,7 @@ int main(int argc, const char** argv)
6771
throw CLI::RequiredError{vm_option.get_name()};
6872

6973
std::cout << "Config: " << vm_config << "\n";
70-
return cmd::run(vm, rev, gas, code_hex, input_hex, std::cout);
74+
return cmd::run(vm, rev, gas, code_hex, input_hex, create, std::cout);
7175
}
7276

7377
return 0;

0 commit comments

Comments
 (0)