diff --git a/Cargo.lock b/Cargo.lock index 1205f903867..e06d3358c5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3750,6 +3750,7 @@ dependencies = [ "gear-core", "gear-core-errors", "gear-sandbox", + "gear-sandbox-env", "gear-wasm-instrument", "gsys", "log", @@ -4180,6 +4181,7 @@ dependencies = [ "parity-scale-codec", "sp-core 7.0.0 (git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox)", "sp-std 5.0.0 (git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox)", + "sp-wasm-interface 7.0.0 (git+https://github.com/gear-tech/substrate.git?branch=gear-polkadot-v0.9.41-canary-no-sandbox)", ] [[package]] diff --git a/core-backend/codegen/src/host.rs b/core-backend/codegen/src/host.rs index e19eab19dbb..dca9b91ff5b 100644 --- a/core-backend/codegen/src/host.rs +++ b/core-backend/codegen/src/host.rs @@ -122,14 +122,14 @@ impl HostFn { let run: Expr = match self.meta.call_type { CallType::Any => { parse_quote! { - ctx.run_any(#cost, |ctx| { + ctx.run_any(gas, allowance, #cost, |ctx| { #inner_block }) } } CallType::Fallible => { parse_quote! { - ctx.run_fallible::<_, _, #err>(err_mid_ptr, #cost, |ctx| { + ctx.run_fallible::<_, _, #err>(gas, allowance, err_mid_ptr, #cost, |ctx| { #inner_block }) } diff --git a/core-backend/common/src/funcs.rs b/core-backend/common/src/funcs.rs index 40030fe5728..927fe723edf 100644 --- a/core-backend/common/src/funcs.rs +++ b/core-backend/common/src/funcs.rs @@ -18,6 +18,8 @@ //! Syscall implementations generic over wasmi and sandbox backends. +#![allow(clippy::too_many_arguments)] + use crate::{ memory::{MemoryAccessError, WasmMemoryRead}, runtime::{RunFallibleError, Runtime}, @@ -79,11 +81,13 @@ where #[host(fallible, wgas, cost = RuntimeCosts::Send(len))] pub fn send( ctx: &mut R, + gas: u64, + allowance: u64, pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_hash_val = ctx.register_read_as(pid_value_ptr); let read_payload = ctx.register_read(payload_ptr, len); let HashWithValue { @@ -100,10 +104,12 @@ where #[host(fallible, wgas, cost = RuntimeCosts::SendCommit)] pub fn send_commit( ctx: &mut R, + gas: u64, + allowance: u64, handle: u32, pid_value_ptr: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_pid_value = ctx.register_read_as(pid_value_ptr); let HashWithValue { hash: destination, @@ -120,12 +126,19 @@ where } #[host(fallible, cost = RuntimeCosts::SendInit, err = ErrorWithHandle)] - pub fn send_init(ctx: &mut R) -> Result<(), R::Error> { + pub fn send_init(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().send_init().map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::SendPush(len), err = ErrorBytes)] - pub fn send_push(ctx: &mut R, handle: u32, payload_ptr: u32, len: u32) -> Result<(), R::Error> { + pub fn send_push( + ctx: &mut R, + gas: u64, + allowance: u64, + handle: u32, + payload_ptr: u32, + len: u32, + ) -> Result<((), u64, u64), R::Error> { let read_payload = ctx.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -137,11 +150,13 @@ where #[host(fallible, cost = RuntimeCosts::ReservationSend(len))] pub fn reservation_send( ctx: &mut R, + gas: u64, + allowance: u64, rid_pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_rid_pid_value = ctx.register_read_as(rid_pid_value_ptr); let read_payload = ctx.register_read(payload_ptr, len); let TwoHashesWithValue { @@ -163,10 +178,12 @@ where #[host(fallible, cost = RuntimeCosts::ReservationSendCommit)] pub fn reservation_send_commit( ctx: &mut R, + gas: u64, + allowance: u64, handle: u32, rid_pid_value_ptr: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_rid_pid_value = ctx.register_read_as(rid_pid_value_ptr); let TwoHashesWithValue { hash1: reservation_id, @@ -185,7 +202,14 @@ where } #[host(fallible, cost = RuntimeCosts::Read, err = ErrorBytes)] - pub fn read(ctx: &mut R, at: u32, len: u32, buffer_ptr: u32) -> Result<(), R::Error> { + pub fn read( + ctx: &mut R, + gas: u64, + allowance: u64, + at: u32, + len: u32, + buffer_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let payload_lock = ctx.ext_mut().lock_payload(at, len)?; payload_lock .drop_with::(|payload_access| { @@ -200,7 +224,12 @@ where } #[host(cost = RuntimeCosts::Size)] - pub fn size(ctx: &mut R, size_ptr: u32) -> Result<(), R::Error> { + pub fn size( + ctx: &mut R, + gas: u64, + allowance: u64, + size_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let size = ctx.ext_mut().size()? as u32; let write_size = ctx.register_write_as(size_ptr); @@ -209,14 +238,19 @@ where } #[host(cost = RuntimeCosts::Exit)] - pub fn exit(ctx: &mut R, inheritor_id_ptr: u32) -> Result<(), R::Error> { + pub fn exit( + ctx: &mut R, + gas: u64, + allowance: u64, + inheritor_id_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_inheritor_id = ctx.register_read_decoded(inheritor_id_ptr); let inheritor_id = ctx.read_decoded(read_inheritor_id)?; Err(ActorTerminationReason::Exit(inheritor_id).into()) } #[host(fallible, cost = RuntimeCosts::ReplyCode, err = ErrorWithReplyCode)] - pub fn reply_code(ctx: &mut R) -> Result<(), R::Error> { + pub fn reply_code(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut() .reply_code() .map(ReplyCode::to_bytes) @@ -225,7 +259,7 @@ where // TODO: write proper benchmark #2825 #[host(fallible, cost = RuntimeCosts::ReplyCode, err = ErrorWithSignalCode)] - pub fn signal_code(ctx: &mut R) -> Result<(), R::Error> { + pub fn signal_code(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut() .signal_code() .map(SignalCode::to_u32) @@ -233,7 +267,12 @@ where } #[host(cost = RuntimeCosts::Alloc(pages))] - pub fn alloc(ctx: &mut R, pages: u32) -> Result { + pub fn alloc( + ctx: &mut R, + gas: u64, + allowance: u64, + pages: u32, + ) -> Result<(u32, u64, u64), R::Error> { let res = ctx.alloc(pages); let res = ctx.process_alloc_func_result(res)?; @@ -251,7 +290,12 @@ where } #[host(cost = RuntimeCosts::Free)] - pub fn free(ctx: &mut R, page_no: u32) -> Result { + pub fn free( + ctx: &mut R, + gas: u64, + allowance: u64, + page_no: u32, + ) -> Result<(i32, u64, u64), R::Error> { let page = WasmPage::new(page_no).map_err(|_| { TerminationReason::Actor(ActorTerminationReason::Trap(TrapExplanation::Unknown)) })?; @@ -272,7 +316,12 @@ where } #[host(cost = RuntimeCosts::BlockHeight)] - pub fn block_height(ctx: &mut R, height_ptr: u32) -> Result<(), R::Error> { + pub fn block_height( + ctx: &mut R, + gas: u64, + allowance: u64, + height_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let height = ctx.ext_mut().block_height()?; let write_height = ctx.register_write_as(height_ptr); @@ -281,7 +330,12 @@ where } #[host(cost = RuntimeCosts::BlockTimestamp)] - pub fn block_timestamp(ctx: &mut R, timestamp_ptr: u32) -> Result<(), R::Error> { + pub fn block_timestamp( + ctx: &mut R, + gas: u64, + allowance: u64, + timestamp_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let timestamp = ctx.ext_mut().block_timestamp()?; let write_timestamp = ctx.register_write_as(timestamp_ptr); @@ -290,7 +344,13 @@ where } #[host(cost = RuntimeCosts::Random)] - pub fn random(ctx: &mut R, subject_ptr: u32, bn_random_ptr: u32) -> Result<(), R::Error> { + pub fn random( + ctx: &mut R, + gas: u64, + allowance: u64, + subject_ptr: u32, + bn_random_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_subject = ctx.register_read_decoded(subject_ptr); let write_bn_random = ctx.register_write_as(bn_random_ptr); @@ -307,7 +367,14 @@ where } #[host(fallible, wgas, cost = RuntimeCosts::Reply(len))] - pub fn reply(ctx: &mut R, payload_ptr: u32, len: u32, value_ptr: u32) -> Result<(), R::Error> { + pub fn reply( + ctx: &mut R, + gas: u64, + allowance: u64, + payload_ptr: u32, + len: u32, + value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_payload = ctx.register_read(payload_ptr, len); let value = Self::register_and_read_value(ctx, value_ptr)?; let payload = Self::read_message_payload(ctx, read_payload)?; @@ -318,7 +385,12 @@ where } #[host(fallible, wgas, cost = RuntimeCosts::ReplyCommit)] - pub fn reply_commit(ctx: &mut R, value_ptr: u32) -> Result<(), R::Error> { + pub fn reply_commit( + ctx: &mut R, + gas: u64, + allowance: u64, + value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let value = Self::register_and_read_value(ctx, value_ptr)?; ctx.ext_mut() @@ -329,10 +401,12 @@ where #[host(fallible, cost = RuntimeCosts::ReservationReply(len))] pub fn reservation_reply( ctx: &mut R, + gas: u64, + allowance: u64, rid_value_ptr: u32, payload_ptr: u32, len: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_rid_value = ctx.register_read_as(rid_value_ptr); let read_payload = ctx.register_read(payload_ptr, len); let HashWithValue { @@ -347,7 +421,12 @@ where } #[host(fallible, cost = RuntimeCosts::ReservationReplyCommit)] - pub fn reservation_reply_commit(ctx: &mut R, rid_value_ptr: u32) -> Result<(), R::Error> { + pub fn reservation_reply_commit( + ctx: &mut R, + gas: u64, + allowance: u64, + rid_value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_rid_value = ctx.register_read_as(rid_value_ptr); let HashWithValue { hash: reservation_id, @@ -363,18 +442,24 @@ where } #[host(fallible, cost = RuntimeCosts::ReplyTo)] - pub fn reply_to(ctx: &mut R) -> Result<(), R::Error> { + pub fn reply_to(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().reply_to().map_err(Into::into) } // TODO: write proper benchmark #2825 #[host(fallible, cost = RuntimeCosts::SignalFrom)] - pub fn signal_from(ctx: &mut R) -> Result<(), R::Error> { + pub fn signal_from(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().signal_from().map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::ReplyPush(len), err = ErrorBytes)] - pub fn reply_push(ctx: &mut R, payload_ptr: u32, len: u32) -> Result<(), R::Error> { + pub fn reply_push( + ctx: &mut R, + gas: u64, + allowance: u64, + payload_ptr: u32, + len: u32, + ) -> Result<((), u64, u64), R::Error> { let read_payload = ctx.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -382,7 +467,14 @@ where } #[host(fallible, wgas, cost = RuntimeCosts::ReplyInput)] - pub fn reply_input(ctx: &mut R, offset: u32, len: u32, value_ptr: u32) -> Result<(), R::Error> { + pub fn reply_input( + ctx: &mut R, + gas: u64, + allowance: u64, + offset: u32, + len: u32, + value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { // Charge for `len` is inside `reply_push_input` let value = Self::register_and_read_value(ctx, value_ptr)?; @@ -396,7 +488,13 @@ where } #[host(fallible, cost = RuntimeCosts::ReplyPushInput, err = ErrorBytes)] - pub fn reply_push_input(ctx: &mut R, offset: u32, len: u32) -> Result<(), R::Error> { + pub fn reply_push_input( + ctx: &mut R, + gas: u64, + allowance: u64, + offset: u32, + len: u32, + ) -> Result<((), u64, u64), R::Error> { ctx.ext_mut() .reply_push_input(offset, len) .map_err(Into::into) @@ -405,11 +503,13 @@ where #[host(fallible, wgas, cost = RuntimeCosts::SendInput)] pub fn send_input( ctx: &mut R, + gas: u64, + allowance: u64, pid_value_ptr: u32, offset: u32, len: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { // Charge for `len` inside `send_push_input` let read_pid_value = ctx.register_read_as(pid_value_ptr); let HashWithValue { @@ -433,17 +533,25 @@ where #[host(fallible, cost = RuntimeCosts::SendPushInput, err = ErrorBytes)] pub fn send_push_input( ctx: &mut R, + gas: u64, + allowance: u64, handle: u32, offset: u32, len: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { ctx.ext_mut() .send_push_input(handle, offset, len) .map_err(Into::into) } #[host(cost = RuntimeCosts::Debug(data_len))] - pub fn debug(ctx: &mut R, data_ptr: u32, data_len: u32) -> Result<(), R::Error> { + pub fn debug( + ctx: &mut R, + gas: u64, + allowance: u64, + data_ptr: u32, + data_len: u32, + ) -> Result<((), u64, u64), R::Error> { let read_data = ctx.register_read(data_ptr, data_len); let data: RuntimeBuffer = ctx .read(read_data)? @@ -462,7 +570,13 @@ where } #[host(cost = RuntimeCosts::Null)] - pub fn panic(ctx: &mut R, data_ptr: u32, data_len: u32) -> Result<(), R::Error> { + pub fn panic( + ctx: &mut R, + gas: u64, + allowance: u64, + data_ptr: u32, + data_len: u32, + ) -> Result<((), u64, u64), R::Error> { let read_data = ctx.register_read(data_ptr, data_len); let data = ctx.read(read_data).unwrap_or_default(); @@ -472,27 +586,46 @@ where } #[host(cost = RuntimeCosts::Null)] - pub fn oom_panic(ctx: &mut R) -> Result<(), R::Error> { + pub fn oom_panic(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) } #[host(fallible, cost = RuntimeCosts::ReserveGas)] - pub fn reserve_gas(ctx: &mut R, gas: u64, duration: u32) -> Result<(), R::Error> { - ctx.ext_mut().reserve_gas(gas, duration).map_err(Into::into) + pub fn reserve_gas( + ctx: &mut R, + gas: u64, + allowance: u64, + gas_value: u64, + duration: u32, + ) -> Result<((), u64, u64), R::Error> { + ctx.ext_mut() + .reserve_gas(gas_value, duration) + .map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::ReplyDeposit, err = ErrorBytes)] - pub fn reply_deposit(ctx: &mut R, message_id_ptr: u32, gas: u64) -> Result<(), R::Error> { + pub fn reply_deposit( + ctx: &mut R, + gas: u64, + allowance: u64, + message_id_ptr: u32, + gas_value: u64, + ) -> Result<((), u64, u64), R::Error> { let read_message_id = ctx.register_read_decoded(message_id_ptr); let message_id = ctx.read_decoded(read_message_id)?; ctx.ext_mut() - .reply_deposit(message_id, gas) + .reply_deposit(message_id, gas_value) .map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::UnreserveGas, err = ErrorWithGas)] - pub fn unreserve_gas(ctx: &mut R, reservation_id_ptr: u32) -> Result<(), R::Error> { + pub fn unreserve_gas( + ctx: &mut R, + gas: u64, + allowance: u64, + reservation_id_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_reservation_id = ctx.register_read_decoded(reservation_id_ptr); let reservation_id = ctx.read_decoded(read_reservation_id)?; @@ -502,12 +635,22 @@ where } #[host(fallible, cost = RuntimeCosts::SystemReserveGas, err = ErrorBytes)] - pub fn system_reserve_gas(ctx: &mut R, gas: u64) -> Result<(), R::Error> { + pub fn system_reserve_gas( + ctx: &mut R, + gas2: u64, + allowance: u64, + gas: u64, + ) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().system_reserve_gas(gas).map_err(Into::into) } #[host(cost = RuntimeCosts::GasAvailable)] - pub fn gas_available(ctx: &mut R, gas_ptr: u32) -> Result<(), R::Error> { + pub fn gas_available( + ctx: &mut R, + gas: u64, + allowance: u64, + gas_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let gas = ctx.ext_mut().gas_available()?; let write_gas = ctx.register_write_as(gas_ptr); @@ -516,7 +659,12 @@ where } #[host(cost = RuntimeCosts::MsgId)] - pub fn message_id(ctx: &mut R, message_id_ptr: u32) -> Result<(), R::Error> { + pub fn message_id( + ctx: &mut R, + gas: u64, + allowance: u64, + message_id_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let message_id = ctx.ext_mut().message_id()?; let write_message_id = ctx.register_write_as(message_id_ptr); @@ -525,7 +673,12 @@ where } #[host(cost = RuntimeCosts::ProgramId)] - pub fn program_id(ctx: &mut R, program_id_ptr: u32) -> Result<(), R::Error> { + pub fn program_id( + ctx: &mut R, + gas: u64, + allowance: u64, + program_id_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let program_id = ctx.ext_mut().program_id()?; let write_program_id = ctx.register_write_as(program_id_ptr); @@ -534,7 +687,12 @@ where } #[host(fallible, cost = RuntimeCosts::PayProgramRent, err = ErrorWithBlockNumberAndValue)] - pub fn pay_program_rent(ctx: &mut R, rent_pid_ptr: u32) -> Result<(), R::Error> { + pub fn pay_program_rent( + ctx: &mut R, + gas: u64, + allowance: u64, + rent_pid_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let read_rent_pid = ctx.register_read_as(rent_pid_ptr); let HashWithValue { @@ -548,7 +706,12 @@ where } #[host(cost = RuntimeCosts::Source)] - pub fn source(ctx: &mut R, source_ptr: u32) -> Result<(), R::Error> { + pub fn source( + ctx: &mut R, + gas: u64, + allowance: u64, + source_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let source = ctx.ext_mut().source()?; let write_source = ctx.register_write_as(source_ptr); @@ -557,7 +720,12 @@ where } #[host(cost = RuntimeCosts::Value)] - pub fn value(ctx: &mut R, value_ptr: u32) -> Result<(), R::Error> { + pub fn value( + ctx: &mut R, + gas: u64, + allowance: u64, + value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let value = ctx.ext_mut().value()?; let write_value = ctx.register_write_as(value_ptr); @@ -566,7 +734,12 @@ where } #[host(cost = RuntimeCosts::ValueAvailable)] - pub fn value_available(ctx: &mut R, value_ptr: u32) -> Result<(), R::Error> { + pub fn value_available( + ctx: &mut R, + gas: u64, + allowance: u64, + value_ptr: u32, + ) -> Result<((), u64, u64), R::Error> { let value_available = ctx.ext_mut().value_available()?; let write_value = ctx.register_write_as(value_ptr); @@ -575,24 +748,34 @@ where } #[host(cost = RuntimeCosts::Leave)] - pub fn leave(ctx: &mut R) -> Result<(), R::Error> { + pub fn leave(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { Err(ActorTerminationReason::Leave.into()) } #[host(cost = RuntimeCosts::Wait)] - pub fn wait(ctx: &mut R) -> Result<(), R::Error> { + pub fn wait(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().wait()?; Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) } #[host(cost = RuntimeCosts::WaitFor)] - pub fn wait_for(ctx: &mut R, duration: u32) -> Result<(), R::Error> { + pub fn wait_for( + ctx: &mut R, + gas: u64, + allowance: u64, + duration: u32, + ) -> Result<((), u64, u64), R::Error> { ctx.ext_mut().wait_for(duration)?; Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) } #[host(cost = RuntimeCosts::WaitUpTo)] - pub fn wait_up_to(ctx: &mut R, duration: u32) -> Result<(), R::Error> { + pub fn wait_up_to( + ctx: &mut R, + gas: u64, + allowance: u64, + duration: u32, + ) -> Result<((), u64, u64), R::Error> { let waited_type = if ctx.ext_mut().wait_up_to(duration)? { MessageWaitedType::WaitUpToFull } else { @@ -602,7 +785,13 @@ where } #[host(fallible, cost = RuntimeCosts::Wake, err = ErrorBytes)] - pub fn wake(ctx: &mut R, message_id_ptr: u32, delay: u32) -> Result<(), R::Error> { + pub fn wake( + ctx: &mut R, + gas: u64, + allowance: u64, + message_id_ptr: u32, + delay: u32, + ) -> Result<((), u64, u64), R::Error> { let read_message_id = ctx.register_read_decoded(message_id_ptr); let message_id = ctx.read_decoded(read_message_id)?; @@ -613,13 +802,15 @@ where #[host(fallible, wgas, cost = RuntimeCosts::CreateProgram(payload_len, salt_len), err = ErrorWithTwoHashes)] pub fn create_program( ctx: &mut R, + gas: u64, + allowance: u64, cid_value_ptr: u32, salt_ptr: u32, salt_len: u32, payload_ptr: u32, payload_len: u32, delay: u32, - ) -> Result<(), R::Error> { + ) -> Result<((), u64, u64), R::Error> { let read_cid_value = ctx.register_read_as(cid_value_ptr); let read_salt = ctx.register_read(salt_ptr, salt_len); let read_payload = ctx.register_read(payload_ptr, payload_len); @@ -635,15 +826,15 @@ where .map_err(Into::into) } - pub fn forbidden(ctx: &mut R) -> Result<(), R::Error> { + pub fn forbidden(ctx: &mut R, gas: u64, allowance: u64) -> Result<((), u64, u64), R::Error> { syscall_trace!("forbidden"); - ctx.run_any(RuntimeCosts::Null, |_| { + ctx.run_any(gas, allowance, RuntimeCosts::Null, |_| { Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) }) } - pub fn out_of_gas(ctx: &mut R) -> Result<(), R::Error> { + pub fn out_of_gas(ctx: &mut R, _gas: u64, _allowance: u64) -> Result<((), u64, u64), R::Error> { syscall_trace!("out_of_gas"); ctx.set_termination_reason( @@ -653,7 +844,11 @@ where Err(R::unreachable_error()) } - pub fn out_of_allowance(ctx: &mut R) -> Result<(), R::Error> { + pub fn out_of_allowance( + ctx: &mut R, + _gas: u64, + _allowance: u64, + ) -> Result<((), u64, u64), R::Error> { syscall_trace!("out_of_allowance"); ctx.set_termination_reason(ActorTerminationReason::GasAllowanceExceeded.into()); diff --git a/core-backend/common/src/runtime.rs b/core-backend/common/src/runtime.rs index 0a6ab0e33d7..70aff3af776 100644 --- a/core-backend/common/src/runtime.rs +++ b/core-backend/common/src/runtime.rs @@ -50,16 +50,24 @@ pub trait Runtime: fn ext_mut(&mut self) -> &mut Ext; - fn run_any(&mut self, cost: RuntimeCosts, f: F) -> Result + fn run_any( + &mut self, + gas: u64, + allowance: u64, + cost: RuntimeCosts, + f: F, + ) -> Result<(T, u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result; fn run_fallible( &mut self, + gas: u64, + allowance: u64, res_ptr: u32, cost: RuntimeCosts, f: F, - ) -> Result<(), Self::Error> + ) -> Result<((), u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result, R: From> + Sized; diff --git a/core-backend/sandbox/Cargo.toml b/core-backend/sandbox/Cargo.toml index 4d9b264c6d3..9c0e6e710ef 100644 --- a/core-backend/sandbox/Cargo.toml +++ b/core-backend/sandbox/Cargo.toml @@ -13,6 +13,7 @@ gsys ={ workspace = true } gear-wasm-instrument.workspace = true gear-sandbox.workspace = true +gear-sandbox-env.workspace = true # Use max_level_debug feature to remove tracing in sys-calls by default. log.workspace = true derive_more.workspace = true diff --git a/core-backend/sandbox/src/env.rs b/core-backend/sandbox/src/env.rs index f724cea41bb..987c767d4fc 100644 --- a/core-backend/sandbox/src/env.rs +++ b/core-backend/sandbox/src/env.rs @@ -39,9 +39,10 @@ use gear_core::{ }; use gear_sandbox::{ default_executor::{EnvironmentDefinitionBuilder, Instance, Memory as DefaultExecutorMemory}, - HostError, HostFuncType, InstanceGlobals, ReturnValue, SandboxEnvironmentBuilder, + HostError, HostFuncType, InstanceGlobals, IntoValue, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory, Value, }; +use gear_sandbox_env::WasmReturnValue; use gear_wasm_instrument::{ syscalls::SysCallName::{self, *}, GLOBAL_NAME_ALLOWANCE, GLOBAL_NAME_GAS, STACK_END_EXPORT_NAME, @@ -94,16 +95,26 @@ impl TryFrom for u64 { macro_rules! wrap_common_func_internal_ret{ ($func:path, $($arg_no:expr),*) => { - |ctx, args| -> Result { - $func(ctx, $(SandboxValue(args[$arg_no]).try_into()?,)*).map(|ret| Into::::into(ret).0.into()) + |ctx, args: &[Value]| -> Result { + $func(ctx, $(SandboxValue(args[$arg_no]).try_into()?,)*) + .map(|(r, gas, allowance)| WasmReturnValue { + gas: gas as i64, + allowance: allowance as i64, + value: r.into_value().into(), + }) } } } macro_rules! wrap_common_func_internal_no_ret{ ($func:path, $($arg_no:expr),*) => { - |ctx, _args| -> Result { - $func(ctx, $(SandboxValue(_args[$arg_no]).try_into()?,)*).map(|_| ReturnValue::Unit) + |ctx, _args: &[Value]| -> Result { + $func(ctx, $(SandboxValue(_args[$arg_no]).try_into()?,)*) + .map(|(_, gas, allowance)| WasmReturnValue { + gas: gas as i64, + allowance: allowance as i64, + value: ReturnValue::Unit, + }) } } } @@ -119,6 +130,8 @@ macro_rules! wrap_common_func { ($func:path, (6) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4, 5) }; ($func:path, (7) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4, 5, 6) }; ($func:path, (8) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4, 5, 6, 7) }; + ($func:path, (9) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4, 5, 6, 7, 8) }; + ($func:path, (10) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) }; ($func:path, () -> (1)) => { wrap_common_func_internal_ret!($func,) }; ($func:path, (1) -> (1)) => { wrap_common_func_internal_ret!($func, 0) }; @@ -128,6 +141,8 @@ macro_rules! wrap_common_func { ($func:path, (5) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3, 4) }; ($func:path, (6) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3, 4, 5) }; ($func:path, (7) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3, 4, 5, 6) }; + ($func:path, (8) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3, 4, 5, 6, 7) }; + ($func:path, (9) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3, 4, 5, 6, 7, 8) }; } #[derive(Debug, derive_more::Display)] @@ -174,7 +189,7 @@ where self.env_def_builder.add_host_func( "env", name.to_str(), - wrap_common_func!(FuncsHandler::forbidden, () -> ()), + wrap_common_func!(FuncsHandler::forbidden, (2) -> ()), ); } else { self.env_def_builder.add_host_func("env", name.to_str(), f); @@ -206,63 +221,63 @@ where { #[rustfmt::skip] fn bind_funcs(builder: &mut EnvBuilder) { - builder.add_func(BlockHeight, wrap_common_func!(FuncsHandler::block_height, (1) -> ())); - builder.add_func(BlockTimestamp,wrap_common_func!(FuncsHandler::block_timestamp, (1) -> ())); - builder.add_func(CreateProgram, wrap_common_func!(FuncsHandler::create_program, (7) -> ())); - builder.add_func(CreateProgramWGas, wrap_common_func!(FuncsHandler::create_program_wgas, (8) -> ())); - builder.add_func(Debug, wrap_common_func!(FuncsHandler::debug, (2) -> ())); - builder.add_func(Panic, wrap_common_func!(FuncsHandler::panic, (2) -> ())); - builder.add_func(OomPanic, wrap_common_func!(FuncsHandler::oom_panic, () -> ())); - builder.add_func(Exit, wrap_common_func!(FuncsHandler::exit, (1) -> ())); - builder.add_func(ReplyCode, wrap_common_func!(FuncsHandler::reply_code, (1) -> ())); - builder.add_func(SignalCode, wrap_common_func!(FuncsHandler::signal_code, (1) -> ())); - builder.add_func(ReserveGas, wrap_common_func!(FuncsHandler::reserve_gas, (3) -> ())); - builder.add_func(ReplyDeposit, wrap_common_func!(FuncsHandler::reply_deposit, (3) -> ())); - builder.add_func(UnreserveGas, wrap_common_func!(FuncsHandler::unreserve_gas, (2) -> ())); - builder.add_func(GasAvailable, wrap_common_func!(FuncsHandler::gas_available, (1) -> ())); - builder.add_func(Leave, wrap_common_func!(FuncsHandler::leave, () -> ())); - builder.add_func(MessageId, wrap_common_func!(FuncsHandler::message_id, (1) -> ())); - builder.add_func(PayProgramRent, wrap_common_func!(FuncsHandler::pay_program_rent, (2) -> ())); - builder.add_func(ProgramId, wrap_common_func!(FuncsHandler::program_id, (1) -> ())); - builder.add_func(Random, wrap_common_func!(FuncsHandler::random, (2) -> ())); - builder.add_func(Read, wrap_common_func!(FuncsHandler::read, (4) -> ())); - builder.add_func(Reply, wrap_common_func!(FuncsHandler::reply, (4) -> ())); - builder.add_func(ReplyCommit, wrap_common_func!(FuncsHandler::reply_commit, (2) -> ())); - builder.add_func(ReplyCommitWGas, wrap_common_func!(FuncsHandler::reply_commit_wgas, (3) -> ())); - builder.add_func(ReplyPush, wrap_common_func!(FuncsHandler::reply_push, (3) -> ())); - builder.add_func(ReplyTo, wrap_common_func!(FuncsHandler::reply_to, (1) -> ())); - builder.add_func(SignalFrom, wrap_common_func!(FuncsHandler::signal_from, (1) -> ())); - builder.add_func(ReplyWGas, wrap_common_func!(FuncsHandler::reply_wgas, (5) -> ())); - builder.add_func(ReplyInput, wrap_common_func!(FuncsHandler::reply_input, (4) -> ())); - builder.add_func(ReplyPushInput, wrap_common_func!(FuncsHandler::reply_push_input, (3) -> ())); - builder.add_func(ReplyInputWGas, wrap_common_func!(FuncsHandler::reply_input_wgas, (5) -> ())); - builder.add_func(Send, wrap_common_func!(FuncsHandler::send, (5) -> ())); - builder.add_func(SendCommit, wrap_common_func!(FuncsHandler::send_commit, (4) -> ())); - builder.add_func(SendCommitWGas, wrap_common_func!(FuncsHandler::send_commit_wgas, (5) -> ())); - builder.add_func(SendInit, wrap_common_func!(FuncsHandler::send_init, (1) -> ())); - builder.add_func(SendPush, wrap_common_func!(FuncsHandler::send_push, (4) -> ())); - builder.add_func(SendWGas, wrap_common_func!(FuncsHandler::send_wgas, (6) -> ())); - builder.add_func(SendInput, wrap_common_func!(FuncsHandler::send_input, (5) -> ())); - builder.add_func(SendPushInput, wrap_common_func!(FuncsHandler::send_push_input, (4) -> ())); - builder.add_func(SendInputWGas, wrap_common_func!(FuncsHandler::send_input_wgas, (6) -> ())); - builder.add_func(Size, wrap_common_func!(FuncsHandler::size, (1) -> ())); - builder.add_func(Source, wrap_common_func!(FuncsHandler::source, (1) -> ())); - builder.add_func(Value, wrap_common_func!(FuncsHandler::value, (1) -> ())); - builder.add_func(ValueAvailable, wrap_common_func!(FuncsHandler::value_available, (1) -> ())); - builder.add_func(Wait, wrap_common_func!(FuncsHandler::wait, () -> ())); - builder.add_func(WaitFor, wrap_common_func!(FuncsHandler::wait_for, (1) -> ())); - builder.add_func(WaitUpTo, wrap_common_func!(FuncsHandler::wait_up_to, (1) -> ())); - builder.add_func(Wake, wrap_common_func!(FuncsHandler::wake, (3) -> ())); - builder.add_func(SystemReserveGas, wrap_common_func!(FuncsHandler::system_reserve_gas, (2) -> ())); - builder.add_func(ReservationReply, wrap_common_func!(FuncsHandler::reservation_reply, (4) -> ())); - builder.add_func(ReservationReplyCommit, wrap_common_func!(FuncsHandler::reservation_reply_commit, (2) -> ())); - builder.add_func(ReservationSend, wrap_common_func!(FuncsHandler::reservation_send, (5) -> ())); - builder.add_func(ReservationSendCommit, wrap_common_func!(FuncsHandler::reservation_send_commit, (4) -> ())); - builder.add_func(OutOfGas, wrap_common_func!(FuncsHandler::out_of_gas, () -> ())); - builder.add_func(OutOfAllowance, wrap_common_func!(FuncsHandler::out_of_allowance, () -> ())); - - builder.add_func(Alloc, wrap_common_func!(FuncsHandler::alloc, (1) -> (1))); - builder.add_func(Free, wrap_common_func!(FuncsHandler::free, (1) -> (1))); + builder.add_func(BlockHeight, wrap_common_func!(FuncsHandler::block_height, (3) -> ())); + builder.add_func(BlockTimestamp,wrap_common_func!(FuncsHandler::block_timestamp, (3) -> ())); + builder.add_func(CreateProgram, wrap_common_func!(FuncsHandler::create_program, (9) -> ())); + builder.add_func(CreateProgramWGas, wrap_common_func!(FuncsHandler::create_program_wgas, (10) -> ())); + builder.add_func(Debug, wrap_common_func!(FuncsHandler::debug, (4) -> ())); + builder.add_func(Panic, wrap_common_func!(FuncsHandler::panic, (4) -> ())); + builder.add_func(OomPanic, wrap_common_func!(FuncsHandler::oom_panic, (2) -> ())); + builder.add_func(Exit, wrap_common_func!(FuncsHandler::exit, (3) -> ())); + builder.add_func(ReplyCode, wrap_common_func!(FuncsHandler::reply_code, (3) -> ())); + builder.add_func(SignalCode, wrap_common_func!(FuncsHandler::signal_code, (3) -> ())); + builder.add_func(ReserveGas, wrap_common_func!(FuncsHandler::reserve_gas, (5) -> ())); + builder.add_func(ReplyDeposit, wrap_common_func!(FuncsHandler::reply_deposit, (5) -> ())); + builder.add_func(UnreserveGas, wrap_common_func!(FuncsHandler::unreserve_gas, (4) -> ())); + builder.add_func(GasAvailable, wrap_common_func!(FuncsHandler::gas_available, (3) -> ())); + builder.add_func(Leave, wrap_common_func!(FuncsHandler::leave, (2) -> ())); + builder.add_func(MessageId, wrap_common_func!(FuncsHandler::message_id, (3) -> ())); + builder.add_func(PayProgramRent, wrap_common_func!(FuncsHandler::pay_program_rent, (4) -> ())); + builder.add_func(ProgramId, wrap_common_func!(FuncsHandler::program_id, (3) -> ())); + builder.add_func(Random, wrap_common_func!(FuncsHandler::random, (4) -> ())); + builder.add_func(Read, wrap_common_func!(FuncsHandler::read, (6) -> ())); + builder.add_func(Reply, wrap_common_func!(FuncsHandler::reply, (6) -> ())); + builder.add_func(ReplyCommit, wrap_common_func!(FuncsHandler::reply_commit, (4) -> ())); + builder.add_func(ReplyCommitWGas, wrap_common_func!(FuncsHandler::reply_commit_wgas, (5) -> ())); + builder.add_func(ReplyPush, wrap_common_func!(FuncsHandler::reply_push, (5) -> ())); + builder.add_func(ReplyTo, wrap_common_func!(FuncsHandler::reply_to, (3) -> ())); + builder.add_func(SignalFrom, wrap_common_func!(FuncsHandler::signal_from, (3) -> ())); + builder.add_func(ReplyWGas, wrap_common_func!(FuncsHandler::reply_wgas, (7) -> ())); + builder.add_func(ReplyInput, wrap_common_func!(FuncsHandler::reply_input, (6) -> ())); + builder.add_func(ReplyPushInput, wrap_common_func!(FuncsHandler::reply_push_input, (5) -> ())); + builder.add_func(ReplyInputWGas, wrap_common_func!(FuncsHandler::reply_input_wgas, (7) -> ())); + builder.add_func(Send, wrap_common_func!(FuncsHandler::send, (7) -> ())); + builder.add_func(SendCommit, wrap_common_func!(FuncsHandler::send_commit, (6) -> ())); + builder.add_func(SendCommitWGas, wrap_common_func!(FuncsHandler::send_commit_wgas, (7) -> ())); + builder.add_func(SendInit, wrap_common_func!(FuncsHandler::send_init, (3) -> ())); + builder.add_func(SendPush, wrap_common_func!(FuncsHandler::send_push, (6) -> ())); + builder.add_func(SendWGas, wrap_common_func!(FuncsHandler::send_wgas, (8) -> ())); + builder.add_func(SendInput, wrap_common_func!(FuncsHandler::send_input, (7) -> ())); + builder.add_func(SendPushInput, wrap_common_func!(FuncsHandler::send_push_input, (6) -> ())); + builder.add_func(SendInputWGas, wrap_common_func!(FuncsHandler::send_input_wgas, (8) -> ())); + builder.add_func(Size, wrap_common_func!(FuncsHandler::size, (3) -> ())); + builder.add_func(Source, wrap_common_func!(FuncsHandler::source, (3) -> ())); + builder.add_func(Value, wrap_common_func!(FuncsHandler::value, (3) -> ())); + builder.add_func(ValueAvailable, wrap_common_func!(FuncsHandler::value_available, (3) -> ())); + builder.add_func(Wait, wrap_common_func!(FuncsHandler::wait, (2) -> ())); + builder.add_func(WaitFor, wrap_common_func!(FuncsHandler::wait_for, (3) -> ())); + builder.add_func(WaitUpTo, wrap_common_func!(FuncsHandler::wait_up_to, (3) -> ())); + builder.add_func(Wake, wrap_common_func!(FuncsHandler::wake, (5) -> ())); + builder.add_func(SystemReserveGas, wrap_common_func!(FuncsHandler::system_reserve_gas, (4) -> ())); + builder.add_func(ReservationReply, wrap_common_func!(FuncsHandler::reservation_reply, (6) -> ())); + builder.add_func(ReservationReplyCommit, wrap_common_func!(FuncsHandler::reservation_reply_commit, (4) -> ())); + builder.add_func(ReservationSend, wrap_common_func!(FuncsHandler::reservation_send, (7) -> ())); + builder.add_func(ReservationSendCommit, wrap_common_func!(FuncsHandler::reservation_send_commit, (6) -> ())); + builder.add_func(OutOfGas, wrap_common_func!(FuncsHandler::out_of_gas, (2) -> ())); + builder.add_func(OutOfAllowance, wrap_common_func!(FuncsHandler::out_of_allowance, (2) -> ())); + + builder.add_func(Alloc, wrap_common_func!(FuncsHandler::alloc, (3) -> (1))); + builder.add_func(Free, wrap_common_func!(FuncsHandler::free, (3) -> (1))); } } diff --git a/core-backend/sandbox/src/runtime.rs b/core-backend/sandbox/src/runtime.rs index 73f963ef5f6..2ee0233c428 100644 --- a/core-backend/sandbox/src/runtime.rs +++ b/core-backend/sandbox/src/runtime.rs @@ -30,8 +30,7 @@ use gear_backend_common::{ BackendExternalities, BackendState, BackendTermination, TerminationReason, }; use gear_core::{costs::RuntimeCosts, gas::GasLeft, pages::WasmPage}; -use gear_sandbox::{HostError, InstanceGlobals, Value}; -use gear_wasm_instrument::{GLOBAL_NAME_ALLOWANCE, GLOBAL_NAME_GAS}; +use gear_sandbox::{HostError, Value}; pub(crate) fn as_i64(v: Value) -> Option { match v { @@ -60,28 +59,45 @@ impl CommonRuntime for Runtime { HostError } - fn run_any(&mut self, cost: RuntimeCosts, f: F) -> Result + fn run_any( + &mut self, + gas: u64, + allowance: u64, + cost: RuntimeCosts, + f: F, + ) -> Result<(T, u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result, { - self.with_globals_update(|ctx| { - ctx.prepare_run(); - ctx.ext.charge_gas_runtime(cost)?; - f(ctx) + self.prepare_run(gas, allowance); + (|| { + self.ext.charge_gas_runtime(cost)?; + f(self) + })() + .map_err(|err| { + self.set_termination_reason(err); + HostError + }) + .map(|r| { + let GasLeft { gas, allowance } = self.ext.gas_left(); + + (r, gas, allowance) }) } fn run_fallible( &mut self, + gas: u64, + allowance: u64, res_ptr: u32, cost: RuntimeCosts, f: F, - ) -> Result<(), Self::Error> + ) -> Result<((), u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result, R: From> + Sized, { - self.run_any(cost, |ctx| { + self.run_any(gas, allowance, cost, |ctx| { let res = f(ctx); let res = ctx.process_fallible_func_result(res)?; @@ -90,7 +106,6 @@ impl CommonRuntime for Runtime { ctx.write_as(write_res, R::from(res)).map_err(Into::into) }) - .map(|_| ()) } fn alloc(&mut self, pages: u32) -> Result::AllocError> { @@ -100,55 +115,12 @@ impl CommonRuntime for Runtime { impl Runtime { // Cleans `memory_manager`, updates ext counters based on globals. - fn prepare_run(&mut self) { + fn prepare_run(&mut self, gas: u64, allowance: u64) { self.memory_manager = Default::default(); - let gas = self - .globals - .get_global_val(GLOBAL_NAME_GAS) - .and_then(as_i64) - .unwrap_or_else(|| unreachable!("Globals must be checked during env creation")); - - let allowance = self - .globals - .get_global_val(GLOBAL_NAME_ALLOWANCE) - .and_then(as_i64) - .unwrap_or_else(|| unreachable!("Globals must be checked during env creation")); - self.ext.set_gas_left((gas, allowance).into()); } - // Updates globals after execution. - fn update_globals(&mut self) { - let GasLeft { gas, allowance } = self.ext.gas_left(); - - self.globals - .set_global_val(GLOBAL_NAME_GAS, Value::I64(gas as i64)) - .unwrap_or_else(|e| { - unreachable!("Globals must be checked during env creation: {:?}", e) - }); - - self.globals - .set_global_val(GLOBAL_NAME_ALLOWANCE, Value::I64(allowance as i64)) - .unwrap_or_else(|e| { - unreachable!("Globals must be checked during env creation: {:?}", e) - }); - } - - fn with_globals_update(&mut self, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - { - let result = f(self).map_err(|err| { - self.set_termination_reason(err); - HostError - }); - - self.update_globals(); - - result - } - fn with_memory(&mut self, f: F) -> Result where F: FnOnce( diff --git a/core-backend/wasmi/src/funcs_tree.rs b/core-backend/wasmi/src/funcs_tree.rs index bb3f020afc7..1b7817581e8 100644 --- a/core-backend/wasmi/src/funcs_tree.rs +++ b/core-backend/wasmi/src/funcs_tree.rs @@ -46,7 +46,7 @@ macro_rules! wrap_common_func_internal_ret { let func = move |caller: Caller<'_, HostState>, $($arg_name,)*| -> Result<(_, ), Trap> { let mut ctx = CallerWrap::prepare(caller, forbidden, memory)?; - $func(&mut ctx, $($arg_name,)*).map(|ret| (ret,)) + $func(&mut ctx, $($arg_name,)*).map(|(r, ..)| (r,)) }; Func::wrap(store, func) } @@ -60,6 +60,7 @@ macro_rules! wrap_common_func_internal_no_ret { { let mut ctx = CallerWrap::prepare(caller, forbidden, memory)?; $func(&mut ctx, $($arg_name,)*) + .map(|(r, ..)| r) }; Func::wrap(store, func) } @@ -77,6 +78,8 @@ macro_rules! wrap_common_func { ($func:path, (6) -> ()) => { wrap_common_func_internal_no_ret!($func, a, b, c, d, e, f) }; ($func:path, (7) -> ()) => { wrap_common_func_internal_no_ret!($func, a, b, c, d, e, f, g) }; ($func:path, (8) -> ()) => { wrap_common_func_internal_no_ret!($func, a, b, c, d, e, f, g, h) }; + ($func:path, (9) -> ()) => { wrap_common_func_internal_no_ret!($func, a, b, c, d, e, f, g, h, i) }; + ($func:path, (10) -> ()) => { wrap_common_func_internal_no_ret!($func, a, b, c, d, e, f, g, h, i, j) }; ($func:path, () -> (1)) => { wrap_common_func_internal_ret!($func,)}; ($func:path, (1) -> (1)) => { wrap_common_func_internal_ret!($func, a)}; @@ -87,6 +90,8 @@ macro_rules! wrap_common_func { ($func:path, (6) -> (1)) => { wrap_common_func_internal_ret!($func, a, b, c, d, e, f)}; ($func:path, (7) -> (1)) => { wrap_common_func_internal_ret!($func, a, b, c, d, e, f, g)}; ($func:path, (8) -> (1)) => { wrap_common_func_internal_ret!($func, a, b, c, d, e, f, g, h)}; + ($func:path, (9) -> (1)) => { wrap_common_func_internal_ret!($func, a, b, c, d, e, f, g, h, i)}; + ($func:path, (10) -> (1)) => { wrap_common_func_internal_ret!($func, a, b, c, d, e, f, g, h, i, j)}; } pub(crate) fn build( @@ -104,62 +109,62 @@ where #[rustfmt::skip] let funcs: BTreeMap<_, _> = [ - f.build(Send, |forbidden| wrap_common_func!(CommonFuncsHandler::send, (5) -> ())(store, forbidden, memory)), - f.build(SendWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_wgas, (6) -> ())(store, forbidden, memory)), - f.build(SendCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::send_commit, (4) -> ())(store, forbidden, memory)), - f.build(SendCommitWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_commit_wgas, (5) -> ())(store, forbidden, memory)), - f.build(SendInit, |forbidden| wrap_common_func!(CommonFuncsHandler::send_init, (1) -> ())(store, forbidden, memory)), - f.build(SendPush, |forbidden| wrap_common_func!(CommonFuncsHandler::send_push, (4) -> ())(store, forbidden, memory)), - f.build(Read, |forbidden| wrap_common_func!(CommonFuncsHandler::read, (4) -> ())(store, forbidden, memory)), - f.build(Size, |forbidden| wrap_common_func!(CommonFuncsHandler::size, (1) -> ())(store, forbidden, memory)), - f.build(Exit, |forbidden| wrap_common_func!(CommonFuncsHandler::exit, (1) -> ())(store, forbidden, memory)), - f.build(ReplyCode, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_code, (1) -> ())(store, forbidden, memory)), - f.build(SignalCode, |forbidden| wrap_common_func!(CommonFuncsHandler::signal_code, (1) -> ())(store, forbidden, memory)), - f.build(Alloc, |forbidden| wrap_common_func!(CommonFuncsHandler::alloc, (1) -> (1))(store, forbidden, memory)), - f.build(Free, |forbidden| wrap_common_func!(CommonFuncsHandler::free, (1) -> (1))(store, forbidden, memory)), - f.build(BlockHeight, |forbidden| wrap_common_func!(CommonFuncsHandler::block_height, (1) -> ())(store, forbidden, memory)), - f.build(BlockTimestamp, |forbidden| wrap_common_func!(CommonFuncsHandler::block_timestamp, (1) -> ())(store, forbidden, memory)), - f.build(ReservationSend, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_send, (5) -> ())(store, forbidden, memory)), - f.build(ReservationSendCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_send_commit, (4) -> ())(store, forbidden, memory)), - f.build(Reply, |forbidden| wrap_common_func!(CommonFuncsHandler::reply, (4) -> ())(store, forbidden, memory)), - f.build(ReplyWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_wgas, (5) -> ())(store, forbidden, memory)), - f.build(ReplyCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_commit, (2) -> ())(store, forbidden, memory)), - f.build(ReplyCommitWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_commit_wgas, (3) -> ())(store, forbidden, memory)), - f.build(ReplyTo, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_to, (1) -> ())(store, forbidden, memory)), - f.build(SignalFrom, |forbidden| wrap_common_func!(CommonFuncsHandler::signal_from, (1) -> ())(store, forbidden, memory)), - f.build(ReplyPush, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_push, (3) -> ())(store, forbidden, memory)), - f.build(ReplyInput, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_input, (4) -> ())(store, forbidden, memory)), - f.build(ReplyPushInput, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_push_input, (3) -> ())(store, forbidden, memory)), - f.build(ReplyInputWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_input_wgas, (5) -> ())(store, forbidden, memory)), - f.build(SendInput, |forbidden| wrap_common_func!(CommonFuncsHandler::send_input, (5) -> ())(store, forbidden, memory)), - f.build(SendPushInput, |forbidden| wrap_common_func!(CommonFuncsHandler::send_push_input, (4) -> ())(store, forbidden, memory)), - f.build(SendInputWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_input_wgas, (6) -> ())(store, forbidden, memory)), - f.build(Debug, |forbidden| wrap_common_func!(CommonFuncsHandler::debug, (2) -> ())(store, forbidden, memory)), - f.build(Panic, |forbidden| wrap_common_func!(CommonFuncsHandler::panic, (2) -> ())(store, forbidden, memory)), - f.build(OomPanic, |forbidden| wrap_common_func!(CommonFuncsHandler::oom_panic, () -> ())(store, forbidden, memory)), - f.build(GasAvailable, |forbidden| wrap_common_func!(CommonFuncsHandler::gas_available, (1) -> ())(store, forbidden, memory)), - f.build(MessageId, |forbidden| wrap_common_func!(CommonFuncsHandler::message_id, (1) -> ())(store, forbidden, memory)), - f.build(ReservationReply, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_reply, (4) -> ())(store, forbidden, memory)), - f.build(ReservationReplyCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_reply_commit, (2) -> ())(store, forbidden, memory)), - f.build(PayProgramRent, |forbidden| wrap_common_func!(CommonFuncsHandler::pay_program_rent, (2) -> ())(store, forbidden, memory)), - f.build(ProgramId, |forbidden| wrap_common_func!(CommonFuncsHandler::program_id, (1) -> ())(store, forbidden, memory)), - f.build(Source, |forbidden| wrap_common_func!(CommonFuncsHandler::source, (1) -> ())(store, forbidden, memory)), - f.build(Value, |forbidden| wrap_common_func!(CommonFuncsHandler::value, (1) -> ())(store, forbidden, memory)), - f.build(ValueAvailable, |forbidden| wrap_common_func!(CommonFuncsHandler::value_available, (1) -> ())(store, forbidden, memory)), - f.build(Random, |forbidden| wrap_common_func!(CommonFuncsHandler::random, (2) -> ())(store, forbidden, memory)), - f.build(Leave, |forbidden| wrap_common_func!(CommonFuncsHandler::leave, () -> ())(store, forbidden, memory)), - f.build(Wait, |forbidden| wrap_common_func!(CommonFuncsHandler::wait, () -> ())(store, forbidden, memory)), - f.build(WaitFor, |forbidden| wrap_common_func!(CommonFuncsHandler::wait_for, (1) -> ())(store, forbidden, memory)), - f.build(WaitUpTo, |forbidden| wrap_common_func!(CommonFuncsHandler::wait_up_to, (1) -> ())(store, forbidden, memory)), - f.build(Wake, |forbidden| wrap_common_func!(CommonFuncsHandler::wake, (3) -> ())(store, forbidden, memory)), - f.build(CreateProgram, |forbidden| wrap_common_func!(CommonFuncsHandler::create_program, (7) -> ())(store, forbidden, memory)), - f.build(CreateProgramWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::create_program_wgas, (8) -> ())(store, forbidden, memory)), - f.build(ReserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reserve_gas, (3) -> ())(store, forbidden, memory)), - f.build(ReplyDeposit, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_deposit, (3) -> ())(store, forbidden, memory)), - f.build(UnreserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::unreserve_gas, (2) -> ())(store, forbidden, memory)), - f.build(OutOfGas, |_| wrap_common_func!(CommonFuncsHandler::out_of_gas, () -> ())(store, false, memory)), - f.build(OutOfAllowance, |_| wrap_common_func!(CommonFuncsHandler::out_of_allowance, () -> ())(store, false, memory)), - f.build(SystemReserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::system_reserve_gas, (2) -> ())(store, forbidden, memory)), + f.build(Send, |forbidden| wrap_common_func!(CommonFuncsHandler::send, (7) -> ())(store, forbidden, memory)), + f.build(SendWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_wgas, (8) -> ())(store, forbidden, memory)), + f.build(SendCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::send_commit, (6) -> ())(store, forbidden, memory)), + f.build(SendCommitWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_commit_wgas, (7) -> ())(store, forbidden, memory)), + f.build(SendInit, |forbidden| wrap_common_func!(CommonFuncsHandler::send_init, (3) -> ())(store, forbidden, memory)), + f.build(SendPush, |forbidden| wrap_common_func!(CommonFuncsHandler::send_push, (6) -> ())(store, forbidden, memory)), + f.build(Read, |forbidden| wrap_common_func!(CommonFuncsHandler::read, (6) -> ())(store, forbidden, memory)), + f.build(Size, |forbidden| wrap_common_func!(CommonFuncsHandler::size, (3) -> ())(store, forbidden, memory)), + f.build(Exit, |forbidden| wrap_common_func!(CommonFuncsHandler::exit, (3) -> ())(store, forbidden, memory)), + f.build(ReplyCode, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_code, (3) -> ())(store, forbidden, memory)), + f.build(SignalCode, |forbidden| wrap_common_func!(CommonFuncsHandler::signal_code, (3) -> ())(store, forbidden, memory)), + f.build(Alloc, |forbidden| wrap_common_func!(CommonFuncsHandler::alloc, (3) -> (1))(store, forbidden, memory)), + f.build(Free, |forbidden| wrap_common_func!(CommonFuncsHandler::free, (3) -> (1))(store, forbidden, memory)), + f.build(BlockHeight, |forbidden| wrap_common_func!(CommonFuncsHandler::block_height, (3) -> ())(store, forbidden, memory)), + f.build(BlockTimestamp, |forbidden| wrap_common_func!(CommonFuncsHandler::block_timestamp, (3) -> ())(store, forbidden, memory)), + f.build(ReservationSend, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_send, (7) -> ())(store, forbidden, memory)), + f.build(ReservationSendCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_send_commit, (6) -> ())(store, forbidden, memory)), + f.build(Reply, |forbidden| wrap_common_func!(CommonFuncsHandler::reply, (6) -> ())(store, forbidden, memory)), + f.build(ReplyWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_wgas, (7) -> ())(store, forbidden, memory)), + f.build(ReplyCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_commit, (4) -> ())(store, forbidden, memory)), + f.build(ReplyCommitWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_commit_wgas, (5) -> ())(store, forbidden, memory)), + f.build(ReplyTo, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_to, (3) -> ())(store, forbidden, memory)), + f.build(SignalFrom, |forbidden| wrap_common_func!(CommonFuncsHandler::signal_from, (3) -> ())(store, forbidden, memory)), + f.build(ReplyPush, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_push, (5) -> ())(store, forbidden, memory)), + f.build(ReplyInput, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_input, (6) -> ())(store, forbidden, memory)), + f.build(ReplyPushInput, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_push_input, (5) -> ())(store, forbidden, memory)), + f.build(ReplyInputWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_input_wgas, (7) -> ())(store, forbidden, memory)), + f.build(SendInput, |forbidden| wrap_common_func!(CommonFuncsHandler::send_input, (7) -> ())(store, forbidden, memory)), + f.build(SendPushInput, |forbidden| wrap_common_func!(CommonFuncsHandler::send_push_input, (6) -> ())(store, forbidden, memory)), + f.build(SendInputWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::send_input_wgas, (8) -> ())(store, forbidden, memory)), + f.build(Debug, |forbidden| wrap_common_func!(CommonFuncsHandler::debug, (4) -> ())(store, forbidden, memory)), + f.build(Panic, |forbidden| wrap_common_func!(CommonFuncsHandler::panic, (4) -> ())(store, forbidden, memory)), + f.build(OomPanic, |forbidden| wrap_common_func!(CommonFuncsHandler::oom_panic, (2) -> ())(store, forbidden, memory)), + f.build(GasAvailable, |forbidden| wrap_common_func!(CommonFuncsHandler::gas_available, (3) -> ())(store, forbidden, memory)), + f.build(MessageId, |forbidden| wrap_common_func!(CommonFuncsHandler::message_id, (3) -> ())(store, forbidden, memory)), + f.build(ReservationReply, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_reply, (6) -> ())(store, forbidden, memory)), + f.build(ReservationReplyCommit, |forbidden| wrap_common_func!(CommonFuncsHandler::reservation_reply_commit, (4) -> ())(store, forbidden, memory)), + f.build(PayProgramRent, |forbidden| wrap_common_func!(CommonFuncsHandler::pay_program_rent, (4) -> ())(store, forbidden, memory)), + f.build(ProgramId, |forbidden| wrap_common_func!(CommonFuncsHandler::program_id, (3) -> ())(store, forbidden, memory)), + f.build(Source, |forbidden| wrap_common_func!(CommonFuncsHandler::source, (3) -> ())(store, forbidden, memory)), + f.build(Value, |forbidden| wrap_common_func!(CommonFuncsHandler::value, (3) -> ())(store, forbidden, memory)), + f.build(ValueAvailable, |forbidden| wrap_common_func!(CommonFuncsHandler::value_available, (3) -> ())(store, forbidden, memory)), + f.build(Random, |forbidden| wrap_common_func!(CommonFuncsHandler::random, (4) -> ())(store, forbidden, memory)), + f.build(Leave, |forbidden| wrap_common_func!(CommonFuncsHandler::leave, (2) -> ())(store, forbidden, memory)), + f.build(Wait, |forbidden| wrap_common_func!(CommonFuncsHandler::wait, (2) -> ())(store, forbidden, memory)), + f.build(WaitFor, |forbidden| wrap_common_func!(CommonFuncsHandler::wait_for, (3) -> ())(store, forbidden, memory)), + f.build(WaitUpTo, |forbidden| wrap_common_func!(CommonFuncsHandler::wait_up_to, (3) -> ())(store, forbidden, memory)), + f.build(Wake, |forbidden| wrap_common_func!(CommonFuncsHandler::wake, (5) -> ())(store, forbidden, memory)), + f.build(CreateProgram, |forbidden| wrap_common_func!(CommonFuncsHandler::create_program, (9) -> ())(store, forbidden, memory)), + f.build(CreateProgramWGas, |forbidden| wrap_common_func!(CommonFuncsHandler::create_program_wgas, (10) -> ())(store, forbidden, memory)), + f.build(ReserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::reserve_gas, (5) -> ())(store, forbidden, memory)), + f.build(ReplyDeposit, |forbidden| wrap_common_func!(CommonFuncsHandler::reply_deposit, (5) -> ())(store, forbidden, memory)), + f.build(UnreserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::unreserve_gas, (4) -> ())(store, forbidden, memory)), + f.build(OutOfGas, |_| wrap_common_func!(CommonFuncsHandler::out_of_gas, (2) -> ())(store, false, memory)), + f.build(OutOfAllowance, |_| wrap_common_func!(CommonFuncsHandler::out_of_allowance, (2) -> ())(store, false, memory)), + f.build(SystemReserveGas, |forbidden| wrap_common_func!(CommonFuncsHandler::system_reserve_gas, (4) -> ())(store, forbidden, memory)), ] .into(); diff --git a/core-backend/wasmi/src/runtime.rs b/core-backend/wasmi/src/runtime.rs index e76a8c896d2..a0dcdbba507 100644 --- a/core-backend/wasmi/src/runtime.rs +++ b/core-backend/wasmi/src/runtime.rs @@ -79,36 +79,49 @@ impl<'a, Ext: BackendExternalities + 'static> Runtime for CallerWrap<'a, Ex } #[track_caller] - fn run_any(&mut self, cost: RuntimeCosts, f: F) -> Result + fn run_any( + &mut self, + _gas: u64, + _allowance: u64, + cost: RuntimeCosts, + f: F, + ) -> Result<(T, u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result, { self.with_globals_update(|ctx| { ctx.host_state_mut().ext.charge_gas_runtime(cost)?; - f(ctx) + f(ctx).map(|r| (r, 0, 0)) }) } #[track_caller] fn run_fallible( &mut self, + gas: u64, + allowance: u64, res_ptr: u32, cost: RuntimeCosts, f: F, - ) -> Result<(), Self::Error> + ) -> Result<((), u64, u64), Self::Error> where F: FnOnce(&mut Self) -> Result, R: From> + Sized, { - self.run_any(cost, |ctx: &mut Self| -> Result<_, TerminationReason> { - let res = f(ctx); - let res = ctx.host_state_mut().process_fallible_func_result(res)?; - - // TODO: move above or make normal process memory access. - let write_res = ctx.register_write_as::(res_ptr); - - ctx.write_as(write_res, R::from(res)).map_err(Into::into) - }) + self.run_any( + gas, + allowance, + cost, + |ctx: &mut Self| -> Result<_, TerminationReason> { + let res = f(ctx); + let res = ctx.host_state_mut().process_fallible_func_result(res)?; + + // TODO: move above or make normal process memory access. + let write_res = ctx.register_write_as::(res_ptr); + + ctx.write_as(write_res, R::from(res)).map_err(Into::into) + }, + ) } fn alloc(&mut self, pages: u32) -> Result::AllocError> { diff --git a/sandbox/env/Cargo.toml b/sandbox/env/Cargo.toml index 3d9138e7321..844eaa9bc90 100644 --- a/sandbox/env/Cargo.toml +++ b/sandbox/env/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec.workspace = true sp-core.workspace = true sp-std.workspace = true +sp-wasm-interface = { workspace = true, default-features = false } [features] default = ["std"] @@ -22,4 +23,5 @@ std = [ "codec/std", "sp-core/std", "sp-std/std", + "sp-wasm-interface/std", ] diff --git a/sandbox/env/src/lib.rs b/sandbox/env/src/lib.rs index aacbcf9c3bd..ca074b93b88 100644 --- a/sandbox/env/src/lib.rs +++ b/sandbox/env/src/lib.rs @@ -21,9 +21,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; - use sp_core::RuntimeDebug; use sp_std::vec::Vec; +use sp_wasm_interface::ReturnValue; /// Error error that can be returned from host function. #[derive(Encode, Decode, RuntimeDebug)] @@ -108,6 +108,21 @@ pub const ERROR_GLOBALS_NOT_FOUND: u32 = u32::MAX; /// For FFI purposes. pub const ERROR_GLOBALS_OTHER: u32 = u32::MAX - 1; +/// Typed value that can be returned from a wasm function +/// through the dispatch thunk. +/// Additionally contains globals values. +#[derive(Clone, Copy, PartialEq, Encode, Decode, Debug)] +#[codec(crate = codec)] +pub struct WasmReturnValue { + pub gas: i64, + pub allowance: i64, + pub value: ReturnValue, +} + +impl WasmReturnValue { + pub const ENCODED_MAX_SIZE: usize = 16 + ReturnValue::ENCODED_MAX_SIZE; +} + #[cfg(test)] mod tests { use super::*; diff --git a/sandbox/host/src/sandbox/wasmer_backend.rs b/sandbox/host/src/sandbox/wasmer_backend.rs index 27c92864aef..15cddf5ce56 100644 --- a/sandbox/host/src/sandbox/wasmer_backend.rs +++ b/sandbox/host/src/sandbox/wasmer_backend.rs @@ -20,10 +20,10 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use wasmer::RuntimeError; +use wasmer::{Exportable, RuntimeError}; use codec::{Decode, Encode}; -use gear_sandbox_env::HostError; +use gear_sandbox_env::{HostError, WasmReturnValue}; use sp_wasm_interface::{util, Pointer, ReturnValue, Value, WordSize}; use crate::{ @@ -69,6 +69,49 @@ impl Backend { } } +#[derive(Default)] +pub struct Env { + gas: Option, + allowance: Option, +} + +// WARNING: intentionally to avoid cyclic refs +impl Clone for Env { + fn clone(&self) -> Self { + let into_weak_instance_ref = |mut global: wasmer::Global| { + global.into_weak_instance_ref(); + + global + }; + + Self { + gas: self.gas.clone().map(into_weak_instance_ref), + allowance: self.allowance.clone().map(into_weak_instance_ref), + } + } +} + +// copypaste +pub const GLOBAL_NAME_GAS: &str = "gear_gas"; +pub const GLOBAL_NAME_ALLOWANCE: &str = "gear_allowance"; + +impl wasmer::WasmerEnv for Env { + fn init_with_instance( + &mut self, + instance: &wasmer::Instance, + ) -> std::result::Result<(), wasmer::HostEnvInitError> { + let gas: wasmer::Global = instance.exports.get_with_generics_weak(GLOBAL_NAME_GAS)?; + self.gas = Some(gas); + + let allowance: wasmer::Global = instance + .exports + .get_with_generics_weak(GLOBAL_NAME_ALLOWANCE)?; + self.allowance = Some(allowance); + + Ok(()) + } +} + /// Invoke a function within a sandboxed module pub fn invoke( instance: &wasmer::Instance, @@ -278,11 +321,22 @@ fn dispatch_function( store: &wasmer::Store, func_ty: &wasmer::FunctionType, ) -> wasmer::Function { - wasmer::Function::new(store, func_ty, move |params| { + wasmer::Function::new_with_env(store, func_ty, Env::default(), move |env, params| { SandboxContextStore::with(|sandbox_context| { + let gas = env + .gas + .as_ref() + .ok_or(RuntimeError::new("gas global should be set"))?; + + let allowance = env + .allowance + .as_ref() + .ok_or(RuntimeError::new("allowance global should be set"))?; + // Serialize arguments into a byte vector. - let invoke_args_data = params + let invoke_args_data = [gas.get(), allowance.get()] .iter() + .chain(params.iter()) .map(|val| match val { wasmer::Val::I32(val) => Ok(Value::I32(*val)), wasmer::Val::I64(val) => Ok(Value::I64(*val)), @@ -361,13 +415,13 @@ fn dispatch_function( let serialized_result_val = serialized_result_val?; - let deserialized_result = std::result::Result::::decode( + let deserialized_result = std::result::Result::::decode( &mut serialized_result_val.as_slice(), ) .map_err(|_| RuntimeError::new("Decoding Result failed!"))? .map_err(|_| RuntimeError::new("Supervisor function returned sandbox::HostError"))?; - let result = match deserialized_result { + let result = match deserialized_result.value { ReturnValue::Value(Value::I32(val)) => vec![wasmer::Val::I32(val)], ReturnValue::Value(Value::I64(val)) => vec![wasmer::Val::I64(val)], ReturnValue::Value(Value::F32(val)) => vec![wasmer::Val::F32(f32::from_bits(val))], @@ -376,6 +430,9 @@ fn dispatch_function( ReturnValue::Unit => vec![], }; + gas.set(wasmer::Val::I64(deserialized_result.gas))?; + allowance.set(wasmer::Val::I64(deserialized_result.allowance))?; + Ok(result) }) .expect("SandboxContextStore is set when invoking sandboxed functions; qed") diff --git a/sandbox/sandbox/src/embedded_executor.rs b/sandbox/sandbox/src/embedded_executor.rs index 76b48c1ea94..bd7f8b3ef94 100644 --- a/sandbox/sandbox/src/embedded_executor.rs +++ b/sandbox/sandbox/src/embedded_executor.rs @@ -137,7 +137,7 @@ impl<'a, T> Externals for GuestExternals<'a, T> { let result = (self.defined_host_functions.funcs[index])(self.state, &args); match result { - Ok(value) => Ok(match value { + Ok(value) => Ok(match value.value { ReturnValue::Value(v) => Some(to_wasmi(v)), ReturnValue::Unit => None, }), @@ -384,37 +384,53 @@ mod tests { use super::{EnvironmentDefinitionBuilder, Instance}; use crate::{Error, HostError, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, Value}; use assert_matches::assert_matches; + use gear_sandbox_env::WasmReturnValue; fn execute_sandboxed(code: &[u8], args: &[Value]) -> Result { struct State { counter: u32, } - fn env_assert(_e: &mut State, args: &[Value]) -> Result { + fn env_assert(_e: &mut State, args: &[Value]) -> Result { if args.len() != 1 { return Err(HostError); } let condition = args[0].as_i32().ok_or(HostError)?; if condition != 0 { - Ok(ReturnValue::Unit) + Ok(WasmReturnValue { + gas: 0, + allowance: 0, + value: ReturnValue::Unit, + }) } else { Err(HostError) } } - fn env_inc_counter(e: &mut State, args: &[Value]) -> Result { + fn env_inc_counter(e: &mut State, args: &[Value]) -> Result { if args.len() != 1 { return Err(HostError); } let inc_by = args[0].as_i32().ok_or(HostError)?; e.counter += inc_by as u32; - Ok(ReturnValue::Value(Value::I32(e.counter as i32))) + Ok(WasmReturnValue { + gas: 0, + allowance: 0, + value: ReturnValue::Value(Value::I32(e.counter as i32)), + }) } /// Function that takes one argument of any type and returns that value. - fn env_polymorphic_id(_e: &mut State, args: &[Value]) -> Result { + fn env_polymorphic_id( + _e: &mut State, + args: &[Value], + ) -> Result { if args.len() != 1 { return Err(HostError); } - Ok(ReturnValue::Value(args[0])) + Ok(WasmReturnValue { + gas: 0, + allowance: 0, + value: ReturnValue::Value(args[0]), + }) } let mut state = State { counter: 0 }; @@ -525,8 +541,12 @@ mod tests { #[test] fn cant_return_unmatching_type() { - fn env_returns_i32(_e: &mut (), _args: &[Value]) -> Result { - Ok(ReturnValue::Value(Value::I32(42))) + fn env_returns_i32(_e: &mut (), _args: &[Value]) -> Result { + Ok(WasmReturnValue { + gas: 0, + allowance: 0, + value: ReturnValue::Value(Value::I32(42)), + }) } let mut env_builder = EnvironmentDefinitionBuilder::new(); diff --git a/sandbox/sandbox/src/lib.rs b/sandbox/sandbox/src/lib.rs index ccbf1be9969..31de81fc86a 100644 --- a/sandbox/sandbox/src/lib.rs +++ b/sandbox/sandbox/src/lib.rs @@ -50,7 +50,7 @@ use sp_core::RuntimeDebug; use sp_std::prelude::*; use sp_wasm_interface::HostPointer; -pub use sp_wasm_interface::{ReturnValue, Value}; +pub use sp_wasm_interface::{IntoValue, ReturnValue, Value}; #[cfg(feature = "std")] pub use self::embedded_executor as default_executor; @@ -89,7 +89,7 @@ impl From for HostError { /// supervisor in [`EnvironmentDefinitionBuilder`]. /// /// [`EnvironmentDefinitionBuilder`]: struct.EnvironmentDefinitionBuilder.html -pub type HostFuncType = fn(&mut T, &[Value]) -> Result; +pub type HostFuncType = fn(&mut T, &[Value]) -> Result; /// Reference to a sandboxed linear memory, that /// will be used by the guest module.