Skip to content

Commit

Permalink
Merge pull request #666 from ethereum/refund
Browse files Browse the repository at this point in the history
Add gas refund to evmc_result
  • Loading branch information
chfast authored Aug 17, 2022
2 parents b36789a + 58e16bf commit 762a8e6
Show file tree
Hide file tree
Showing 18 changed files with 88 additions and 43 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>`
.
- C++ types `evmc::address` and `evmc::bytes32` are convertible to `std::basic_string_view<uint8_t>`.
[#636](https://github.com/ethereum/evmc/pull/636)
- Convenient constructors for C++ `evmc::result`.
[#660](https://github.com/ethereum/evmc/pull/660)
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions bindings/go/evmc/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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))

Expand All @@ -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
}
Expand Down
5 changes: 3 additions & 2 deletions bindings/go/evmc/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion bindings/java/Makefile
Original file line number Diff line number Diff line change
@@ -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//')
Expand Down
2 changes: 1 addition & 1 deletion bindings/java/c/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion bindings/rust/evmc-declare-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ impl EvmcVm for FooVM {
_message: &ExecutionMessage,
_context: Option<&mut ExecutionContext>,
) -> ExecutionResult {
ExecutionResult::success(1337, None)
ExecutionResult::success(1337, 21, None)
}
}
4 changes: 2 additions & 2 deletions bindings/rust/evmc-declare/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
//! }
//! }
//! ```
Expand Down Expand Up @@ -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()
};
Expand Down
1 change: 0 additions & 1 deletion bindings/rust/evmc-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ mod tests {
// TODO: add other checks from test/unittests/test_helpers.cpp
assert_eq!(size_of::<evmc_bytes32>(), 32);
assert_eq!(size_of::<evmc_address>(), 20);
assert!(size_of::<evmc_result>() <= 64);
assert!(size_of::<evmc_vm>() <= 64);
}
}
40 changes: 32 additions & 8 deletions bindings/rust/evmc-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub enum SetOptionError {
pub struct ExecutionResult {
status_code: StatusCode,
gas_left: i64,
gas_refund: i64,
output: Option<Vec<u8>>,
create_address: Option<Address>,
}
Expand Down Expand Up @@ -79,28 +80,34 @@ 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,
}
}

/// 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.
Expand All @@ -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<u8>> {
self.output.as_ref()
Expand Down Expand Up @@ -397,6 +409,7 @@ impl From<ffi::evmc_result> 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
Expand Down Expand Up @@ -469,6 +482,7 @@ impl From<ExecutionResult> 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),
Expand Down Expand Up @@ -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());
}
Expand All @@ -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),
Expand All @@ -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());
Expand All @@ -580,6 +597,7 @@ mod tests {
let r = ExecutionResult::new(
StatusCode::EVMC_FAILURE,
420,
21,
Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]),
);

Expand All @@ -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!(
Expand All @@ -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]);
Expand All @@ -624,13 +644,15 @@ mod tests {
let r = ExecutionResult::new(
StatusCode::EVMC_FAILURE,
420,
21,
Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]),
);

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, 5);
assert_eq!(
Expand All @@ -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]);
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/example-rust-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
2 changes: 1 addition & 1 deletion examples/example_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
22 changes: 11 additions & 11 deletions examples/example_vm/example_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);

Expand All @@ -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);
}


Expand Down
Loading

0 comments on commit 762a8e6

Please sign in to comment.