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

Commit 5f86929

Browse files
committed
examples: Add "Precompiles VM" example
1 parent 4f54f3d commit 5f86929

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

examples/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ if(NOT CMAKE_CXX_STANDARD)
1010
endif()
1111
set(CMAKE_DEBUG_POSTFIX "")
1212

13+
add_subdirectory(example_precompiles_vm)
14+
1315

1416
add_library(evmc-example-host STATIC example_host.cpp)
1517
target_link_libraries(evmc-example-host PRIVATE evmc)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# EVMC: Ethereum Client-VM Connector API.
2+
# Copyright 2019 The EVMC Authors.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
add_library(evmc-example-precompiles-vm SHARED example_precompiles_vm.cpp)
6+
target_link_libraries(evmc-example-precompiles-vm PRIVATE evmc)
7+
set_source_files_properties(example_precompiles_vm.cpp PROPERTIES
8+
COMPILE_DEFINITIONS PROJECT_VERSION="${PROJECT_VERSION}")
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/* EVMC: Ethereum Client-VM Connector API.
2+
* Copyright 2019 The EVMC Authors.
3+
* Licensed under the Apache License, Version 2.0.
4+
*/
5+
6+
#include <evmc/evmc.h>
7+
#include <evmc/utils.h>
8+
#include <algorithm>
9+
10+
static evmc_result execute_identity(const evmc_message* msg)
11+
{
12+
auto result = evmc_result{};
13+
auto data = new uint8_t[msg->input_size];
14+
std::copy_n(msg->input_data, msg->input_size, data);
15+
result.status_code = EVMC_SUCCESS;
16+
result.output_data = data;
17+
result.output_size = msg->input_size;
18+
result.release = [](const evmc_result* result) { delete[] result->output_data; };
19+
return result;
20+
}
21+
22+
static evmc_result execute_empty(const evmc_message* msg)
23+
{
24+
auto result = evmc_result{};
25+
result.status_code = EVMC_SUCCESS;
26+
result.gas_left = msg->gas;
27+
return result;
28+
}
29+
30+
static evmc_result not_implemented()
31+
{
32+
auto result = evmc_result{};
33+
result.status_code = EVMC_INTERNAL_ERROR;
34+
return result;
35+
}
36+
37+
static evmc_result execute(evmc_instance*,
38+
evmc_context*,
39+
enum evmc_revision rev,
40+
const evmc_message* msg,
41+
const uint8_t*,
42+
size_t)
43+
{
44+
// The EIP-1352 (https://eips.ethereum.org/EIPS/eip-1352) defines
45+
// the range 0 - 0xffff (2 bytes) of addresses reserved for precompiled contracts.
46+
// Check if the destination address is within the reserved range.
47+
48+
constexpr auto prefix_size = sizeof(evmc_address) - 2;
49+
const auto& dst = msg->destination;
50+
// Check if the address prefix is all zeros.
51+
if (std::all_of(&dst.bytes[0], &dst.bytes[prefix_size], [](uint8_t x) { return x == 0; }))
52+
{
53+
// If not, reject the execution request.
54+
auto result = evmc_result{};
55+
result.status_code = EVMC_REJECTED;
56+
return result;
57+
}
58+
59+
// Extract the precompiled contract id from last 2 bytes of the destination address.
60+
const auto id = (dst.bytes[prefix_size] << 8) | dst.bytes[prefix_size + 1];
61+
switch (id)
62+
{
63+
case 0x0001: // ECDSARECOVER
64+
return not_implemented();
65+
66+
case 0x0002: // SHA256
67+
return not_implemented();
68+
69+
case 0x0003: // RIPEMD160
70+
return not_implemented();
71+
72+
case 0x0004: // Identity
73+
return execute_identity(msg);
74+
75+
case 0x0005: // EXPMOD
76+
if (rev < EVMC_BYZANTIUM)
77+
return execute_empty(msg);
78+
return not_implemented();
79+
80+
case 0x0006: // SNARKV
81+
if (rev < EVMC_BYZANTIUM)
82+
return execute_empty(msg);
83+
return not_implemented();
84+
85+
case 0x0007: // BNADD
86+
if (rev < EVMC_BYZANTIUM)
87+
return execute_empty(msg);
88+
return not_implemented();
89+
90+
case 0x0008: // BNMUL
91+
if (rev < EVMC_BYZANTIUM)
92+
return execute_empty(msg);
93+
return not_implemented();
94+
95+
default: // As if empty code was executed.
96+
return execute_empty(msg);
97+
}
98+
}
99+
100+
extern "C" EVMC_EXPORT evmc_instance* evmc_create_example_precompiles_vm()
101+
{
102+
static struct evmc_instance instance = {
103+
EVMC_ABI_VERSION,
104+
"example_precompiles_vm",
105+
PROJECT_VERSION,
106+
[](evmc_instance*) {},
107+
execute,
108+
[](evmc_instance*) { return evmc_capabilities_flagset{EVMC_CAPABILITY_PRECOMPILES}; },
109+
nullptr,
110+
nullptr,
111+
};
112+
return &instance;
113+
}

test/vmtester/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set_source_files_properties(vmtester.cpp PROPERTIES COMPILE_DEFINITIONS PROJECT_
1313
install(TARGETS evmc-vmtester RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
1414
1515
add_test(NAME vmtester/examplevm COMMAND evmc-vmtester $<TARGET_FILE:evmc-example-vm>)
16+
add_test(NAME vmtester/example_precompiles_vm COMMAND evmc-vmtester $<TARGET_FILE:evmc-example-precompiles-vm>)
1617
1718
add_test(NAME vmtester/help COMMAND evmc-vmtester --version --help)
1819
set_tests_properties(vmtester/help PROPERTIES PASS_REGULAR_EXPRESSION "Usage:")

0 commit comments

Comments
 (0)