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 method name to execution message and call syscall #112

Merged
merged 16 commits into from
Oct 4, 2024
Merged
18 changes: 14 additions & 4 deletions core/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ pub mod tests {
.symbol_table
.get("athexp_spawn")
.unwrap(),
&2103440
&2103464
);
assert_eq!(
runtime
Expand All @@ -898,7 +898,7 @@ pub mod tests {
.symbol_table
.get("athexp_send")
.unwrap(),
&2103492
&2103516
);

// now attempt to execute each function in turn
Expand Down Expand Up @@ -1115,8 +1115,18 @@ pub mod tests {
Instruction::new(Opcode::ADD, Register::X12 as u32, 0, 0, false, true),
);
instructions.push(
// X13 is arg4 (value ptr)
Instruction::new(Opcode::ADD, Register::X13 as u32, 0, memloc2, false, true),
// X13 is arg4 (ptr to method name)
// zero pointer
Instruction::new(Opcode::ADD, Register::X13 as u32, 0, 0, false, true),
);
instructions.push(
// X14 is arg5 (method name len)
// no input
Instruction::new(Opcode::ADD, Register::X14 as u32, 0, 0, false, true),
);
instructions.push(
// X15 is arg6 (value ptr)
Instruction::new(Opcode::ADD, Register::X15 as u32, 0, memloc2, false, true),
);
instructions.push(
// X5 is syscall ID
Expand Down
36 changes: 31 additions & 5 deletions core/src/syscall/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@ impl Syscall for SyscallHostWrite {

/// SyscallHostCall performs a host call, calling other programs.
/// Inputs:
/// - a0: address to call
/// - a1: address of input (bytes) to pass to the called program
/// - a2: length of input (bytes)
/// - a3: address to read the amount from (2 words, 8 bytes)
/// - a0 (arg1): address to call
/// - a1 (arg2): pointer to input (bytes) to pass to the called program
/// - a2 (x12): length of input (bytes)
/// - a3 (x13): pointer to method name (bytes) to call
/// - a4 (x14): length of method name (bytes)
/// - a5 (x15): address to read the amount from (2 words, 8 bytes)
pub(crate) struct SyscallHostCall;

impl Syscall for SyscallHostCall {
Expand Down Expand Up @@ -111,7 +113,30 @@ impl Syscall for SyscallHostCall {
None
};

let amount_ptr = ctx.rt.register(Register::X13);
// read the method name from the next register
let len = ctx.rt.register(Register::X14) as usize;
if len % 4 != 0 {
log::debug!("host system call input (a4/x14) not aligned to 4 bytes");
return Err(StatusCode::InvalidSyscallArgument);
}

let method_name_ptr = ctx.rt.register(Register::X13);

// `len` is denominated in number of bytes; we read words in chunks of four bytes
// then convert into a byte array.
let method = if len > 0 {
let words = ctx.slice(method_name_ptr, len / 4);
Some(
words
.into_iter()
.flat_map(|word| word.to_le_bytes())
.collect(),
)
} else {
None
};

let amount_ptr = ctx.rt.register(Register::X15);
let amount = ctx.dword(amount_ptr);

// note: host is responsible for checking balance and stack depth
Expand All @@ -124,6 +149,7 @@ impl Syscall for SyscallHostCall {
address.into(),
*athena_ctx.address(),
input,
method,
amount,
Vec::new(),
);
Expand Down
Binary file modified examples/wallet/program/elf/wallet-template
Binary file not shown.
2 changes: 1 addition & 1 deletion examples/wallet/program/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl WalletProgram for Wallet {
fn send(&self, send_arguments: SendArguments) {
// Send coins
// Note: error checking happens inside the host
call(send_arguments.recipient, None, send_arguments.amount);
call(send_arguments.recipient, None, None, send_arguments.amount);
}

fn proxy(&self, _destination: Address, _args: &[u8]) {
Expand Down
8 changes: 8 additions & 0 deletions ffi/athcon/bindings/go/athcon.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ func (vm *VM) Execute(
gas int64,
recipient, sender Address,
input []byte,
method []byte,
value Bytes32,
code []byte,
) (res Result, err error) {
Expand All @@ -194,6 +195,13 @@ func (vm *VM) Execute(
msg.input_data = (*C.uchar)(cInputData)
msg.input_size = C.size_t(len(input))
}
if len(method) > 0 {
// Allocate memory for method name in C.
cMethodName := C.CBytes(method)
defer C.free(cMethodName)
msg.method_name = (*C.uchar)(cMethodName)
msg.method_name_size = C.size_t(len(method))
}

ctxHandle := cgo.NewHandle(ctx)

Expand Down
2 changes: 1 addition & 1 deletion ffi/athcon/bindings/go/athcon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestExecuteEmptyCode(t *testing.T) {

addr := Address{}
h := Bytes32{}
result, err := vm.Execute(nil, Frontier, Call, 1, 999, addr, addr, nil, h, nil)
result, err := vm.Execute(nil, Frontier, Call, 1, 999, addr, addr, nil, nil, h, nil)

require.Error(t, err)
require.Empty(t, result.Output)
Expand Down
6 changes: 3 additions & 3 deletions ffi/athcon/bindings/go/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestGetBalance(t *testing.T) {
host := &testHostContext{}
addr := Address{}
h := Bytes32{}
result, err := vm.Execute(host, Frontier, Call, 1, 100, addr, addr, nil, h, MINIMAL_TEST_CODE)
result, err := vm.Execute(host, Frontier, Call, 1, 100, addr, addr, nil, nil, h, MINIMAL_TEST_CODE)
output := result.Output
gasLeft := result.GasLeft

Expand Down Expand Up @@ -98,14 +98,14 @@ func TestCall(t *testing.T) {
host := &testHostContext{}
addr := Address{}
h := Bytes32{}
result, err := vm.Execute(host, Frontier, Call, 1, 10000, addr, addr, []byte{2, 0, 0, 0}, h, RECURSIVE_CALL_TEST)
result, err := vm.Execute(host, Frontier, Call, 1, 10000, addr, addr, []byte{2, 0, 0, 0}, nil, h, RECURSIVE_CALL_TEST)
output := result.Output
gasLeft := result.GasLeft

if len(output) != 4 {
t.Errorf("execution unexpected output length: %d", len(output))
}
if gasLeft != 6604 {
if gasLeft != 5204 {
t.Errorf("execution gas left is incorrect: %d", gasLeft)
}
if err != nil {
Expand Down
12 changes: 11 additions & 1 deletion ffi/athcon/bindings/rust/athcon-client/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub trait HostContext {
sender: &Address,
value: &Bytes32,
input: &Bytes,
method: &Bytes,
gas: i64,
depth: i32,
) -> (Vec<u8>, i64, Address, StatusCode);
Expand Down Expand Up @@ -161,7 +162,16 @@ pub unsafe extern "C" fn call(
&msg.recipient.bytes,
&msg.sender.bytes,
&msg.value.bytes,
std::slice::from_raw_parts(msg.input_data, msg.input_size),
if !msg.input_data.is_null() && msg.input_size > 0 {
std::slice::from_raw_parts(msg.input_data, msg.input_size)
} else {
&[]
},
if !msg.method_name.is_null() && msg.method_name_size > 0 {
std::slice::from_raw_parts(msg.method_name, msg.method_name_size)
} else {
&[]
},
msg.gas,
msg.depth,
);
Expand Down
11 changes: 9 additions & 2 deletions ffi/athcon/bindings/rust/athcon-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl AthconVm {
destination: &Address,
sender: &Address,
input: &[u8],
method: &[u8],
value: &[u8; 32],
code: &[u8],
) -> (Vec<u8>, i64, StatusCode) {
Expand All @@ -67,6 +68,8 @@ impl AthconVm {
sender: ffi::athcon_address { bytes: *sender },
input_data: input.as_ptr(),
input_size: input.len(),
method_name: method.as_ptr(),
method_name_size: method.len(),
value: ffi::athcon_uint256be { bytes: *value },
code: code.as_ptr(),
code_size: code.len(),
Expand All @@ -84,8 +87,12 @@ impl AthconVm {
code.as_ptr(),
code.len(),
);
let data = std::slice::from_raw_parts(result.output_data, result.output_size);
let output = data.to_vec();
let output = if !result.output_data.is_null() && result.output_size > 0 {
let data = std::slice::from_raw_parts(result.output_data, result.output_size);
data.to_vec()
} else {
Vec::new()
};
if let Some(release) = result.release {
release(&result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl HostInterface for HostContext {
sender: &Address,
value: &Bytes32,
input: &Bytes,
method: &Bytes,
gas: i64,
depth: i32,
) -> (Vec<u8>, i64, Address, StatusCode) {
Expand Down Expand Up @@ -114,6 +115,7 @@ impl HostInterface for HostContext {
destination,
sender,
input,
method,
value,
CONTRACT_CODE,
);
Expand Down Expand Up @@ -157,6 +159,8 @@ fn test_rust_host() {
&[128u8; ADDRESS_LENGTH],
// the value 3 as little-endian u32
3u32.to_le_bytes().as_slice(),
// empty method name
&[],
&[0u8; BYTES32_LENGTH],
CONTRACT_CODE,
);
Expand Down
2 changes: 2 additions & 0 deletions ffi/athcon/bindings/rust/athcon-vm/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ mod tests {
sender: ::athcon_sys::athcon_address::default(),
input_data: std::ptr::null(),
input_size: 0,
method_name: std::ptr::null(),
method_name_size: 0,
value: ::athcon_sys::athcon_uint256be::default(),
code: std::ptr::null(),
code_size: 0,
Expand Down
Loading
Loading