Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EOFCREATE message support #681

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bindings/go/evmc/evmc.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ static struct evmc_result execute_wrapper(struct evmc_vm* vm,
*value,
{{0}}, // create2_salt: not required for execution
{{0}}, // code_address: not required for execution
0, // code
0, // code_size
};

struct evmc_host_context* context = (struct evmc_host_context*)context_index;
Expand Down
1 change: 1 addition & 0 deletions bindings/go/evmc/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
CallCode CallKind = C.EVMC_CALLCODE
Create CallKind = C.EVMC_CREATE
Create2 CallKind = C.EVMC_CREATE2
EofCreate CallKind = C.EVMC_EOFCREATE
)

type AccessStatus int
Expand Down
2 changes: 2 additions & 0 deletions bindings/rust/evmc-vm/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ mod tests {
value: ::evmc_sys::evmc_uint256be::default(),
create2_salt: ::evmc_sys::evmc_bytes32::default(),
code_address: ::evmc_sys::evmc_address::default(),
code: std::ptr::null(),
code_size: 0,
};
let message: ExecutionMessage = (&message).into();

Expand Down
111 changes: 111 additions & 0 deletions bindings/rust/evmc-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub struct ExecutionMessage {
value: Uint256,
create2_salt: Bytes32,
code_address: Address,
code: Option<Vec<u8>>,
}

