From 8fd448536ddbf073c7181795f4c5a9ca53cf2c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Aug 2022 07:11:28 +0200 Subject: [PATCH 1/2] Add gas refund to evmc_result The evmc_result::gas_refund represents refunded gas accumulated from the current execution and its sub-calls. --- CHANGELOG.md | 7 ++-- bindings/go/evmc/host.go | 7 ++-- bindings/go/evmc/host_test.go | 5 ++- bindings/java/Makefile | 2 +- bindings/java/c/host.c | 2 +- .../org/ethereum/evmc/TestHostContext.java | 2 +- bindings/rust/evmc-declare-tests/src/lib.rs | 2 +- bindings/rust/evmc-declare/src/lib.rs | 4 +- bindings/rust/evmc-sys/src/lib.rs | 1 - bindings/rust/evmc-vm/src/lib.rs | 40 +++++++++++++++---- examples/example-rust-vm/src/lib.rs | 2 +- include/evmc/evmc.h | 8 ++++ include/evmc/evmc.hpp | 1 + test/unittests/helpers_test.cpp | 1 - 14 files changed, 59 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c1ba446..d3410bf2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,13 +18,14 @@ and this project adheres to [Semantic Versioning]. [#634](https://github.com/ethereum/evmc/pull/634) - The Cancun EVM revision (anticipated after Shanghai) [#633](https://github.com/ethereum/evmc/pull/633) +- The gas refund counter has been added to the `evmc_result`. + [#666](https://github.com/ethereum/evmc/pull/666) - The error code `EVMC_LOADER_UNSPECIFIED_ERROR` has been defined to provide a convenient way of initializing `evmc_loader_error_code` objects. [#617](https://github.com/ethereum/evmc/pull/617) - Support for Visual Studio 2022. [#619](https://github.com/ethereum/evmc/pull/619) -- C++ types `evmc::address` and `evmc::bytes32` are convertible to `std::basic_string_view` - . +- C++ types `evmc::address` and `evmc::bytes32` are convertible to `std::basic_string_view`. [#636](https://github.com/ethereum/evmc/pull/636) - Convenient constructors for C++ `evmc::result`. [#660](https://github.com/ethereum/evmc/pull/660) @@ -41,7 +42,7 @@ and this project adheres to [Semantic Versioning]. - The `evmc_message::destination` field has been renamed to `evmc_message::recipient` to clarify its purpose and match the naming from the Yellow Paper. [#616](https://github.com/ethereum/evmc/pull/616) -- The `evmc_storage_status` has been extended to provide information about every possible case of +- The `evmc_storage_status` has been extended to provide information about every possible case of storage net gas metering ([EIP-2200](https://eips.ethereum.org/EIPS/eip-2200)). [#661](https://github.com/ethereum/evmc/pull/661) - The `selfdestruct` method returns the information if the given address diff --git a/bindings/go/evmc/host.go b/bindings/go/evmc/host.go index 29058bc7a..7e7ff4603 100644 --- a/bindings/go/evmc/host.go +++ b/bindings/go/evmc/host.go @@ -97,7 +97,8 @@ type HostContext interface { EmitLog(addr Address, topics []Hash, data []byte) Call(kind CallKind, recipient Address, sender Address, value Hash, input []byte, gas int64, depth int, - static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, createAddr Address, err error) + static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, gasRefund int64, + createAddr Address, err error) AccessAccount(addr Address) AccessStatus AccessStorage(addr Address, key Hash) AccessStatus } @@ -211,7 +212,7 @@ func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result ctx := getHostContext(uintptr(pCtx)) kind := CallKind(msg.kind) - output, gasLeft, createAddr, err := ctx.Call(kind, goAddress(msg.recipient), goAddress(msg.sender), goHash(msg.value), + output, gasLeft, gasRefund, createAddr, err := ctx.Call(kind, goAddress(msg.recipient), goAddress(msg.sender), goHash(msg.value), goByteSlice(msg.input_data, msg.input_size), int64(msg.gas), int(msg.depth), msg.flags != 0, goHash(msg.create2_salt), goAddress(msg.code_address)) @@ -225,7 +226,7 @@ func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result outputData = (*C.uint8_t)(&output[0]) } - result := C.evmc_make_result(statusCode, C.int64_t(gasLeft), outputData, C.size_t(len(output))) + result := C.evmc_make_result(statusCode, C.int64_t(gasLeft), C.int64_t(gasRefund), outputData, C.size_t(len(output))) result.create_address = evmcAddress(createAddr) return result } diff --git a/bindings/go/evmc/host_test.go b/bindings/go/evmc/host_test.go index d6fb0e46f..30225a746 100644 --- a/bindings/go/evmc/host_test.go +++ b/bindings/go/evmc/host_test.go @@ -58,9 +58,10 @@ func (host *testHostContext) EmitLog(addr Address, topics []Hash, data []byte) { func (host *testHostContext) Call(kind CallKind, recipient Address, sender Address, value Hash, input []byte, gas int64, depth int, - static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, createAddr Address, err error) { + static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, gasRefund int64, + createAddr Address, err error) { output = []byte("output from testHostContext.Call()") - return output, gas, Address{}, nil + return output, gas, 0, Address{}, nil } func (host *testHostContext) AccessAccount(addr Address) AccessStatus { diff --git a/bindings/java/Makefile b/bindings/java/Makefile index 8d58175db..6e7dcca8f 100644 --- a/bindings/java/Makefile +++ b/bindings/java/Makefile @@ -1,5 +1,5 @@ # EVMC: Ethereum Client-VM Connector API. -# Copyright 2019-2020 The EVMC Authors. +# Copyright 2019 The EVMC Authors. # Licensed under the Apache License, Version 2.0. JAVA_HOME:=$(shell java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | sed 's/\s*java.home = //' | sed 's/\/jre//') diff --git a/bindings/java/c/host.c b/bindings/java/c/host.c index 24be6b743..71a847989 100644 --- a/bindings/java/c/host.c +++ b/bindings/java/c/host.c @@ -42,7 +42,7 @@ static void CopyFromByteBuffer(JNIEnv* jenv, jobject src, void* dst, size_t size { jclass exception_class = (*jenv)->FindClass(jenv, "java/lang/IllegalArgumentException"); assert(exception_class != NULL); - (*jenv)->ThrowNew(jenv, exception_class, "Unexpected length."); + (*jenv)->ThrowNew(jenv, exception_class, "Unexpected ByteBuffer length."); } memcpy(dst, ptr, size); } diff --git a/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java b/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java index b70d5679a..024328bc3 100644 --- a/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java +++ b/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java @@ -58,7 +58,7 @@ public boolean selfdestruct(byte[] address, byte[] beneficiary) { @Override public ByteBuffer call(ByteBuffer msg) { - return ByteBuffer.allocateDirect(64).put(new byte[64]); + return ByteBuffer.allocateDirect(72).put(new byte[72]); } @Override diff --git a/bindings/rust/evmc-declare-tests/src/lib.rs b/bindings/rust/evmc-declare-tests/src/lib.rs index 0e4ba5d10..10eb373dc 100644 --- a/bindings/rust/evmc-declare-tests/src/lib.rs +++ b/bindings/rust/evmc-declare-tests/src/lib.rs @@ -35,6 +35,6 @@ impl EvmcVm for FooVM { _message: &ExecutionMessage, _context: Option<&mut ExecutionContext>, ) -> ExecutionResult { - ExecutionResult::success(1337, None) + ExecutionResult::success(1337, 21, None) } } diff --git a/bindings/rust/evmc-declare/src/lib.rs b/bindings/rust/evmc-declare/src/lib.rs index 7d2fd842a..5ca91e876 100644 --- a/bindings/rust/evmc-declare/src/lib.rs +++ b/bindings/rust/evmc-declare/src/lib.rs @@ -22,7 +22,7 @@ //! } //! //! fn execute(&self, revision: evmc_vm::ffi::evmc_revision, code: &[u8], message: &evmc_vm::ExecutionMessage, context: Option<&mut evmc_vm::ExecutionContext>) -> evmc_vm::ExecutionResult { -//! evmc_vm::ExecutionResult::success(1337, None) +//! evmc_vm::ExecutionResult::success(1337, 0, None) //! } //! } //! ``` @@ -446,7 +446,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { let result = if result.is_err() { // Consider a panic an internal error. - ::evmc_vm::ExecutionResult::new(::evmc_vm::ffi::evmc_status_code::EVMC_INTERNAL_ERROR, 0, None) + ::evmc_vm::ExecutionResult::new(::evmc_vm::ffi::evmc_status_code::EVMC_INTERNAL_ERROR, 0, 0, None) } else { result.unwrap() }; diff --git a/bindings/rust/evmc-sys/src/lib.rs b/bindings/rust/evmc-sys/src/lib.rs index 02e74ef9d..032fcacfb 100644 --- a/bindings/rust/evmc-sys/src/lib.rs +++ b/bindings/rust/evmc-sys/src/lib.rs @@ -38,7 +38,6 @@ mod tests { // TODO: add other checks from test/unittests/test_helpers.cpp assert_eq!(size_of::(), 32); assert_eq!(size_of::(), 20); - assert!(size_of::() <= 64); assert!(size_of::() <= 64); } } diff --git a/bindings/rust/evmc-vm/src/lib.rs b/bindings/rust/evmc-vm/src/lib.rs index 0bc379297..6285c1482 100644 --- a/bindings/rust/evmc-vm/src/lib.rs +++ b/bindings/rust/evmc-vm/src/lib.rs @@ -47,6 +47,7 @@ pub enum SetOptionError { pub struct ExecutionResult { status_code: StatusCode, gas_left: i64, + gas_refund: i64, output: Option>, create_address: Option
, } @@ -79,10 +80,16 @@ pub struct ExecutionContext<'a> { impl ExecutionResult { /// Manually create a result. - pub fn new(_status_code: StatusCode, _gas_left: i64, _output: Option<&[u8]>) -> Self { + pub fn new( + _status_code: StatusCode, + _gas_left: i64, + _gas_refund: i64, + _output: Option<&[u8]>, + ) -> Self { ExecutionResult { status_code: _status_code, gas_left: _gas_left, + gas_refund: _gas_refund, output: _output.map(|s| s.to_vec()), create_address: None, } @@ -90,17 +97,17 @@ impl ExecutionResult { /// Create failure result. pub fn failure() -> Self { - ExecutionResult::new(StatusCode::EVMC_FAILURE, 0, None) + ExecutionResult::new(StatusCode::EVMC_FAILURE, 0, 0, None) } /// Create a revert result. pub fn revert(_gas_left: i64, _output: Option<&[u8]>) -> Self { - ExecutionResult::new(StatusCode::EVMC_REVERT, _gas_left, _output) + ExecutionResult::new(StatusCode::EVMC_REVERT, _gas_left, 0, _output) } /// Create a successful result. - pub fn success(_gas_left: i64, _output: Option<&[u8]>) -> Self { - ExecutionResult::new(StatusCode::EVMC_SUCCESS, _gas_left, _output) + pub fn success(_gas_left: i64, _gas_refund: i64, _output: Option<&[u8]>) -> Self { + ExecutionResult::new(StatusCode::EVMC_SUCCESS, _gas_left, _gas_refund, _output) } /// Read the status code. @@ -113,6 +120,11 @@ impl ExecutionResult { self.gas_left } + /// Read the amount of gas refunded. + pub fn gas_refund(&self) -> i64 { + self.gas_refund + } + /// Read the output returned. pub fn output(&self) -> Option<&Vec> { self.output.as_ref() @@ -397,6 +409,7 @@ impl From for ExecutionResult { let ret = Self { status_code: result.status_code, gas_left: result.gas_left, + gas_refund: result.gas_refund, output: if result.output_data.is_null() { assert_eq!(result.output_size, 0); None @@ -469,6 +482,7 @@ impl From for ffi::evmc_result { Self { status_code: value.status_code, gas_left: value.gas_left, + gas_refund: value.gas_refund, output_data: buffer, output_size: len, release: Some(release_stack_result), @@ -532,10 +546,11 @@ mod tests { #[test] fn result_new() { - let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None); + let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, 21, None); assert_eq!(r.status_code(), StatusCode::EVMC_FAILURE); assert_eq!(r.gas_left(), 420); + assert_eq!(r.gas_refund(), 21); assert!(r.output().is_none()); assert!(r.create_address().is_none()); } @@ -559,6 +574,7 @@ mod tests { let f = ffi::evmc_result { status_code: StatusCode::EVMC_SUCCESS, gas_left: 1337, + gas_refund: 21, output_data: Box::into_raw(Box::new([0xde, 0xad, 0xbe, 0xef])) as *const u8, output_size: 4, release: Some(test_result_dispose), @@ -570,6 +586,7 @@ mod tests { assert_eq!(r.status_code(), StatusCode::EVMC_SUCCESS); assert_eq!(r.gas_left(), 1337); + assert_eq!(r.gas_refund(), 21); assert!(r.output().is_some()); assert_eq!(r.output().unwrap().len(), 4); assert!(r.create_address().is_some()); @@ -580,6 +597,7 @@ mod tests { let r = ExecutionResult::new( StatusCode::EVMC_FAILURE, 420, + 21, Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]), ); @@ -588,6 +606,7 @@ mod tests { unsafe { assert_eq!((*f).status_code, StatusCode::EVMC_FAILURE); assert_eq!((*f).gas_left, 420); + assert_eq!((*f).gas_refund, 21); assert!(!(*f).output_data.is_null()); assert_eq!((*f).output_size, 5); assert_eq!( @@ -603,13 +622,14 @@ mod tests { #[test] fn result_into_heap_ffi_empty_data() { - let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None); + let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, 21, None); let f: *const ffi::evmc_result = r.into(); assert!(!f.is_null()); unsafe { assert_eq!((*f).status_code, StatusCode::EVMC_FAILURE); assert_eq!((*f).gas_left, 420); + assert_eq!((*f).gas_refund, 21); assert!((*f).output_data.is_null()); assert_eq!((*f).output_size, 0); assert_eq!((*f).create_address.bytes, [0u8; 20]); @@ -624,6 +644,7 @@ mod tests { let r = ExecutionResult::new( StatusCode::EVMC_FAILURE, 420, + 21, Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]), ); @@ -631,6 +652,7 @@ mod tests { unsafe { assert_eq!(f.status_code, StatusCode::EVMC_FAILURE); assert_eq!(f.gas_left, 420); + assert_eq!(f.gas_refund, 21); assert!(!f.output_data.is_null()); assert_eq!(f.output_size, 5); assert_eq!( @@ -646,12 +668,13 @@ mod tests { #[test] fn result_into_stack_ffi_empty_data() { - let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None); + let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, 21, None); let f: ffi::evmc_result = r.into(); unsafe { assert_eq!(f.status_code, StatusCode::EVMC_FAILURE); assert_eq!(f.gas_left, 420); + assert_eq!(f.gas_refund, 21); assert!(f.output_data.is_null()); assert_eq!(f.output_size, 0); assert_eq!(f.create_address.bytes, [0u8; 20]); @@ -812,6 +835,7 @@ mod tests { StatusCode::EVMC_INTERNAL_ERROR }, gas_left: 2, + gas_refund: 0, // NOTE: we are passing the input pointer here, but for testing the lifetime is ok output_data: msg.input_data, output_size: msg.input_size, diff --git a/examples/example-rust-vm/src/lib.rs b/examples/example-rust-vm/src/lib.rs index 22c80694a..8e45c006f 100644 --- a/examples/example-rust-vm/src/lib.rs +++ b/examples/example-rust-vm/src/lib.rs @@ -76,6 +76,6 @@ impl EvmcVm for ExampleRustVM { _context.set_storage(message.recipient(), &storage_key, &storage_value); let ret = format!("{}", block_number).into_bytes(); - ExecutionResult::success(message.gas() / 2, Some(&ret)) + ExecutionResult::success(message.gas() / 2, 0, Some(&ret)) } } diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index eba22f489..16d568660 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -401,6 +401,14 @@ struct evmc_result */ int64_t gas_left; + /** + * The refunded gas accumulated from this execution and its sub-calls. + * + * The transaction gas refund limit is not applied. + * If evmc_result::status_code is other than ::EVMC_SUCCESS the value MUST be 0. + */ + int64_t gas_refund; + /** * The reference to output data. * diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index f687091e0..276dd8a5f 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -333,6 +333,7 @@ class Result : private evmc_result public: using evmc_result::create_address; using evmc_result::gas_left; + using evmc_result::gas_refund; using evmc_result::output_data; using evmc_result::output_size; using evmc_result::status_code; diff --git a/test/unittests/helpers_test.cpp b/test/unittests/helpers_test.cpp index d169430c7..81fdb8a0d 100644 --- a/test/unittests/helpers_test.cpp +++ b/test/unittests/helpers_test.cpp @@ -10,7 +10,6 @@ static_assert(sizeof(evmc_bytes32) == 32, "evmc_bytes32 is too big"); static_assert(sizeof(evmc_address) == 20, "evmc_address is too big"); -static_assert(sizeof(evmc_result) <= 64, "evmc_result does not fit cache line"); static_assert(sizeof(evmc_vm) <= 64, "evmc_vm does not fit cache line"); static_assert(offsetof(evmc_message, value) % sizeof(size_t) == 0, "evmc_message.value not aligned"); From 58e16bf6a1be9a5f445b2dd443f018e55218e777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 10 Aug 2022 16:14:12 +0200 Subject: [PATCH 2/2] Extend evmc_make_result() and evmc::Result with gas refund --- examples/example_host.cpp | 2 +- examples/example_vm/example_vm.cpp | 22 +++++++++++----------- include/evmc/evmc.hpp | 14 ++++++++++---- include/evmc/helpers.h | 3 +++ test/unittests/cpp_test.cpp | 6 ++++-- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/examples/example_host.cpp b/examples/example_host.cpp index 1385a4b45..576501ff4 100644 --- a/examples/example_host.cpp +++ b/examples/example_host.cpp @@ -134,7 +134,7 @@ class ExampleHost : public evmc::Host evmc::Result call(const evmc_message& msg) noexcept final { - return evmc::Result{EVMC_REVERT, msg.gas, msg.input_data, msg.input_size}; + return evmc::Result{EVMC_REVERT, msg.gas, 0, msg.input_data, msg.input_size}; } evmc_tx_context get_tx_context() const noexcept final { return tx_context; } diff --git a/examples/example_vm/example_vm.cpp b/examples/example_vm/example_vm.cpp index 13dd43d35..ecb99c8fc 100644 --- a/examples/example_vm/example_vm.cpp +++ b/examples/example_vm/example_vm.cpp @@ -181,15 +181,15 @@ evmc_result execute(evmc_vm* instance, // Check remaining gas, assume each instruction costs 1. gas_left -= 1; if (gas_left < 0) - return evmc_make_result(EVMC_OUT_OF_GAS, 0, nullptr, 0); + return evmc_make_result(EVMC_OUT_OF_GAS, 0, 0, nullptr, 0); switch (code[pc]) { default: - return evmc_make_result(EVMC_UNDEFINED_INSTRUCTION, 0, nullptr, 0); + return evmc_make_result(EVMC_UNDEFINED_INSTRUCTION, 0, 0, nullptr, 0); case OP_STOP: - return evmc_make_result(EVMC_SUCCESS, gas_left, nullptr, 0); + return evmc_make_result(EVMC_SUCCESS, gas_left, 0, nullptr, 0); case OP_ADD: { @@ -235,7 +235,7 @@ evmc_result execute(evmc_vm* instance, uint32_t index = to_uint32(stack.pop()); evmc_uint256be value = stack.pop(); if (!memory.store(index, value.bytes, sizeof(value))) - return evmc_make_result(EVMC_FAILURE, 0, nullptr, 0); + return evmc_make_result(EVMC_FAILURE, 0, 0, nullptr, 0); break; } @@ -329,7 +329,7 @@ evmc_result execute(evmc_vm* instance, uint8_t* call_output_ptr = memory.expand(call_output_offset, call_output_size); if (call_msg.input_data == nullptr || call_output_ptr == nullptr) - return evmc_make_result(EVMC_FAILURE, 0, nullptr, 0); + return evmc_make_result(EVMC_FAILURE, 0, 0, nullptr, 0); evmc_result call_result = host->call(context, &call_msg); @@ -351,28 +351,28 @@ evmc_result execute(evmc_vm* instance, uint32_t output_size = to_uint32(stack.pop()); uint8_t* output_ptr = memory.expand(output_offset, output_size); if (output_ptr == nullptr) - return evmc_make_result(EVMC_FAILURE, 0, nullptr, 0); + return evmc_make_result(EVMC_FAILURE, 0, 0, nullptr, 0); - return evmc_make_result(EVMC_SUCCESS, gas_left, output_ptr, output_size); + return evmc_make_result(EVMC_SUCCESS, gas_left, 0, output_ptr, output_size); } case OP_REVERT: { if (rev < EVMC_BYZANTIUM) - return evmc_make_result(EVMC_UNDEFINED_INSTRUCTION, 0, nullptr, 0); + return evmc_make_result(EVMC_UNDEFINED_INSTRUCTION, 0, 0, nullptr, 0); uint32_t output_offset = to_uint32(stack.pop()); uint32_t output_size = to_uint32(stack.pop()); uint8_t* output_ptr = memory.expand(output_offset, output_size); if (output_ptr == nullptr) - return evmc_make_result(EVMC_FAILURE, 0, nullptr, 0); + return evmc_make_result(EVMC_FAILURE, 0, 0, nullptr, 0); - return evmc_make_result(EVMC_REVERT, gas_left, output_ptr, output_size); + return evmc_make_result(EVMC_REVERT, gas_left, 0, output_ptr, output_size); } } } - return evmc_make_result(EVMC_SUCCESS, gas_left, nullptr, 0); + return evmc_make_result(EVMC_SUCCESS, gas_left, 0, nullptr, 0); } diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index 276dd8a5f..3d336894f 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -345,33 +345,39 @@ class Result : private evmc_result /// /// @param _status_code The status code. /// @param _gas_left The amount of gas left. + /// @param _gas_refund The amount of refunded gas. /// @param _output_data The pointer to the output. /// @param _output_size The output size. explicit Result(evmc_status_code _status_code, int64_t _gas_left, + int64_t _gas_refund, const uint8_t* _output_data, size_t _output_size) noexcept - : evmc_result{make_result(_status_code, _gas_left, _output_data, _output_size)} + : evmc_result{make_result(_status_code, _gas_left, _gas_refund, _output_data, _output_size)} {} /// Creates the result without output. /// /// @param _status_code The status code. /// @param _gas_left The amount of gas left. + /// @param _gas_refund The amount of refunded gas. explicit Result(evmc_status_code _status_code = EVMC_INTERNAL_ERROR, - int64_t _gas_left = 0) noexcept - : evmc_result{make_result(_status_code, _gas_left, nullptr, 0)} + int64_t _gas_left = 0, + int64_t _gas_refund = 0) noexcept + : evmc_result{make_result(_status_code, _gas_left, _gas_refund, nullptr, 0)} {} /// Creates the result of contract creation. /// /// @param _status_code The status code. /// @param _gas_left The amount of gas left. + /// @param _gas_refund The amount of refunded gas. /// @param _create_address The address of the possibly created account. explicit Result(evmc_status_code _status_code, int64_t _gas_left, + int64_t _gas_refund, const evmc_address& _create_address) noexcept - : evmc_result{make_result(_status_code, _gas_left, nullptr, 0)} + : evmc_result{make_result(_status_code, _gas_left, _gas_refund, nullptr, 0)} { create_address = _create_address; } diff --git a/include/evmc/helpers.h b/include/evmc/helpers.h index 9d9247796..17db3d194 100644 --- a/include/evmc/helpers.h +++ b/include/evmc/helpers.h @@ -119,10 +119,12 @@ static void evmc_free_result_memory(const struct evmc_result* result) /// /// @param status_code The status code. /// @param gas_left The amount of gas left. +/// @param gas_refund The amount of refunded gas. /// @param output_data The pointer to the output. /// @param output_size The output size. static inline struct evmc_result evmc_make_result(enum evmc_status_code status_code, int64_t gas_left, + int64_t gas_refund, const uint8_t* output_data, size_t output_size) { @@ -147,6 +149,7 @@ static inline struct evmc_result evmc_make_result(enum evmc_status_code status_c result.status_code = status_code; result.gas_left = gas_left; + result.gas_refund = gas_refund; return result; } diff --git a/test/unittests/cpp_test.cpp b/test/unittests/cpp_test.cpp index 12b142672..885291e73 100644 --- a/test/unittests/cpp_test.cpp +++ b/test/unittests/cpp_test.cpp @@ -799,15 +799,17 @@ TEST(cpp, result_create_no_output) TEST(cpp, result_create) { const uint8_t output[] = {1, 2}; - auto r = evmc::Result{EVMC_FAILURE, -1, output, sizeof(output)}; + auto r = evmc::Result{EVMC_FAILURE, -1, -2, output, sizeof(output)}; EXPECT_EQ(r.status_code, EVMC_FAILURE); EXPECT_EQ(r.gas_left, -1); + EXPECT_EQ(r.gas_refund, -2); ASSERT_TRUE(r.output_data); ASSERT_EQ(r.output_size, size_t{2}); EXPECT_EQ(r.output_data[0], 1); EXPECT_EQ(r.output_data[1], 2); - auto c = evmc::make_result(r.status_code, r.gas_left, r.output_data, r.output_size); + auto c = + evmc::make_result(r.status_code, r.gas_left, r.gas_refund, r.output_data, r.output_size); EXPECT_EQ(c.status_code, r.status_code); EXPECT_EQ(c.gas_left, r.gas_left); ASSERT_EQ(c.output_size, r.output_size);