2018-08-30 15:38:14 +00:00
|
|
|
// EVMC: Ethereum Client-VM Connector API
|
2019-04-24 14:12:13 +00:00
|
|
|
// Copyright 2018-2019 The EVMC Authors.
|
2019-03-15 01:32:00 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0.
|
2018-04-10 22:37:03 +00:00
|
|
|
|
2018-08-30 16:16:15 +00:00
|
|
|
#include "../../examples/example_host.h"
|
2018-04-10 22:37:03 +00:00
|
|
|
#include "vmtester.hpp"
|
|
|
|
|
2019-07-22 13:18:52 +00:00
|
|
|
#include <evmc/evmc.hpp>
|
2018-08-13 16:42:20 +00:00
|
|
|
|
2018-08-27 14:33:16 +00:00
|
|
|
#include <array>
|
2018-04-17 09:11:07 +00:00
|
|
|
#include <cstring>
|
|
|
|
|
2019-04-24 10:43:24 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
// NOTE: this is to avoid compiler optimisations when reading the buffer
|
|
|
|
uint8_t read_uint8(const volatile uint8_t* p)
|
|
|
|
{
|
|
|
|
return *p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void read_buffer(const uint8_t* ptr, size_t size)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
read_uint8(&ptr[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2018-04-10 22:37:03 +00:00
|
|
|
TEST_F(evmc_vm_test, abi_version_match)
|
|
|
|
{
|
|
|
|
ASSERT_EQ(vm->abi_version, EVMC_ABI_VERSION);
|
|
|
|
}
|
|
|
|
|
2019-04-24 08:34:13 +00:00
|
|
|
TEST_F(evmc_vm_test, name)
|
|
|
|
{
|
2019-05-05 21:33:41 +00:00
|
|
|
ASSERT_TRUE(vm->name != nullptr);
|
2019-06-25 09:04:53 +00:00
|
|
|
EXPECT_NE(std::strlen(vm->name), size_t{0}) << "VM name cannot be empty";
|
2019-08-06 10:48:04 +00:00
|
|
|
|
|
|
|
EXPECT_STREQ(owned_vm.name(), vm->name);
|
2019-04-24 08:34:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(evmc_vm_test, version)
|
|
|
|
{
|
2019-05-05 21:33:41 +00:00
|
|
|
ASSERT_TRUE(vm->version != nullptr);
|
2019-06-25 09:04:53 +00:00
|
|
|
EXPECT_NE(std::strlen(vm->version), size_t{0}) << "VM version cannot be empty";
|
2019-08-06 10:48:04 +00:00
|
|
|
|
|
|
|
EXPECT_STREQ(owned_vm.version(), vm->version);
|
2019-04-24 08:34:13 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 13:48:10 +00:00
|
|
|
TEST_F(evmc_vm_test, capabilities)
|
|
|
|
{
|
|
|
|
// The VM should have at least one of EVM1 or EWASM capabilities.
|
|
|
|
EXPECT_TRUE(evmc_vm_has_capability(vm, EVMC_CAPABILITY_EVM1) ||
|
2019-05-08 11:48:27 +00:00
|
|
|
evmc_vm_has_capability(vm, EVMC_CAPABILITY_EWASM) ||
|
|
|
|
evmc_vm_has_capability(vm, EVMC_CAPABILITY_PRECOMPILES));
|
2019-05-08 13:48:10 +00:00
|
|
|
}
|
|
|
|
|
2019-04-24 10:33:55 +00:00
|
|
|
TEST_F(evmc_vm_test, execute_call)
|
2018-08-27 14:33:16 +00:00
|
|
|
{
|
2019-09-20 09:29:46 +00:00
|
|
|
evmc_host_context* context = example_host_create_context(evmc_tx_context{});
|
2018-08-27 14:33:16 +00:00
|
|
|
evmc_message msg{};
|
|
|
|
std::array<uint8_t, 2> code = {{0xfe, 0x00}};
|
|
|
|
|
|
|
|
evmc_result result =
|
2019-01-18 13:17:19 +00:00
|
|
|
vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
2018-08-27 14:33:16 +00:00
|
|
|
|
|
|
|
// Validate some constraints
|
|
|
|
if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT)
|
2018-08-29 20:56:55 +00:00
|
|
|
{
|
2018-08-27 14:33:16 +00:00
|
|
|
EXPECT_EQ(result.gas_left, 0);
|
2018-08-29 20:56:55 +00:00
|
|
|
}
|
2018-08-27 14:33:16 +00:00
|
|
|
|
2019-06-25 09:04:53 +00:00
|
|
|
if (result.output_data == nullptr)
|
2018-08-29 20:56:55 +00:00
|
|
|
{
|
2019-09-13 09:13:12 +00:00
|
|
|
EXPECT_EQ(result.output_size, size_t{0});
|
2018-08-29 20:56:55 +00:00
|
|
|
}
|
2019-04-24 09:58:12 +00:00
|
|
|
else
|
|
|
|
{
|
2019-06-25 09:04:53 +00:00
|
|
|
EXPECT_NE(result.output_size, size_t{0});
|
2019-04-24 10:43:24 +00:00
|
|
|
read_buffer(result.output_data, result.output_size);
|
2019-04-24 09:58:12 +00:00
|
|
|
}
|
2018-08-27 14:33:16 +00:00
|
|
|
|
2019-07-22 13:18:52 +00:00
|
|
|
EXPECT_TRUE(evmc::is_zero(result.create_address));
|
2019-05-08 20:33:15 +00:00
|
|
|
|
2018-08-27 14:33:16 +00:00
|
|
|
if (result.release)
|
|
|
|
result.release(&result);
|
2018-08-30 13:15:39 +00:00
|
|
|
|
|
|
|
example_host_destroy_context(context);
|
2018-08-27 14:33:16 +00:00
|
|
|
}
|
|
|
|
|
2019-04-24 10:33:55 +00:00
|
|
|
TEST_F(evmc_vm_test, execute_create)
|
|
|
|
{
|
2019-09-20 09:29:46 +00:00
|
|
|
evmc_host_context* context = example_host_create_context(evmc_tx_context{});
|
2019-04-24 10:33:55 +00:00
|
|
|
evmc_message msg{
|
2019-05-08 20:33:15 +00:00
|
|
|
EVMC_CREATE, 0, 0, 65536, evmc_address{}, evmc_address{}, nullptr, 0, evmc_uint256be{},
|
2019-04-24 10:33:55 +00:00
|
|
|
evmc_bytes32{}};
|
|
|
|
std::array<uint8_t, 2> code = {{0xfe, 0x00}};
|
|
|
|
|
|
|
|
evmc_result result =
|
|
|
|
vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size());
|
|
|
|
|
|
|
|
// Validate some constraints
|
|
|
|
if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(result.gas_left, 0);
|
|
|
|
}
|
|
|
|
|
2019-05-08 20:33:15 +00:00
|
|
|
if (result.output_data == nullptr)
|
2019-04-24 10:33:55 +00:00
|
|
|
{
|
2019-09-13 09:13:12 +00:00
|
|
|
EXPECT_EQ(result.output_size, size_t{0});
|
2019-04-24 10:33:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-25 09:04:53 +00:00
|
|
|
EXPECT_NE(result.output_size, size_t{0});
|
2019-04-24 10:33:55 +00:00
|
|
|
read_buffer(result.output_data, result.output_size);
|
|
|
|
}
|
|
|
|
|
2019-05-08 20:33:15 +00:00
|
|
|
// The VM will never provide the create address.
|
2019-07-22 13:18:52 +00:00
|
|
|
EXPECT_TRUE(evmc::is_zero(result.create_address));
|
2019-04-24 10:33:55 +00:00
|
|
|
|
|
|
|
if (result.release)
|
|
|
|
result.release(&result);
|
|
|
|
|
|
|
|
example_host_destroy_context(context);
|
|
|
|
}
|
|
|
|
|
2018-09-06 13:44:59 +00:00
|
|
|
TEST_F(evmc_vm_test, set_option_unknown_name)
|
2018-04-10 22:37:03 +00:00
|
|
|
{
|
|
|
|
if (vm->set_option)
|
|
|
|
{
|
2018-09-06 13:44:59 +00:00
|
|
|
evmc_set_option_result r = vm->set_option(vm, "unknown_option_csk9twq", "v");
|
2018-09-05 17:24:02 +00:00
|
|
|
EXPECT_EQ(r, EVMC_SET_OPTION_INVALID_NAME);
|
2018-04-10 22:37:03 +00:00
|
|
|
r = vm->set_option(vm, "unknown_option_csk9twq", "x");
|
2018-09-05 17:24:02 +00:00
|
|
|
EXPECT_EQ(r, EVMC_SET_OPTION_INVALID_NAME);
|
2018-04-10 22:37:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(evmc_vm_test, set_option_empty_value)
|
|
|
|
{
|
|
|
|
if (vm->set_option)
|
|
|
|
{
|
2018-09-06 13:44:59 +00:00
|
|
|
evmc_set_option_result r = vm->set_option(vm, "unknown_option_csk9twq", nullptr);
|
2018-09-05 17:24:02 +00:00
|
|
|
EXPECT_EQ(r, EVMC_SET_OPTION_INVALID_NAME);
|
2018-04-10 22:37:03 +00:00
|
|
|
}
|
2018-04-17 09:11:07 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 13:44:59 +00:00
|
|
|
TEST_F(evmc_vm_test, set_option_unknown_value)
|
|
|
|
{
|
|
|
|
auto r = evmc_set_option(vm, "verbose", "1");
|
|
|
|
|
|
|
|
// Execute more tests if the VM supports "verbose" option.
|
|
|
|
if (r != EVMC_SET_OPTION_INVALID_NAME)
|
|
|
|
{
|
|
|
|
// The VM supports "verbose" option. Try dummy value for it.
|
|
|
|
auto r2 = evmc_set_option(vm, "verbose", "GjNOONsbUl");
|
|
|
|
EXPECT_EQ(r2, EVMC_SET_OPTION_INVALID_VALUE);
|
|
|
|
|
|
|
|
// For null the behavior should be the same.
|
|
|
|
auto r3 = evmc_set_option(vm, "verbose", nullptr);
|
|
|
|
EXPECT_EQ(r3, EVMC_SET_OPTION_INVALID_VALUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-09 16:27:24 +00:00
|
|
|
TEST_F(evmc_vm_test, precompile_test)
|
|
|
|
{
|
|
|
|
// This logic is based on and should match the description in EIP-2003.
|
|
|
|
|
|
|
|
if (!evmc_vm_has_capability(vm, EVMC_CAPABILITY_PRECOMPILES))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Iterate every address (as per EIP-1352)
|
|
|
|
for (size_t i = 0; i < 0xffff; i++)
|
|
|
|
{
|
|
|
|
auto destination = evmc_address{};
|
|
|
|
destination.bytes[18] = static_cast<uint8_t>(i >> 8);
|
|
|
|
destination.bytes[19] = static_cast<uint8_t>(i & 0xff);
|
|
|
|
|
|
|
|
evmc_message msg{
|
2019-06-25 09:04:53 +00:00
|
|
|
EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, nullptr, 0, evmc_uint256be{},
|
2019-05-09 16:27:24 +00:00
|
|
|
evmc_bytes32{}};
|
|
|
|
|
2019-06-02 22:33:44 +00:00
|
|
|
evmc_result result = vm->execute(vm, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);
|
2019-05-09 16:27:24 +00:00
|
|
|
|
|
|
|
// Validate some constraints
|
|
|
|
|
|
|
|
// Precompiles can only return a limited subset of codes.
|
|
|
|
EXPECT_TRUE(result.status_code == EVMC_SUCCESS || result.status_code == EVMC_OUT_OF_GAS ||
|
|
|
|
result.status_code == EVMC_FAILURE || result.status_code == EVMC_REVERT ||
|
|
|
|
result.status_code == EVMC_REJECTED);
|
|
|
|
|
|
|
|
if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(result.gas_left, 0);
|
|
|
|
}
|
|
|
|
|
2019-06-25 09:04:53 +00:00
|
|
|
if (result.output_data == nullptr)
|
2019-05-09 16:27:24 +00:00
|
|
|
{
|
2019-09-13 09:13:12 +00:00
|
|
|
EXPECT_EQ(result.output_size, size_t{0});
|
2019-05-09 16:27:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-25 09:04:53 +00:00
|
|
|
EXPECT_NE(result.output_size, size_t{0});
|
2019-05-09 16:27:24 +00:00
|
|
|
read_buffer(result.output_data, result.output_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.release)
|
|
|
|
result.release(&result);
|
|
|
|
}
|
|
|
|
}
|