/// EVMC transaction context structure.
Expand Down Expand Up @@ -149,6 +150,7 @@ impl ExecutionMessage {
value: Uint256,
create2_salt: Bytes32,
code_address: Address,
code: Option<&[u8]>,
) -> Self {
ExecutionMessage {
kind,
Expand All @@ -161,6 +163,7 @@ impl ExecutionMessage {
value,
create2_salt,
code_address,
code: code.map(|s| s.to_vec()),
}
}

Expand Down Expand Up @@ -213,6 +216,11 @@ impl ExecutionMessage {
pub fn code_address(&self) -> &Address {
&self.code_address
}

/// Read the optional init code.
pub fn code(&self) -> Option<&Vec<u8>> {
self.code.as_ref()
}
}

impl<'a> ExecutionContext<'a> {
Expand Down Expand Up @@ -338,6 +346,13 @@ impl<'a> ExecutionContext<'a> {
} else {
std::ptr::null() as *const u8
};
let code = message.code();
let code_size = if let Some(code) = code { code.len() } else { 0 };
let code_data = if let Some(code) = code {
code.as_ptr()
} else {
std::ptr::null() as *const u8
};
// Cannot use a nice from trait here because that complicates memory management,
// evmc_message doesn't have a release() method we could abstract it with.
let message = ffi::evmc_message {
Expand All @@ -352,6 +367,8 @@ impl<'a> ExecutionContext<'a> {
value: *message.value(),
create2_salt: *message.create2_salt(),
code_address: *message.code_address(),
code: code_data,
code_size,
};
unsafe {
assert!((*self.host).call.is_some());
Expand Down Expand Up @@ -524,6 +541,14 @@ impl From<&ffi::evmc_message> for ExecutionMessage {
value: message.value,
create2_salt: message.create2_salt,
code_address: message.code_address,
code: if message.code.is_null() {
assert_eq!(message.code_size, 0);
None
} else if message.code_size == 0 {
None
} else {
Some(from_buf_raw::<u8>(message.code, message.code_size))
},
}
}
}
Expand Down Expand Up @@ -704,6 +729,7 @@ mod tests {
value,
create2_salt,
code_address,
None,
);

assert_eq!(ret.kind(), MessageKind::EVMC_CALL);
Expand All @@ -719,6 +745,42 @@ mod tests {
assert_eq!(*ret.code_address(), code_address);
}

#[test]
fn message_new_with_code() {
let recipient = Address { bytes: [32u8; 20] };
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 code = vec![0x5f, 0x5f, 0xfd];

let ret = ExecutionMessage::new(
MessageKind::EVMC_CALL,
44,
66,
4466,
recipient,
sender,
None,
value,
create2_salt,
code_address,
Some(&code),
);

assert_eq!(ret.kind(), MessageKind::EVMC_CALL);
assert_eq!(ret.flags(), 44);
assert_eq!(ret.depth(), 66);
assert_eq!(ret.gas(), 4466);
assert_eq!(*ret.recipient(), recipient);
assert_eq!(*ret.sender(), sender);
assert_eq!(*ret.value(), value);
assert_eq!(*ret.create2_salt(), create2_salt);
assert_eq!(*ret.code_address(), code_address);
assert!(ret.code().is_some());
assert_eq!(*ret.code().unwrap(), code);
}

#[test]
fn message_from_ffi() {
let recipient = Address { bytes: [32u8; 20] };
Expand All @@ -739,6 +801,8 @@ mod tests {
value,
create2_salt,
code_address,
code: std::ptr::null(),
code_size: 0,
};

let ret: ExecutionMessage = (&msg).into();
Expand All @@ -753,6 +817,7 @@ mod tests {
assert_eq!(*ret.value(), msg.value);
assert_eq!(*ret.create2_salt(), msg.create2_salt);
assert_eq!(*ret.code_address(), msg.code_address);
assert!(ret.code().is_none());
}

#[test]
Expand All @@ -776,6 +841,8 @@ mod tests {
value,
create2_salt,
code_address,
code: std::ptr::null(),
code_size: 0,
};

let ret: ExecutionMessage = (&msg).into();
Expand All @@ -791,6 +858,48 @@ mod tests {
assert_eq!(*ret.value(), msg.value);
assert_eq!(*ret.create2_salt(), msg.create2_salt);
assert_eq!(*ret.code_address(), msg.code_address);
assert!(ret.code().is_none());
}

#[test]
fn message_from_ffi_with_code() {
let recipient = Address { bytes: [32u8; 20] };
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 code = vec![0x5f, 0x5f, 0xfd];

let msg = ffi::evmc_message {
kind: MessageKind::EVMC_CALL,
flags: 44,
depth: 66,
gas: 4466,
recipient,
sender,
input_data: std::ptr::null(),
input_size: 0,
value,
create2_salt,
code_address,
code: code.as_ptr(),
code_size: code.len(),
};

let ret: ExecutionMessage = (&msg).into();

assert_eq!(ret.kind(), msg.kind);
assert_eq!(ret.flags(), msg.flags);
assert_eq!(ret.depth(), msg.depth);
assert_eq!(ret.gas(), msg.gas);
assert_eq!(*ret.recipient(), msg.recipient);
assert_eq!(*ret.sender(), msg.sender);
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);
assert!(ret.code().is_some());
assert_eq!(*ret.code().unwrap(), code);
}

unsafe extern "C" fn get_dummy_tx_context(
Expand Down Expand Up @@ -918,6 +1027,7 @@ mod tests {
Uint256::default(),
Bytes32::default(),
test_addr,
None,
);

let b = exe_context.call(&message);
Expand Down Expand Up @@ -950,6 +1060,7 @@ mod tests {
Uint256::default(),
Bytes32::default(),
test_addr,
None,
);

let b = exe_context.call(&message);
Expand Down
5 changes: 5 additions & 0 deletions bindings/rust/evmc-vm/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ mod tests {
ffi::evmc_call_kind::EVMC_DELEGATECALL
);
assert_eq!(MessageKind::EVMC_CREATE, ffi::evmc_call_kind::EVMC_CREATE);
assert_eq!(MessageKind::EVMC_CREATE2, ffi::evmc_call_kind::EVMC_CREATE2);
assert_eq!(
MessageKind::EVMC_EOFCREATE,
ffi::evmc_call_kind::EVMC_EOFCREATE
);
}

#[test]
Expand Down
13 changes: 12 additions & 1 deletion include/evmc/evmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ enum evmc_call_kind
The value param ignored. */
EVMC_CALLCODE = 2, /**< Request CALLCODE. */
EVMC_CREATE = 3, /**< Request CREATE. */
EVMC_CREATE2 = 4 /**< Request CREATE2. Valid since Constantinople.*/
EVMC_CREATE2 = 4, /**< Request CREATE2. Valid since Constantinople.*/
EVMC_EOFCREATE = 5 /**< Request EOFCREATE. Valid since Prague.*/
};

/** The flags for ::evmc_message. */
Expand Down Expand Up @@ -187,6 +188,16 @@ struct evmc_message
* Defined as `c` in the Yellow Paper.
*/
evmc_address code_address;

/**
* The code to be executed.
*/
const uint8_t* code;

/**
* The length of the code to be executed.
*/
size_t code_size;
};


Expand Down
8 changes: 6 additions & 2 deletions tools/vmtester/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ TEST_F(evmc_vm_test, execute_create)
0,
evmc_uint256be{},
evmc_bytes32{},
evmc_address{}};
evmc_address{},
nullptr,
0};
std::array<uint8_t, 2> code = {{0xfe, 0x00}};

const evmc_result result =
Expand Down Expand Up @@ -188,7 +190,9 @@ TEST_F(evmc_vm_test, precompile_test)
0,
evmc_uint256be{},
evmc_bytes32{},
addr};
addr,
nullptr,
0};

const evmc_result result =
vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);
Expand Down