diff --git a/examples/example_precompiles_vm/example_precompiles_vm.cpp b/examples/example_precompiles_vm/example_precompiles_vm.cpp index e5d3b52..e03737c 100644 --- a/examples/example_precompiles_vm/example_precompiles_vm.cpp +++ b/examples/example_precompiles_vm/example_precompiles_vm.cpp @@ -44,7 +44,7 @@ static evmc_result execute_empty(const evmc_message* msg) static evmc_result not_implemented() { auto result = evmc_result{}; - result.status_code = EVMC_INTERNAL_ERROR; + result.status_code = EVMC_REJECTED; return result; } diff --git a/test/vmtester/tests.cpp b/test/vmtester/tests.cpp index afd1a20..f796a1a 100644 --- a/test/vmtester/tests.cpp +++ b/test/vmtester/tests.cpp @@ -168,3 +168,50 @@ TEST_F(evmc_vm_test, set_tracer) if (vm->set_tracer) vm->set_tracer(vm, tracer_callback, nullptr); } + +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(i >> 8); + destination.bytes[19] = static_cast(i & 0xff); + + evmc_message msg{ + EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, NULL, 0, evmc_uint256be{}, + evmc_bytes32{}}; + + evmc_result result = vm->execute(vm, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0); + + // 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); + } + + if (result.output_data == NULL) + { + EXPECT_EQ(result.output_size, 0); + } + else + { + EXPECT_NE(result.output_size, 0); + read_buffer(result.output_data, result.output_size); + } + + if (result.release) + result.release(&result); + } +}