mirror of
https://github.com/status-im/evmc.git
synced 2025-02-24 00:48:09 +00:00
examples: Add "Precompiles VM" example
This commit is contained in:
parent
018ff5b2f0
commit
2e9bd6ffc5
@ -10,6 +10,8 @@ if(NOT CMAKE_CXX_STANDARD)
|
|||||||
endif()
|
endif()
|
||||||
set(CMAKE_DEBUG_POSTFIX "")
|
set(CMAKE_DEBUG_POSTFIX "")
|
||||||
|
|
||||||
|
add_subdirectory(example_precompiles_vm)
|
||||||
|
|
||||||
|
|
||||||
add_library(evmc-example-host STATIC example_host.cpp)
|
add_library(evmc-example-host STATIC example_host.cpp)
|
||||||
target_link_libraries(evmc-example-host PRIVATE evmc)
|
target_link_libraries(evmc-example-host PRIVATE evmc)
|
||||||
|
8
examples/example_precompiles_vm/CMakeLists.txt
Normal file
8
examples/example_precompiles_vm/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# EVMC: Ethereum Client-VM Connector API.
|
||||||
|
# Copyright 2019 The EVMC Authors.
|
||||||
|
# Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
|
add_library(evmc-example-precompiles-vm SHARED example_precompiles_vm.cpp)
|
||||||
|
target_link_libraries(evmc-example-precompiles-vm PRIVATE evmc)
|
||||||
|
set_source_files_properties(example_precompiles_vm.cpp PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS PROJECT_VERSION="${PROJECT_VERSION}")
|
127
examples/example_precompiles_vm/example_precompiles_vm.cpp
Normal file
127
examples/example_precompiles_vm/example_precompiles_vm.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/* EVMC: Ethereum Client-VM Connector API.
|
||||||
|
* Copyright 2019 The EVMC Authors.
|
||||||
|
* Licensed under the Apache License, Version 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <evmc/evmc.h>
|
||||||
|
#include <evmc/utils.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
static evmc_result execute_identity(const evmc_message* msg)
|
||||||
|
{
|
||||||
|
auto result = evmc_result{};
|
||||||
|
|
||||||
|
// Check the gas cost.
|
||||||
|
auto gas_cost = 15 + 3 * ((int64_t(msg->input_size) + 31) / 32);
|
||||||
|
auto gas_left = msg->gas - gas_cost;
|
||||||
|
if (gas_left < 0)
|
||||||
|
{
|
||||||
|
result.status_code = EVMC_OUT_OF_GAS;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute.
|
||||||
|
auto data = new uint8_t[msg->input_size];
|
||||||
|
std::copy_n(msg->input_data, msg->input_size, data);
|
||||||
|
|
||||||
|
// Return the result.
|
||||||
|
result.status_code = EVMC_SUCCESS;
|
||||||
|
result.output_data = data;
|
||||||
|
result.output_size = msg->input_size;
|
||||||
|
result.release = [](const evmc_result* result) { delete[] result->output_data; };
|
||||||
|
result.gas_left = gas_left;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evmc_result execute_empty(const evmc_message* msg)
|
||||||
|
{
|
||||||
|
auto result = evmc_result{};
|
||||||
|
result.status_code = EVMC_SUCCESS;
|
||||||
|
result.gas_left = msg->gas;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evmc_result not_implemented()
|
||||||
|
{
|
||||||
|
auto result = evmc_result{};
|
||||||
|
result.status_code = EVMC_INTERNAL_ERROR;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evmc_result execute(evmc_instance*,
|
||||||
|
evmc_context*,
|
||||||
|
enum evmc_revision rev,
|
||||||
|
const evmc_message* msg,
|
||||||
|
const uint8_t*,
|
||||||
|
size_t)
|
||||||
|
{
|
||||||
|
// The EIP-1352 (https://eips.ethereum.org/EIPS/eip-1352) defines
|
||||||
|
// the range 0 - 0xffff (2 bytes) of addresses reserved for precompiled contracts.
|
||||||
|
// Check if the destination address is within the reserved range.
|
||||||
|
|
||||||
|
constexpr auto prefix_size = sizeof(evmc_address) - 2;
|
||||||
|
const auto& dst = msg->destination;
|
||||||
|
// Check if the address prefix is all zeros.
|
||||||
|
if (std::all_of(&dst.bytes[0], &dst.bytes[prefix_size], [](uint8_t x) { return x == 0; }))
|
||||||
|
{
|
||||||
|
// If not, reject the execution request.
|
||||||
|
auto result = evmc_result{};
|
||||||
|
result.status_code = EVMC_REJECTED;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the precompiled contract id from last 2 bytes of the destination address.
|
||||||
|
const auto id = (dst.bytes[prefix_size] << 8) | dst.bytes[prefix_size + 1];
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case 0x0001: // ECDSARECOVER
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0002: // SHA256
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0003: // RIPEMD160
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0004: // Identity
|
||||||
|
return execute_identity(msg);
|
||||||
|
|
||||||
|
case 0x0005: // EXPMOD
|
||||||
|
if (rev < EVMC_BYZANTIUM)
|
||||||
|
return execute_empty(msg);
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0006: // SNARKV
|
||||||
|
if (rev < EVMC_BYZANTIUM)
|
||||||
|
return execute_empty(msg);
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0007: // BNADD
|
||||||
|
if (rev < EVMC_BYZANTIUM)
|
||||||
|
return execute_empty(msg);
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
case 0x0008: // BNMUL
|
||||||
|
if (rev < EVMC_BYZANTIUM)
|
||||||
|
return execute_empty(msg);
|
||||||
|
return not_implemented();
|
||||||
|
|
||||||
|
default: // As if empty code was executed.
|
||||||
|
return execute_empty(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" EVMC_EXPORT evmc_instance* evmc_create_example_precompiles_vm()
|
||||||
|
{
|
||||||
|
static struct evmc_instance instance = {
|
||||||
|
EVMC_ABI_VERSION,
|
||||||
|
"example_precompiles_vm",
|
||||||
|
PROJECT_VERSION,
|
||||||
|
[](evmc_instance*) {},
|
||||||
|
execute,
|
||||||
|
[](evmc_instance*) { return evmc_capabilities_flagset{EVMC_CAPABILITY_PRECOMPILES}; },
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
};
|
||||||
|
return &instance;
|
||||||
|
}
|
@ -13,6 +13,7 @@ set_source_files_properties(vmtester.cpp PROPERTIES COMPILE_DEFINITIONS PROJECT_
|
|||||||
install(TARGETS evmc-vmtester RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS evmc-vmtester RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
add_test(NAME vmtester/examplevm COMMAND evmc-vmtester $<TARGET_FILE:evmc-example-vm>)
|
add_test(NAME vmtester/examplevm COMMAND evmc-vmtester $<TARGET_FILE:evmc-example-vm>)
|
||||||
|
add_test(NAME vmtester/example_precompiles_vm COMMAND evmc-vmtester $<TARGET_FILE:evmc-example-precompiles-vm>)
|
||||||
|
|
||||||
add_test(NAME vmtester/help COMMAND evmc-vmtester --version --help)
|
add_test(NAME vmtester/help COMMAND evmc-vmtester --version --help)
|
||||||
set_tests_properties(vmtester/help PROPERTIES PASS_REGULAR_EXPRESSION "Usage:")
|
set_tests_properties(vmtester/help PROPERTIES PASS_REGULAR_EXPRESSION "Usage:")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user