diff --git a/bindings/go/evmc/evmc.go b/bindings/go/evmc/evmc.go index 51da0c28f..9f2e4536a 100644 --- a/bindings/go/evmc/evmc.go +++ b/bindings/go/evmc/evmc.go @@ -43,6 +43,7 @@ static struct evmc_result execute_wrapper(struct evmc_vm* vm, input_size, *value, {{0}}, // create2_salt: not required for execution + {{0}}, // code_address: not required for execution }; struct evmc_host_context* context = (struct evmc_host_context*)context_index; diff --git a/bindings/go/evmc/host.go b/bindings/go/evmc/host.go index b2760a089..e78fbe46e 100644 --- a/bindings/go/evmc/host.go +++ b/bindings/go/evmc/host.go @@ -93,7 +93,7 @@ type HostContext interface { EmitLog(addr Address, topics []Hash, data []byte) Call(kind CallKind, destination Address, sender Address, value Hash, input []byte, gas int64, depth int, - static bool, salt Hash) (output []byte, gasLeft int64, createAddr Address, err error) + static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, createAddr Address, err error) AccessAccount(addr Address) AccessStatus AccessStorage(addr Address, key Hash) AccessStatus } @@ -208,7 +208,8 @@ func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result kind := CallKind(msg.kind) output, gasLeft, createAddr, err := ctx.Call(kind, goAddress(msg.destination), 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)) + goByteSlice(msg.input_data, msg.input_size), int64(msg.gas), int(msg.depth), msg.flags != 0, goHash(msg.create2_salt), + goAddress(msg.code_address)) statusCode := C.enum_evmc_status_code(0) if err != nil { diff --git a/bindings/go/evmc/host_test.go b/bindings/go/evmc/host_test.go index cf457e3b3..4d7c2c11b 100644 --- a/bindings/go/evmc/host_test.go +++ b/bindings/go/evmc/host_test.go @@ -57,7 +57,7 @@ func (host *testHostContext) EmitLog(addr Address, topics []Hash, data []byte) { func (host *testHostContext) Call(kind CallKind, destination Address, sender Address, value Hash, input []byte, gas int64, depth int, - static bool, salt Hash) (output []byte, gasLeft int64, createAddr Address, err error) { + static bool, salt Hash, codeAddress Address) (output []byte, gasLeft int64, createAddr Address, err error) { output = []byte("output from testHostContext.Call()") return output, gas, Address{}, nil } diff --git a/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java b/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java index a3837a1b7..f63635dd7 100644 --- a/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java +++ b/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java @@ -19,6 +19,7 @@ public class TestMessage { long inputSize; char[] value; byte[] createSalt; + byte[] codeAddress; public TestMessage( int kind, @@ -38,6 +39,7 @@ public TestMessage( this.inputSize = (long) inputData.length; this.value = value; this.createSalt = new byte[32]; + this.codeAddress = new byte[20]; } public TestMessage(ByteBuffer msg) { @@ -56,11 +58,12 @@ public TestMessage(ByteBuffer msg) { tmpbuf = msg.get(new byte[32]); this.value = StandardCharsets.ISO_8859_1.decode(tmpbuf).array(); this.createSalt = msg.get(new byte[32]).array(); + this.codeAddress = msg.get(new byte[20]).array(); } public ByteBuffer toByteBuffer() { - return ByteBuffer.allocateDirect(152) + return ByteBuffer.allocateDirect(172) .order(ByteOrder.nativeOrder()) .putInt(kind) // 4 .putInt(flags) // 4 @@ -72,6 +75,7 @@ public ByteBuffer toByteBuffer() { .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(inputData))) // 8 .putLong(inputSize) // 8 .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(value))) // 32 - .put(createSalt); // 32 + .put(createSalt) // 32 + .put(codeAddress); // 20 } } diff --git a/bindings/rust/evmc-vm/src/container.rs b/bindings/rust/evmc-vm/src/container.rs index 2f36e24c6..759bd9682 100644 --- a/bindings/rust/evmc-vm/src/container.rs +++ b/bindings/rust/evmc-vm/src/container.rs @@ -122,6 +122,7 @@ mod tests { input_size: 0, value: ::evmc_sys::evmc_uint256be::default(), create2_salt: ::evmc_sys::evmc_bytes32::default(), + code_address: ::evmc_sys::evmc_address::default(), }; let message: ExecutionMessage = (&message).into(); diff --git a/bindings/rust/evmc-vm/src/lib.rs b/bindings/rust/evmc-vm/src/lib.rs index 808e027fd..54e5fa68a 100644 --- a/bindings/rust/evmc-vm/src/lib.rs +++ b/bindings/rust/evmc-vm/src/lib.rs @@ -50,6 +50,7 @@ pub struct ExecutionMessage { input: Option>, value: Uint256, create2_salt: Bytes32, + code_address: Address, } /// EVMC transaction context structure. @@ -126,6 +127,7 @@ impl ExecutionMessage { input: Option<&[u8]>, value: Uint256, create2_salt: Bytes32, + code_address: Address, ) -> Self { ExecutionMessage { kind, @@ -141,6 +143,7 @@ impl ExecutionMessage { }, value, create2_salt, + code_address, } } @@ -188,6 +191,11 @@ impl ExecutionMessage { pub fn create2_salt(&self) -> &Bytes32 { &self.create2_salt } + + /// Read the code address of the message. + pub fn code_address(&self) -> &Address { + &self.code_address + } } impl<'a> ExecutionContext<'a> { @@ -326,6 +334,7 @@ impl<'a> ExecutionContext<'a> { input_size: input_size, value: *message.value(), create2_salt: *message.create2_salt(), + code_address: *message.code_address(), }; unsafe { assert!((*self.host).call.is_some()); @@ -495,6 +504,7 @@ impl From<&ffi::evmc_message> for ExecutionMessage { }, value: message.value, create2_salt: message.create2_salt, + code_address: message.code_address, } } } @@ -653,6 +663,7 @@ mod tests { let sender = Address { bytes: [128u8; 20] }; let value = Uint256 { bytes: [0u8; 32] }; let create2_salt = Bytes32 { bytes: [255u8; 32] }; + let code_address = Address { bytes: [64u8; 20] }; let ret = ExecutionMessage::new( MessageKind::EVMC_CALL, @@ -664,6 +675,7 @@ mod tests { Some(&input), value, create2_salt, + code_address, ); assert_eq!(ret.kind(), MessageKind::EVMC_CALL); @@ -676,6 +688,7 @@ mod tests { assert_eq!(*ret.input().unwrap(), input); assert_eq!(*ret.value(), value); assert_eq!(*ret.create2_salt(), create2_salt); + assert_eq!(*ret.code_address(), code_address); } #[test] @@ -684,6 +697,7 @@ mod tests { let sender = Address { bytes: [128u8; 20] }; let value = Uint256 { bytes: [0u8; 32] }; let create2_salt = Bytes32 { bytes: [255u8; 32] }; + let code_address = Address { bytes: [64u8; 20] }; let msg = ffi::evmc_message { kind: MessageKind::EVMC_CALL, @@ -696,6 +710,7 @@ mod tests { input_size: 0, value: value, create2_salt: create2_salt, + code_address: code_address, }; let ret: ExecutionMessage = (&msg).into(); @@ -709,6 +724,7 @@ mod tests { assert!(ret.input().is_none()); assert_eq!(*ret.value(), msg.value); assert_eq!(*ret.create2_salt(), msg.create2_salt); + assert_eq!(*ret.code_address(), msg.code_address); } #[test] @@ -718,6 +734,7 @@ mod tests { let sender = Address { bytes: [128u8; 20] }; let value = Uint256 { bytes: [0u8; 32] }; let create2_salt = Bytes32 { bytes: [255u8; 32] }; + let code_address = Address { bytes: [64u8; 20] }; let msg = ffi::evmc_message { kind: MessageKind::EVMC_CALL, @@ -730,6 +747,7 @@ mod tests { input_size: input.len(), value: value, create2_salt: create2_salt, + code_address: code_address, }; let ret: ExecutionMessage = (&msg).into(); @@ -744,6 +762,7 @@ mod tests { assert_eq!(*ret.input().unwrap(), input); assert_eq!(*ret.value(), msg.value); assert_eq!(*ret.create2_salt(), msg.create2_salt); + assert_eq!(*ret.code_address(), msg.code_address); } unsafe extern "C" fn get_dummy_tx_context( @@ -866,6 +885,7 @@ mod tests { None, Uint256::default(), Bytes32::default(), + test_addr, ); let b = exe_context.call(&message); @@ -897,6 +917,7 @@ mod tests { Some(&data), Uint256::default(), Bytes32::default(), + test_addr, ); let b = exe_context.call(&message); diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index 28f3c406c..55479e279 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -109,7 +109,7 @@ struct evmc_message /** The amount of gas for message execution. */ int64_t gas; - /** The destination of the message. */ + /** The destination (recipient) of the message. */ evmc_address destination; /** The sender of the message. */ @@ -141,6 +141,16 @@ struct evmc_message * Ignored in evmc_execute_fn(). */ evmc_bytes32 create2_salt; + + /** + * The address of the code to be executed. + * May be different from the destination (recipient) in case of CALLCODE & DELEGATECALL. + * See Section 8 "Message Call" of the Yellow Paper for detail. + * + * Not required when invoking evmc_execute_fn, only when invoking evmc_call_fn. + * Ignored if kind is EVMC_CREATE or EVMC_CREATE2. + */ + evmc_address code_address; }; diff --git a/tools/vmtester/tests.cpp b/tools/vmtester/tests.cpp index 83ed52b02..89c48aa2d 100644 --- a/tools/vmtester/tests.cpp +++ b/tools/vmtester/tests.cpp @@ -87,9 +87,17 @@ TEST_F(evmc_vm_test, execute_call) TEST_F(evmc_vm_test, execute_create) { evmc::MockedHost mockedHost; - evmc_message msg{ - EVMC_CREATE, 0, 0, 65536, evmc_address{}, evmc_address{}, nullptr, 0, evmc_uint256be{}, - evmc_bytes32{}}; + evmc_message msg{EVMC_CREATE, + 0, + 0, + 65536, + evmc_address{}, + evmc_address{}, + nullptr, + 0, + evmc_uint256be{}, + evmc_bytes32{}, + evmc_address{}}; std::array code = {{0xfe, 0x00}}; evmc_result result = @@ -170,9 +178,17 @@ TEST_F(evmc_vm_test, precompile_test) 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{}, nullptr, 0, evmc_uint256be{}, - evmc_bytes32{}}; + evmc_message msg{EVMC_CALL, + 0, + 0, + 65536, + destination, + evmc_address{}, + nullptr, + 0, + evmc_uint256be{}, + evmc_bytes32{}, + evmc_address{}}; evmc_result result = vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);