From 3721a9a48c9c98052473c3778efbd1590fcc21e9 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 20 Sep 2023 19:45:27 +0300 Subject: [PATCH 01/37] Hide gas counter in macro --- core-backend/codegen/src/host.rs | 20 +++- core-backend/src/funcs.rs | 168 +++++++++---------------------- 2 files changed, 66 insertions(+), 122 deletions(-) diff --git a/core-backend/codegen/src/host.rs b/core-backend/codegen/src/host.rs index dd241427d31..1b9ebeb774f 100644 --- a/core-backend/codegen/src/host.rs +++ b/core-backend/codegen/src/host.rs @@ -21,7 +21,8 @@ use proc_macro2::{Ident, Span}; use quote::{quote, ToTokens}; use syn::{ fold::Fold, parse::Parse, parse_quote, punctuated::Punctuated, Block, Expr, ExprCall, ExprPath, - FnArg, ItemFn, Meta, Pat, PatType, Path, Signature, Token, + FnArg, GenericArgument, ItemFn, Meta, Pat, PatType, Path, PathArguments, ReturnType, Signature, + Token, Type, }; /// Host function builder. @@ -69,6 +70,8 @@ impl HostFn { fn build_inputs(&self) -> Vec { let mut inputs = self.item.sig.inputs.iter().cloned().collect::>(); + inputs.insert(1, parse_quote!(gas: u64)); + if matches!(self.meta.call_type, CallType::Fallible) { inputs.push(parse_quote!(err_mid_ptr: u32)); } @@ -100,7 +103,20 @@ impl HostFn { fn build_sig(&self) -> Signature { let name = self.item.sig.ident.clone(); let inputs = self.build_inputs(); - let output = self.item.sig.output.clone().into_token_stream(); + + let mut output = self.item.sig.output.clone(); + if let ReturnType::Type(_rarrow, ty) = &mut output { + if let Type::Path(type_path) = ty.as_mut() { + let segment = type_path.path.segments.first_mut().unwrap(); + if let PathArguments::AngleBracketed(generic_args) = &mut segment.arguments { + let generic_arg = generic_args.args.first_mut().unwrap(); + if let GenericArgument::Type(ty) = generic_arg { + *ty = parse_quote! { (u64, #ty) }; + } + } + } + } + let output = output.clone().into_token_stream(); parse_quote! { fn #name(#(#inputs),*) #output diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 3b064431d60..51ce9f6720e 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -126,12 +126,11 @@ where #[host(fallible, wgas, cost = RuntimeCosts::Send(len))] pub fn send( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_hash_val = ctx.manager.register_read_as(pid_value_ptr); let read_payload = ctx.manager.register_read(payload_ptr, len); let HashWithValue { @@ -148,11 +147,10 @@ where #[host(fallible, wgas, cost = RuntimeCosts::SendCommit)] pub fn send_commit( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, handle: u32, pid_value_ptr: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_pid_value = ctx.manager.register_read_as(pid_value_ptr); let HashWithValue { hash: destination, @@ -169,18 +167,17 @@ where } #[host(fallible, cost = RuntimeCosts::SendInit, err = ErrorWithHandle)] - pub fn send_init(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn send_init(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut().send_init().map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::SendPush(len), err = ErrorBytes)] pub fn send_push( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, handle: u32, payload_ptr: u32, len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_payload = ctx.manager.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -192,12 +189,11 @@ where #[host(fallible, cost = RuntimeCosts::ReservationSend(len))] pub fn reservation_send( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, rid_pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); let read_payload = ctx.manager.register_read(payload_ptr, len); let TwoHashesWithValue { @@ -219,11 +215,10 @@ where #[host(fallible, cost = RuntimeCosts::ReservationSendCommit)] pub fn reservation_send_commit( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, handle: u32, rid_pid_value_ptr: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); let TwoHashesWithValue { hash1: reservation_id, @@ -244,11 +239,10 @@ where #[host(fallible, cost = RuntimeCosts::Read, err = ErrorBytes)] pub fn read( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, at: u32, len: u32, buffer_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let payload_lock = ctx.ext_mut().lock_payload(at, len)?; payload_lock .drop_with::(|payload_access| { @@ -263,11 +257,7 @@ where } #[host(cost = RuntimeCosts::Size)] - pub fn size( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - size_ptr: u32, - ) -> Result<(u64, ()), HostError> { + pub fn size(ctx: &mut CallerWrap<'_, '_, Ext>, size_ptr: u32) -> Result<(), HostError> { let size = ctx.ext_mut().size()? as u32; let write_size = ctx.manager.register_write_as(size_ptr); @@ -276,18 +266,14 @@ where } #[host(cost = RuntimeCosts::Exit)] - pub fn exit( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - inheritor_id_ptr: u32, - ) -> Result<(u64, ()), HostError> { + pub fn exit(ctx: &mut CallerWrap<'_, '_, Ext>, inheritor_id_ptr: u32) -> Result<(), HostError> { let read_inheritor_id = ctx.manager.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 CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn reply_code(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut() .reply_code() .map(ReplyCode::to_bytes) @@ -295,10 +281,7 @@ where } #[host(fallible, cost = RuntimeCosts::SignalCode, err = ErrorWithSignalCode)] - pub fn signal_code( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - ) -> Result<(u64, ()), HostError> { + pub fn signal_code(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut() .signal_code() .map(SignalCode::to_u32) @@ -306,11 +289,7 @@ where } #[host(cost = RuntimeCosts::Alloc(pages))] - pub fn alloc( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - pages: u32, - ) -> Result<(u64, u32), HostError> { + pub fn alloc(ctx: &mut CallerWrap<'_, '_, Ext>, pages: u32) -> Result { let res = ctx.alloc(pages); let res = ctx.process_alloc_func_result(res)?; @@ -328,11 +307,7 @@ where } #[host(cost = RuntimeCosts::Free)] - pub fn free( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - page_no: u32, - ) -> Result<(u64, i32), HostError> { + pub fn free(ctx: &mut CallerWrap<'_, '_, Ext>, page_no: u32) -> Result { let page = WasmPage::new(page_no).map_err(|_| { UndefinedTerminationReason::Actor(ActorTerminationReason::Trap( TrapExplanation::Unknown, @@ -357,9 +332,8 @@ where #[host(cost = RuntimeCosts::BlockHeight)] pub fn block_height( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, height_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let height = ctx.ext_mut().block_height()?; let write_height = ctx.manager.register_write_as(height_ptr); @@ -370,9 +344,8 @@ where #[host(cost = RuntimeCosts::BlockTimestamp)] pub fn block_timestamp( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, timestamp_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let timestamp = ctx.ext_mut().block_timestamp()?; let write_timestamp = ctx.manager.register_write_as(timestamp_ptr); @@ -383,10 +356,9 @@ where #[host(cost = RuntimeCosts::Random)] pub fn random( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, subject_ptr: u32, bn_random_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_subject = ctx.manager.register_read_decoded(subject_ptr); let write_bn_random = ctx.manager.register_write_as(bn_random_ptr); @@ -405,11 +377,10 @@ where #[host(fallible, wgas, cost = RuntimeCosts::Reply(len))] pub fn reply( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, payload_ptr: u32, len: u32, value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_payload = ctx.manager.register_read(payload_ptr, len); let value = Self::register_and_read_value(ctx, value_ptr)?; let payload = Self::read_message_payload(ctx, read_payload)?; @@ -422,9 +393,8 @@ where #[host(fallible, wgas, cost = RuntimeCosts::ReplyCommit)] pub fn reply_commit( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let value = Self::register_and_read_value(ctx, value_ptr)?; ctx.ext_mut() @@ -435,11 +405,10 @@ where #[host(fallible, cost = RuntimeCosts::ReservationReply(len))] pub fn reservation_reply( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, rid_value_ptr: u32, payload_ptr: u32, len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); let read_payload = ctx.manager.register_read(payload_ptr, len); let HashWithValue { @@ -456,9 +425,8 @@ where #[host(fallible, cost = RuntimeCosts::ReservationReplyCommit)] pub fn reservation_reply_commit( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, rid_value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); let HashWithValue { hash: reservation_id, @@ -474,25 +442,21 @@ where } #[host(fallible, cost = RuntimeCosts::ReplyTo)] - pub fn reply_to(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn reply_to(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut().reply_to().map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::SignalFrom)] - pub fn signal_from( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - ) -> Result<(u64, ()), HostError> { + pub fn signal_from(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut().signal_from().map_err(Into::into) } #[host(fallible, cost = RuntimeCosts::ReplyPush(len), err = ErrorBytes)] pub fn reply_push( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, payload_ptr: u32, len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_payload = ctx.manager.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -502,11 +466,10 @@ where #[host(fallible, wgas, cost = RuntimeCosts::ReplyInput)] pub fn reply_input( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, offset: u32, len: u32, value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { // Charge for `len` is inside `reply_push_input` let value = Self::register_and_read_value(ctx, value_ptr)?; @@ -522,10 +485,9 @@ where #[host(fallible, cost = RuntimeCosts::ReplyPushInput, err = ErrorBytes)] pub fn reply_push_input( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, offset: u32, len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { ctx.ext_mut() .reply_push_input(offset, len) .map_err(Into::into) @@ -535,12 +497,11 @@ where #[host(fallible, wgas, cost = RuntimeCosts::SendInput)] pub fn send_input( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, pid_value_ptr: u32, offset: u32, len: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { // Charge for `len` inside `send_push_input` let read_pid_value = ctx.manager.register_read_as(pid_value_ptr); let HashWithValue { @@ -564,11 +525,10 @@ where #[host(fallible, cost = RuntimeCosts::SendPushInput, err = ErrorBytes)] pub fn send_push_input( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, handle: u32, offset: u32, len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { ctx.ext_mut() .send_push_input(handle, offset, len) .map_err(Into::into) @@ -577,10 +537,9 @@ where #[host(cost = RuntimeCosts::Debug(data_len))] pub fn debug( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, data_ptr: u32, data_len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_data = ctx.manager.register_read(data_ptr, data_len); let data: RuntimeBuffer = ctx .read(read_data)? @@ -601,10 +560,9 @@ where #[host(cost = RuntimeCosts::Null)] pub fn panic( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, data_ptr: u32, data_len: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_data = ctx.manager.register_read(data_ptr, data_len); let data = ctx.read(read_data).unwrap_or_default(); @@ -614,17 +572,16 @@ where } #[host(cost = RuntimeCosts::Null)] - pub fn oom_panic(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn oom_panic(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) } #[host(fallible, cost = RuntimeCosts::ReserveGas)] pub fn reserve_gas( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, gas_value: u64, duration: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { ctx.ext_mut() .reserve_gas(gas_value, duration) .map_err(Into::into) @@ -633,10 +590,9 @@ where #[host(fallible, cost = RuntimeCosts::ReplyDeposit, err = ErrorBytes)] pub fn reply_deposit( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, message_id_ptr: u32, gas_value: u64, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); let message_id = ctx.read_decoded(read_message_id)?; @@ -648,9 +604,8 @@ where #[host(fallible, cost = RuntimeCosts::UnreserveGas, err = ErrorWithGas)] pub fn unreserve_gas( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, reservation_id_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_reservation_id = ctx.manager.register_read_decoded(reservation_id_ptr); let reservation_id = ctx.read_decoded(read_reservation_id)?; @@ -662,20 +617,15 @@ where #[host(fallible, cost = RuntimeCosts::SystemReserveGas, err = ErrorBytes)] pub fn system_reserve_gas( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, gas_value: u64, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { ctx.ext_mut() .system_reserve_gas(gas_value) .map_err(Into::into) } #[host(cost = RuntimeCosts::GasAvailable)] - pub fn gas_available( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - gas_ptr: u32, - ) -> Result<(u64, ()), HostError> { + pub fn gas_available(ctx: &mut CallerWrap<'_, '_, Ext>, gas_ptr: u32) -> Result<(), HostError> { let gas_available = ctx.ext_mut().gas_available()?; let write_gas = ctx.manager.register_write_as(gas_ptr); @@ -683,12 +633,11 @@ where .map_err(Into::into) } - #[host(cost = RuntimeCosts::MsgId)] + #[host(cost = RuntimeCosts::MessageId)] pub fn message_id( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, message_id_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let message_id = ctx.ext_mut().message_id()?; let write_message_id = ctx.manager.register_write_as(message_id_ptr); @@ -699,9 +648,8 @@ where #[host(cost = RuntimeCosts::ProgramId)] pub fn program_id( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, program_id_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let program_id = ctx.ext_mut().program_id()?; let write_program_id = ctx.manager.register_write_as(program_id_ptr); @@ -712,9 +660,8 @@ where #[host(fallible, cost = RuntimeCosts::PayProgramRent, err = ErrorWithBlockNumberAndValue)] pub fn pay_program_rent( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, rent_pid_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_rent_pid = ctx.manager.register_read_as(rent_pid_ptr); let HashWithValue { @@ -728,11 +675,7 @@ where } #[host(cost = RuntimeCosts::Source)] - pub fn source( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - source_ptr: u32, - ) -> Result<(u64, ()), HostError> { + pub fn source(ctx: &mut CallerWrap<'_, '_, Ext>, source_ptr: u32) -> Result<(), HostError> { let source = ctx.ext_mut().source()?; let write_source = ctx.manager.register_write_as(source_ptr); @@ -741,11 +684,7 @@ where } #[host(cost = RuntimeCosts::Value)] - pub fn value( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + pub fn value(ctx: &mut CallerWrap<'_, '_, Ext>, value_ptr: u32) -> Result<(), HostError> { let value = ctx.ext_mut().value()?; let write_value = ctx.manager.register_write_as(value_ptr); @@ -756,9 +695,8 @@ where #[host(cost = RuntimeCosts::ValueAvailable)] pub fn value_available( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, value_ptr: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let value_available = ctx.ext_mut().value_available()?; let write_value = ctx.manager.register_write_as(value_ptr); @@ -767,32 +705,24 @@ where } #[host(cost = RuntimeCosts::Leave)] - pub fn leave(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn leave(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { Err(ActorTerminationReason::Leave.into()) } #[host(cost = RuntimeCosts::Wait)] - pub fn wait(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { + pub fn wait(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { ctx.ext_mut().wait()?; Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) } #[host(cost = RuntimeCosts::WaitFor)] - pub fn wait_for( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, - duration: u32, - ) -> Result<(u64, ()), HostError> { + pub fn wait_for(ctx: &mut CallerWrap<'_, '_, Ext>, duration: u32) -> Result<(), HostError> { 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 CallerWrap<'_, '_, Ext>, - gas: u64, - duration: u32, - ) -> Result<(u64, ()), HostError> { + pub fn wait_up_to(ctx: &mut CallerWrap<'_, '_, Ext>, duration: u32) -> Result<(), HostError> { let waited_type = if ctx.ext_mut().wait_up_to(duration)? { MessageWaitedType::WaitUpToFull } else { @@ -804,10 +734,9 @@ where #[host(fallible, cost = RuntimeCosts::Wake, err = ErrorBytes)] pub fn wake( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, message_id_ptr: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); let message_id = ctx.read_decoded(read_message_id)?; @@ -818,14 +747,13 @@ where #[host(fallible, wgas, cost = RuntimeCosts::CreateProgram(payload_len, salt_len), err = ErrorWithTwoHashes)] pub fn create_program( ctx: &mut CallerWrap<'_, '_, Ext>, - gas: u64, cid_value_ptr: u32, salt_ptr: u32, salt_len: u32, payload_ptr: u32, payload_len: u32, delay: u32, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(), HostError> { let read_cid_value = ctx.manager.register_read_as(cid_value_ptr); let read_salt = ctx.manager.register_read(salt_ptr, salt_len); let read_payload = ctx.manager.register_read(payload_ptr, payload_len); From b0db5a98ab2aa3123a8e3d5ae641fe1dc582557f Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 18:31:04 +0300 Subject: [PATCH 02/37] Initial design --- core-backend/src/env.rs | 2 +- core-backend/src/funcs.rs | 118 +++++++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 625eec6e8b0..1842bcd6621 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -61,7 +61,7 @@ use gear_wasm_instrument::{ }; #[derive(Clone, Copy)] -struct SandboxValue(Value); +pub struct SandboxValue(Value); impl From for SandboxValue { fn from(value: i32) -> Self { diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 51ce9f6720e..a6848d548d7 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -24,6 +24,7 @@ use crate::{ TrapExplanation, UndefinedTerminationReason, UnrecoverableExecutionError, UnrecoverableMemoryError, }, + env::SandboxValue, memory::{MemoryAccessError, WasmMemoryRead}, runtime::CallerWrap, BackendExternalities, @@ -43,7 +44,8 @@ use gear_core::{ }; use gear_core_backend_codegen::host; use gear_core_errors::{MessageError, ReplyCode, SignalCode}; -use gear_sandbox_env::HostError; +use gear_sandbox::ReturnValue; +use gear_sandbox_env::{HostError, WasmReturnValue}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Hash, @@ -84,6 +86,40 @@ macro_rules! syscall_trace { } } +pub trait FallibleSysCall { + fn execute( + &self, + ctx: &mut CallerWrap, + gas: u64, + res_ptr: u32, + ) -> Result<(u64, ()), HostError>; +} + +type InnerFallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); + +impl FallibleSysCall for InnerFallibleSysCall +where + F: Fn(&mut CallerWrap) -> Result, + E: From>, + Ext: BackendExternalities + 'static, +{ + fn execute( + &self, + ctx: &mut CallerWrap, + gas: u64, + res_ptr: u32, + ) -> Result<(u64, ()), HostError> { + let (costs, _error, func) = self; + ctx.run_fallible::(gas, res_ptr, *costs, |ctx| (func)(ctx)) + } +} + +#[derive(Default)] +struct FallibleSysCallError(PhantomData); + +#[derive(Default)] +struct FallibleSysCallOutput(PhantomData); + const PTR_SPECIAL: u32 = u32::MAX; pub(crate) struct FuncsHandler { @@ -121,6 +157,86 @@ where .map_err(RunFallibleError::FallibleExt) } + fn sandbox() { + trait SysCallFabric { + fn create(&self, args: &[SandboxValue]) -> Result; + } + + impl SysCallFabric for H + where + H: Fn(u32, u32, u32, u32, u32, u32) -> S, + S: FallibleSysCall, + { + fn create(&self, args: &[SandboxValue]) -> Result { + let [a, b, c, d, e, f]: [SandboxValue; 6] = + args.try_into().map_err(|_| HostError)?; + let a = a.try_into()?; + let b = b.try_into()?; + let c = c.try_into()?; + let d = d.try_into()?; + let e = e.try_into()?; + let f = f.try_into()?; + Ok((self)(a, b, c, d, e, f)) + } + } + + fn execute( + ctx: &mut CallerWrap, + args: &[SandboxValue], + handler: H, + ) -> Result + where + Ext: BackendExternalities + 'static, + Ext::UnrecoverableError: BackendSyscallError, + RunFallibleError: From, + Ext::AllocError: BackendAllocSyscallError, + H: SysCallFabric, + S: FallibleSysCall, + { + let (gas, args) = args.split_first().ok_or(HostError)?; + let gas = (*gas).try_into()?; + let (res_ptr, args) = args.split_last().ok_or(HostError)?; + let res_ptr = (*res_ptr).try_into()?; + + let sys_call = SysCallFabric::create(&handler, args)?; + let (gas, ()) = sys_call.execute(ctx, gas, res_ptr)?; + + Ok(WasmReturnValue { + gas: gas as i64, + inner: ReturnValue::Unit, + }) + } + } + + pub fn create_program2( + cid_value_ptr: u32, + salt_ptr: u32, + salt_len: u32, + payload_ptr: u32, + payload_len: u32, + delay: u32, + ) -> impl FallibleSysCall { + ( + RuntimeCosts::CreateProgram(payload_len, salt_len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| -> Result<_, RunFallibleError> { + let read_cid_value = ctx.manager.register_read_as(cid_value_ptr); + let read_salt = ctx.manager.register_read(salt_ptr, salt_len); + let read_payload = ctx.manager.register_read(payload_ptr, payload_len); + let HashWithValue { + hash: code_id, + value, + } = ctx.read_as(read_cid_value)?; + let salt = Self::read_message_payload(ctx, read_salt)?; + let payload = Self::read_message_payload(ctx, read_payload)?; + + ctx.ext_mut() + .create_program(InitPacket::new(code_id.into(), salt, payload, value), delay) + .map_err(Into::into) + }, + ) + } + // TODO #3037 #[allow(clippy::too_many_arguments)] #[host(fallible, wgas, cost = RuntimeCosts::Send(len))] From 18fcb8ba9da399cb9fc5b189f56d2abf5589d6e0 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:21:59 +0300 Subject: [PATCH 03/37] Infallible sys-call support --- core-backend/src/funcs.rs | 126 ++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 26 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index a6848d548d7..8652441a0b3 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -86,39 +86,95 @@ macro_rules! syscall_trace { } } -pub trait FallibleSysCall { +pub trait SysCallContext: Sized { + fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError>; +} + +pub trait SysCall { + type Context: SysCallContext; + fn execute( &self, - ctx: &mut CallerWrap, - gas: u64, - res_ptr: u32, + caller: &mut CallerWrap, + ctx: Self::Context, ) -> Result<(u64, ()), HostError>; } -type InnerFallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); +struct FallibleSysCallContext { + gas: u64, + res_ptr: u32, +} + +impl SysCallContext for FallibleSysCallContext { + fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError> { + let (gas, args) = args.split_first().ok_or(HostError)?; + let gas: u64 = (*gas).try_into()?; + let (res_ptr, args) = args.split_last().ok_or(HostError)?; + let res_ptr: u32 = (*res_ptr).try_into()?; + Ok((FallibleSysCallContext { gas, res_ptr }, args)) + } +} + +type FallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); -impl FallibleSysCall for InnerFallibleSysCall +impl SysCall for FallibleSysCall where F: Fn(&mut CallerWrap) -> Result, E: From>, Ext: BackendExternalities + 'static, { + type Context = FallibleSysCallContext; + fn execute( &self, - ctx: &mut CallerWrap, - gas: u64, - res_ptr: u32, + caller: &mut CallerWrap, + context: Self::Context, ) -> Result<(u64, ()), HostError> { let (costs, _error, func) = self; - ctx.run_fallible::(gas, res_ptr, *costs, |ctx| (func)(ctx)) + let FallibleSysCallContext { gas, res_ptr } = context; + caller.run_fallible::(gas, res_ptr, *costs, |ctx| (func)(ctx)) } } -#[derive(Default)] -struct FallibleSysCallError(PhantomData); +pub struct InfallibleSysCallContext { + gas: u64, +} + +impl SysCallContext for InfallibleSysCallContext { + fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError> { + let (gas, args) = args.split_first().ok_or(HostError)?; + let gas: u64 = (*gas).try_into()?; + Ok((Self { gas }, args)) + } +} + +type InfallibleSysCall = (RuntimeCosts, F); + +impl SysCall for InfallibleSysCall +where + F: Fn(&mut CallerWrap) -> Result, + Ext: BackendExternalities + 'static, +{ + type Context = InfallibleSysCallContext; + + fn execute( + &self, + caller: &mut CallerWrap, + ctx: Self::Context, + ) -> Result<(u64, ()), HostError> { + let (costs, func) = self; + let InfallibleSysCallContext { gas } = ctx; + caller + .run_any::(gas, *costs, |ctx| (func)(ctx)) + .map(|(gas, _)| { + // FIXME: sys-call return value is not supported yet + (gas, ()) + }) + } +} #[derive(Default)] -struct FallibleSysCallOutput(PhantomData); +struct FallibleSysCallError(PhantomData); const PTR_SPECIAL: u32 = u32::MAX; @@ -159,15 +215,27 @@ where fn sandbox() { trait SysCallFabric { - fn create(&self, args: &[SandboxValue]) -> Result; + fn create(self, args: &[SandboxValue]) -> Result; + } + + impl SysCallFabric for H + where + H: Fn(u32) -> S, + S: SysCall, + { + fn create(self, args: &[SandboxValue]) -> Result { + let [a]: [SandboxValue; 1] = args.try_into().map_err(|_| HostError)?; + let a = a.try_into()?; + Ok((self)(a)) + } } impl SysCallFabric for H where H: Fn(u32, u32, u32, u32, u32, u32) -> S, - S: FallibleSysCall, + S: SysCall, { - fn create(&self, args: &[SandboxValue]) -> Result { + fn create(self, args: &[SandboxValue]) -> Result { let [a, b, c, d, e, f]: [SandboxValue; 6] = args.try_into().map_err(|_| HostError)?; let a = a.try_into()?; @@ -181,7 +249,7 @@ where } fn execute( - ctx: &mut CallerWrap, + caller: &mut CallerWrap, args: &[SandboxValue], handler: H, ) -> Result @@ -191,15 +259,11 @@ where RunFallibleError: From, Ext::AllocError: BackendAllocSyscallError, H: SysCallFabric, - S: FallibleSysCall, + S: SysCall, { - let (gas, args) = args.split_first().ok_or(HostError)?; - let gas = (*gas).try_into()?; - let (res_ptr, args) = args.split_last().ok_or(HostError)?; - let res_ptr = (*res_ptr).try_into()?; - - let sys_call = SysCallFabric::create(&handler, args)?; - let (gas, ()) = sys_call.execute(ctx, gas, res_ptr)?; + let (ctx, args) = S::Context::from_args(args)?; + let sys_call = SysCallFabric::create(handler, args)?; + let (gas, ()) = sys_call.execute(caller, ctx)?; Ok(WasmReturnValue { gas: gas as i64, @@ -215,7 +279,7 @@ where payload_ptr: u32, payload_len: u32, delay: u32, - ) -> impl FallibleSysCall { + ) -> impl SysCall { ( RuntimeCosts::CreateProgram(payload_len, salt_len), FallibleSysCallError::::default(), @@ -237,6 +301,16 @@ where ) } + pub fn size2(size_ptr: u32) -> impl SysCall { + (RuntimeCosts::Size, move |ctx: &mut CallerWrap| { + let size = ctx.ext_mut().size()? as u32; + + let write_size = ctx.manager.register_write_as(size_ptr); + ctx.write_as(write_size, size.to_le_bytes()) + .map_err(Into::into) + }) + } + // TODO #3037 #[allow(clippy::too_many_arguments)] #[host(fallible, wgas, cost = RuntimeCosts::Send(len))] From dd7e214019a702fb576049f49d268ba77936644a Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:33:35 +0300 Subject: [PATCH 04/37] Support value returning sys-calls --- core-backend/src/funcs.rs | 70 ++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 8652441a0b3..7e724385bfd 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -90,14 +90,14 @@ pub trait SysCallContext: Sized { fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError>; } -pub trait SysCall { +pub trait SysCall { type Context: SysCallContext; fn execute( &self, caller: &mut CallerWrap, ctx: Self::Context, - ) -> Result<(u64, ()), HostError>; + ) -> Result<(u64, T), HostError>; } struct FallibleSysCallContext { @@ -117,7 +117,7 @@ impl SysCallContext for FallibleSysCallContext { type FallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); -impl SysCall for FallibleSysCall +impl SysCall for FallibleSysCall where F: Fn(&mut CallerWrap) -> Result, E: From>, @@ -150,7 +150,7 @@ impl SysCallContext for InfallibleSysCallContext { type InfallibleSysCall = (RuntimeCosts, F); -impl SysCall for InfallibleSysCall +impl SysCall for InfallibleSysCall where F: Fn(&mut CallerWrap) -> Result, Ext: BackendExternalities + 'static, @@ -161,15 +161,10 @@ where &self, caller: &mut CallerWrap, ctx: Self::Context, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(u64, T), HostError> { let (costs, func) = self; let InfallibleSysCallContext { gas } = ctx; - caller - .run_any::(gas, *costs, |ctx| (func)(ctx)) - .map(|(gas, _)| { - // FIXME: sys-call return value is not supported yet - (gas, ()) - }) + caller.run_any::(gas, *costs, |ctx| (func)(ctx)) } } @@ -214,14 +209,14 @@ where } fn sandbox() { - trait SysCallFabric { + trait SysCallFabric { fn create(self, args: &[SandboxValue]) -> Result; } - impl SysCallFabric for H + impl SysCallFabric for H where H: Fn(u32) -> S, - S: SysCall, + S: SysCall, { fn create(self, args: &[SandboxValue]) -> Result { let [a]: [SandboxValue; 1] = args.try_into().map_err(|_| HostError)?; @@ -230,10 +225,10 @@ where } } - impl SysCallFabric for H + impl SysCallFabric for H where H: Fn(u32, u32, u32, u32, u32, u32) -> S, - S: SysCall, + S: SysCall, { fn create(self, args: &[SandboxValue]) -> Result { let [a, b, c, d, e, f]: [SandboxValue; 6] = @@ -248,7 +243,7 @@ where } } - fn execute( + fn execute( caller: &mut CallerWrap, args: &[SandboxValue], handler: H, @@ -258,18 +253,53 @@ where Ext::UnrecoverableError: BackendSyscallError, RunFallibleError: From, Ext::AllocError: BackendAllocSyscallError, - H: SysCallFabric, - S: SysCall, + H: SysCallFabric, + S: SysCall, { let (ctx, args) = S::Context::from_args(args)?; let sys_call = SysCallFabric::create(handler, args)?; - let (gas, ()) = sys_call.execute(caller, ctx)?; + // FIXME: return value is not ignored + let (gas, _value) = sys_call.execute(caller, ctx)?; Ok(WasmReturnValue { gas: gas as i64, inner: ReturnValue::Unit, }) } + + fn check(caller: &mut CallerWrap) + where + Ext: BackendExternalities + 'static, + Ext::UnrecoverableError: BackendSyscallError, + RunFallibleError: From, + Ext::AllocError: BackendAllocSyscallError, + { + let _ = execute(caller, &[], FuncsHandler::::create_program2); + let _ = execute(caller, &[], FuncsHandler::::size2); + let _ = execute(caller, &[], FuncsHandler::::alloc2); + } + } + + pub fn alloc2(pages: u32) -> impl SysCall { + ( + RuntimeCosts::Alloc(pages), + move |ctx: &mut CallerWrap| { + let res = ctx.alloc(pages); + let res = ctx.process_alloc_func_result(res)?; + + let page = match res { + Ok(page) => { + log::trace!("Alloc {pages:?} pages at {page:?}"); + page.raw() + } + Err(err) => { + log::trace!("Alloc failed: {err}"); + u32::MAX + } + }; + Ok(page) + }, + ) } pub fn create_program2( From 14c0eed702ebda7ff379105f7e03cbf4f843f603 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:36:41 +0300 Subject: [PATCH 05/37] Check specific sys-calls are supported --- core-backend/src/funcs.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 7e724385bfd..1949e8788f0 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -213,6 +213,17 @@ where fn create(self, args: &[SandboxValue]) -> Result; } + impl SysCallFabric for H + where + H: Fn() -> S, + S: SysCall, + { + fn create(self, args: &[SandboxValue]) -> Result { + let _: [SandboxValue; 0] = args.try_into().map_err(|_| HostError)?; + Ok((self)()) + } + } + impl SysCallFabric for H where H: Fn(u32) -> S, @@ -277,9 +288,16 @@ where let _ = execute(caller, &[], FuncsHandler::::create_program2); let _ = execute(caller, &[], FuncsHandler::::size2); let _ = execute(caller, &[], FuncsHandler::::alloc2); + let _ = execute(caller, &[], FuncsHandler::::forbidden2); } } + pub fn forbidden2() -> impl SysCall { + (RuntimeCosts::Null, |_: &mut CallerWrap| { + Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) + }) + } + pub fn alloc2(pages: u32) -> impl SysCall { ( RuntimeCosts::Alloc(pages), From 47e66a17b70ed4bbf2d2bbb74c6aac1438e2e64f Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:42:27 +0300 Subject: [PATCH 06/37] Reorganize content --- core-backend/src/funcs.rs | 152 +++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 86 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 1949e8788f0..101ec025cee 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -86,6 +86,8 @@ macro_rules! syscall_trace { } } +const PTR_SPECIAL: u32 = u32::MAX; + pub trait SysCallContext: Sized { fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError>; } @@ -100,6 +102,50 @@ pub trait SysCall { ) -> Result<(u64, T), HostError>; } +pub trait SysCallFabric { + fn create(self, args: &[SandboxValue]) -> Result; +} + +impl SysCallFabric for H +where + H: Fn() -> S, + S: SysCall, +{ + fn create(self, args: &[SandboxValue]) -> Result { + let _: [SandboxValue; 0] = args.try_into().map_err(|_| HostError)?; + Ok((self)()) + } +} + +impl SysCallFabric for H +where + H: Fn(u32) -> S, + S: SysCall, +{ + fn create(self, args: &[SandboxValue]) -> Result { + let [a]: [SandboxValue; 1] = args.try_into().map_err(|_| HostError)?; + let a = a.try_into()?; + Ok((self)(a)) + } +} + +impl SysCallFabric for H +where + H: Fn(u32, u32, u32, u32, u32, u32) -> S, + S: SysCall, +{ + fn create(self, args: &[SandboxValue]) -> Result { + let [a, b, c, d, e, f]: [SandboxValue; 6] = args.try_into().map_err(|_| HostError)?; + let a = a.try_into()?; + let b = b.try_into()?; + let c = c.try_into()?; + let d = d.try_into()?; + let e = e.try_into()?; + let f = f.try_into()?; + Ok((self)(a, b, c, d, e, f)) + } +} + struct FallibleSysCallContext { gas: u64, res_ptr: u32, @@ -171,8 +217,6 @@ where #[derive(Default)] struct FallibleSysCallError(PhantomData); -const PTR_SPECIAL: u32 = u32::MAX; - pub(crate) struct FuncsHandler { _phantom: PhantomData, } @@ -184,6 +228,26 @@ where RunFallibleError: From, Ext::AllocError: BackendAllocSyscallError, { + pub fn execute( + caller: &mut CallerWrap, + args: &[SandboxValue], + handler: H, + ) -> Result + where + H: SysCallFabric, + S: SysCall, + { + let (ctx, args) = S::Context::from_args(args)?; + let sys_call = SysCallFabric::create(handler, args)?; + // FIXME: return value is not ignored + let (gas, _value) = sys_call.execute(caller, ctx)?; + + Ok(WasmReturnValue { + gas: gas as i64, + inner: ReturnValue::Unit, + }) + } + /// !!! Usage warning: make sure to do it before any other read/write, /// because it may contain registered read. fn register_and_read_value( @@ -208,90 +272,6 @@ where .map_err(RunFallibleError::FallibleExt) } - fn sandbox() { - trait SysCallFabric { - fn create(self, args: &[SandboxValue]) -> Result; - } - - impl SysCallFabric for H - where - H: Fn() -> S, - S: SysCall, - { - fn create(self, args: &[SandboxValue]) -> Result { - let _: [SandboxValue; 0] = args.try_into().map_err(|_| HostError)?; - Ok((self)()) - } - } - - impl SysCallFabric for H - where - H: Fn(u32) -> S, - S: SysCall, - { - fn create(self, args: &[SandboxValue]) -> Result { - let [a]: [SandboxValue; 1] = args.try_into().map_err(|_| HostError)?; - let a = a.try_into()?; - Ok((self)(a)) - } - } - - impl SysCallFabric for H - where - H: Fn(u32, u32, u32, u32, u32, u32) -> S, - S: SysCall, - { - fn create(self, args: &[SandboxValue]) -> Result { - let [a, b, c, d, e, f]: [SandboxValue; 6] = - args.try_into().map_err(|_| HostError)?; - let a = a.try_into()?; - let b = b.try_into()?; - let c = c.try_into()?; - let d = d.try_into()?; - let e = e.try_into()?; - let f = f.try_into()?; - Ok((self)(a, b, c, d, e, f)) - } - } - - fn execute( - caller: &mut CallerWrap, - args: &[SandboxValue], - handler: H, - ) -> Result - where - Ext: BackendExternalities + 'static, - Ext::UnrecoverableError: BackendSyscallError, - RunFallibleError: From, - Ext::AllocError: BackendAllocSyscallError, - H: SysCallFabric, - S: SysCall, - { - let (ctx, args) = S::Context::from_args(args)?; - let sys_call = SysCallFabric::create(handler, args)?; - // FIXME: return value is not ignored - let (gas, _value) = sys_call.execute(caller, ctx)?; - - Ok(WasmReturnValue { - gas: gas as i64, - inner: ReturnValue::Unit, - }) - } - - fn check(caller: &mut CallerWrap) - where - Ext: BackendExternalities + 'static, - Ext::UnrecoverableError: BackendSyscallError, - RunFallibleError: From, - Ext::AllocError: BackendAllocSyscallError, - { - let _ = execute(caller, &[], FuncsHandler::::create_program2); - let _ = execute(caller, &[], FuncsHandler::::size2); - let _ = execute(caller, &[], FuncsHandler::::alloc2); - let _ = execute(caller, &[], FuncsHandler::::forbidden2); - } - } - pub fn forbidden2() -> impl SysCall { (RuntimeCosts::Null, |_: &mut CallerWrap| { Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) From c9f369d50ce7a4aa2a84c700ca3dfeb0f7e21791 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:48:54 +0300 Subject: [PATCH 07/37] Pass value from sys-calls --- core-backend/src/funcs.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 101ec025cee..d64d86f71c9 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -44,7 +44,7 @@ use gear_core::{ }; use gear_core_backend_codegen::host; use gear_core_errors::{MessageError, ReplyCode, SignalCode}; -use gear_sandbox::ReturnValue; +use gear_sandbox::{ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, @@ -88,6 +88,27 @@ macro_rules! syscall_trace { const PTR_SPECIAL: u32 = u32::MAX; +/// Actually just wrapper around [`ReturnValue`] to implement conversions. +pub struct SysCallReturnValue(ReturnValue); + +impl From for ReturnValue { + fn from(value: SysCallReturnValue) -> Self { + value.0 + } +} + +impl From<()> for SysCallReturnValue { + fn from((): ()) -> Self { + Self(ReturnValue::Unit) + } +} + +impl From for SysCallReturnValue { + fn from(value: u32) -> Self { + Self(ReturnValue::Value(Value::I32(value as i32))) + } +} + pub trait SysCallContext: Sized { fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError>; } @@ -236,15 +257,17 @@ where where H: SysCallFabric, S: SysCall, + R: Into, { let (ctx, args) = S::Context::from_args(args)?; let sys_call = SysCallFabric::create(handler, args)?; // FIXME: return value is not ignored - let (gas, _value) = sys_call.execute(caller, ctx)?; + let (gas, value) = sys_call.execute(caller, ctx)?; + let value = value.into(); Ok(WasmReturnValue { gas: gas as i64, - inner: ReturnValue::Unit, + inner: value.0, }) } From 5a7264da7f4deefac20ccbc73db82853a2bdfa64 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 21:50:57 +0300 Subject: [PATCH 08/37] Move `FallibleSysCallError` --- core-backend/src/funcs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index d64d86f71c9..42f7e03643d 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -182,6 +182,9 @@ impl SysCallContext for FallibleSysCallContext { } } +#[derive(Default)] +struct FallibleSysCallError(PhantomData); + type FallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); impl SysCall for FallibleSysCall @@ -235,9 +238,6 @@ where } } -#[derive(Default)] -struct FallibleSysCallError(PhantomData); - pub(crate) struct FuncsHandler { _phantom: PhantomData, } From 08861cbf5239456bd22b2452f41db2d4c4b09315 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Fri, 22 Sep 2023 22:20:37 +0300 Subject: [PATCH 09/37] Check env can be built --- core-backend/src/env.rs | 7 ++++++- core-backend/src/funcs.rs | 43 +++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 1842bcd6621..1f5d3d407dc 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -61,7 +61,7 @@ use gear_wasm_instrument::{ }; #[derive(Clone, Copy)] -pub struct SandboxValue(Value); +pub struct SandboxValue(pub Value); impl From for SandboxValue { fn from(value: i32) -> Self { @@ -333,6 +333,11 @@ where builder.add_func(Alloc, wrap_common_func!(FuncsHandler::alloc, (2) -> (1))); builder.add_func(Free, wrap_common_func!(FuncsHandler::free, (2) -> (1))); + + builder.add_func(CreateProgram, |caller, args| { + let mut caller = CallerWrap::prepare(caller)?; + FuncsHandler::execute(&mut caller, args, FuncsHandler::create_program2) + }); } } diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 42f7e03643d..d646fbb9c63 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -110,7 +110,7 @@ impl From for SysCallReturnValue { } pub trait SysCallContext: Sized { - fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError>; + fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError>; } pub trait SysCall { @@ -124,7 +124,7 @@ pub trait SysCall { } pub trait SysCallFabric { - fn create(self, args: &[SandboxValue]) -> Result; + fn create(self, args: &[Value]) -> Result; } impl SysCallFabric for H @@ -132,8 +132,8 @@ where H: Fn() -> S, S: SysCall, { - fn create(self, args: &[SandboxValue]) -> Result { - let _: [SandboxValue; 0] = args.try_into().map_err(|_| HostError)?; + fn create(self, args: &[Value]) -> Result { + let _: [Value; 0] = args.try_into().map_err(|_| HostError)?; Ok((self)()) } } @@ -143,9 +143,9 @@ where H: Fn(u32) -> S, S: SysCall, { - fn create(self, args: &[SandboxValue]) -> Result { - let [a]: [SandboxValue; 1] = args.try_into().map_err(|_| HostError)?; - let a = a.try_into()?; + fn create(self, args: &[Value]) -> Result { + let [a]: [Value; 1] = args.try_into().map_err(|_| HostError)?; + let a = SandboxValue(a).try_into()?; Ok((self)(a)) } } @@ -155,14 +155,14 @@ where H: Fn(u32, u32, u32, u32, u32, u32) -> S, S: SysCall, { - fn create(self, args: &[SandboxValue]) -> Result { - let [a, b, c, d, e, f]: [SandboxValue; 6] = args.try_into().map_err(|_| HostError)?; - let a = a.try_into()?; - let b = b.try_into()?; - let c = c.try_into()?; - let d = d.try_into()?; - let e = e.try_into()?; - let f = f.try_into()?; + fn create(self, args: &[Value]) -> Result { + let [a, b, c, d, e, f]: [Value; 6] = args.try_into().map_err(|_| HostError)?; + let a = SandboxValue(a).try_into()?; + let b = SandboxValue(b).try_into()?; + let c = SandboxValue(c).try_into()?; + let d = SandboxValue(d).try_into()?; + let e = SandboxValue(e).try_into()?; + let f = SandboxValue(f).try_into()?; Ok((self)(a, b, c, d, e, f)) } } @@ -173,11 +173,11 @@ struct FallibleSysCallContext { } impl SysCallContext for FallibleSysCallContext { - fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError> { + fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = (*gas).try_into()?; + let gas: u64 = SandboxValue(*gas).try_into()?; let (res_ptr, args) = args.split_last().ok_or(HostError)?; - let res_ptr: u32 = (*res_ptr).try_into()?; + let res_ptr: u32 = SandboxValue(*res_ptr).try_into()?; Ok((FallibleSysCallContext { gas, res_ptr }, args)) } } @@ -211,9 +211,9 @@ pub struct InfallibleSysCallContext { } impl SysCallContext for InfallibleSysCallContext { - fn from_args(args: &[SandboxValue]) -> Result<(Self, &[SandboxValue]), HostError> { + fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = (*gas).try_into()?; + let gas: u64 = SandboxValue(*gas).try_into()?; Ok((Self { gas }, args)) } } @@ -251,7 +251,7 @@ where { pub fn execute( caller: &mut CallerWrap, - args: &[SandboxValue], + args: &[Value], handler: H, ) -> Result where @@ -261,7 +261,6 @@ where { let (ctx, args) = S::Context::from_args(args)?; let sys_call = SysCallFabric::create(handler, args)?; - // FIXME: return value is not ignored let (gas, value) = sys_call.execute(caller, ctx)?; let value = value.into(); From d277f6f4a44a090a309b10874b7a8474c8784458 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sat, 23 Sep 2023 01:17:17 +0300 Subject: [PATCH 10/37] Port all sys-calls to the new design --- core-backend/src/env.rs | 184 ++--- core-backend/src/funcs.rs | 1342 ++++++++++++++++++++++--------------- 2 files changed, 862 insertions(+), 664 deletions(-) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 1f5d3d407dc..c2761e6d61c 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -51,10 +51,9 @@ use gear_sandbox::{ default_executor::{ EnvironmentDefinitionBuilder, Instance, Memory as DefaultExecutorMemory, Store, }, - AsContextExt, HostError, HostFuncType, IntoValue, ReturnValue, SandboxEnvironmentBuilder, - SandboxInstance, SandboxMemory, SandboxStore, Value, + AsContextExt, HostError, HostFuncType, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, + SandboxMemory, SandboxStore, Value, }; -use gear_sandbox_env::WasmReturnValue; use gear_wasm_instrument::{ syscalls::SysCallName::{self, *}, GLOBAL_NAME_GAS, STACK_END_EXPORT_NAME, @@ -105,56 +104,13 @@ impl TryFrom for u64 { } } -macro_rules! wrap_common_func_internal_ret{ - ($func:path, $($arg_no:expr),*) => { - |ctx, args: &[Value]| -> Result { - let mut ctx = CallerWrap::prepare(ctx).map_err(|_| HostError)?; - $func(&mut ctx, $(SandboxValue(args[$arg_no]).try_into()?,)*) - .map(|(gas, r)| WasmReturnValue { - gas: gas as i64, - inner: r.into_value().into(), - }) - } - } -} - -macro_rules! wrap_common_func_internal_no_ret{ - ($func:path, $($arg_no:expr),*) => { - |ctx, _args: &[Value]| -> Result { - let mut ctx = CallerWrap::prepare(ctx).map_err(|_| HostError)?; - $func(&mut ctx, $(SandboxValue(_args[$arg_no]).try_into()?,)*) - .map(|(gas, _)| WasmReturnValue { - gas: gas as i64, - inner: ReturnValue::Unit, - }) +macro_rules! wrap_syscall { + ($func:ident) => { + |caller, args| { + let mut caller = CallerWrap::prepare(caller)?; + FuncsHandler::execute(&mut caller, args, FuncsHandler::$func) } - } -} - -#[rustfmt::skip] -macro_rules! wrap_common_func { - ($func:path, () -> ()) => { wrap_common_func_internal_no_ret!($func,) }; - ($func:path, (1) -> ()) => { wrap_common_func_internal_no_ret!($func, 0) }; - ($func:path, (2) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1) }; - ($func:path, (3) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2) }; - ($func:path, (4) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3) }; - ($func:path, (5) -> ()) => { wrap_common_func_internal_no_ret!($func, 0, 1, 2, 3, 4) }; - ($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) }; - ($func:path, (2) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1) }; - ($func:path, (3) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2) }; - ($func:path, (4) -> (1)) => { wrap_common_func_internal_ret!($func, 0, 1, 2, 3) }; - ($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) }; + }; } fn store_host_state_mut( @@ -242,11 +198,8 @@ where f: HostFuncType>, ) { if self.forbidden_funcs.contains(&name) { - self.env_def_builder.add_host_func( - "env", - name.to_str(), - wrap_common_func!(FuncsHandler::forbidden, (1) -> ()), - ); + self.env_def_builder + .add_host_func("env", name.to_str(), wrap_syscall!(forbidden)); } else { self.env_def_builder.add_host_func("env", name.to_str(), f); } @@ -277,67 +230,62 @@ where { #[rustfmt::skip] fn bind_funcs(builder: &mut EnvBuilder) { - builder.add_func(BlockHeight, wrap_common_func!(FuncsHandler::block_height, (2) -> ())); - builder.add_func(BlockTimestamp,wrap_common_func!(FuncsHandler::block_timestamp, (2) -> ())); - builder.add_func(CreateProgram, wrap_common_func!(FuncsHandler::create_program, (8) -> ())); - builder.add_func(CreateProgramWGas, wrap_common_func!(FuncsHandler::create_program_wgas, (9) -> ())); - builder.add_func(Debug, wrap_common_func!(FuncsHandler::debug, (3) -> ())); - builder.add_func(Panic, wrap_common_func!(FuncsHandler::panic, (3) -> ())); - builder.add_func(OomPanic, wrap_common_func!(FuncsHandler::oom_panic, (1) -> ())); - builder.add_func(Exit, wrap_common_func!(FuncsHandler::exit, (2) -> ())); - builder.add_func(ReplyCode, wrap_common_func!(FuncsHandler::reply_code, (2) -> ())); - builder.add_func(SignalCode, wrap_common_func!(FuncsHandler::signal_code, (2) -> ())); - builder.add_func(ReserveGas, wrap_common_func!(FuncsHandler::reserve_gas, (4) -> ())); - builder.add_func(ReplyDeposit, wrap_common_func!(FuncsHandler::reply_deposit, (4) -> ())); - builder.add_func(UnreserveGas, wrap_common_func!(FuncsHandler::unreserve_gas, (3) -> ())); - builder.add_func(GasAvailable, wrap_common_func!(FuncsHandler::gas_available, (2) -> ())); - builder.add_func(Leave, wrap_common_func!(FuncsHandler::leave, (1) -> ())); - builder.add_func(MessageId, wrap_common_func!(FuncsHandler::message_id, (2) -> ())); - builder.add_func(PayProgramRent, wrap_common_func!(FuncsHandler::pay_program_rent, (3) -> ())); - builder.add_func(ProgramId, wrap_common_func!(FuncsHandler::program_id, (2) -> ())); - builder.add_func(Random, wrap_common_func!(FuncsHandler::random, (3) -> ())); - builder.add_func(Read, wrap_common_func!(FuncsHandler::read, (5) -> ())); - builder.add_func(Reply, wrap_common_func!(FuncsHandler::reply, (5) -> ())); - builder.add_func(ReplyCommit, wrap_common_func!(FuncsHandler::reply_commit, (3) -> ())); - builder.add_func(ReplyCommitWGas, wrap_common_func!(FuncsHandler::reply_commit_wgas, (4) -> ())); - builder.add_func(ReplyPush, wrap_common_func!(FuncsHandler::reply_push, (4) -> ())); - builder.add_func(ReplyTo, wrap_common_func!(FuncsHandler::reply_to, (2) -> ())); - builder.add_func(SignalFrom, wrap_common_func!(FuncsHandler::signal_from, (2) -> ())); - builder.add_func(ReplyWGas, wrap_common_func!(FuncsHandler::reply_wgas, (6) -> ())); - builder.add_func(ReplyInput, wrap_common_func!(FuncsHandler::reply_input, (5) -> ())); - builder.add_func(ReplyPushInput, wrap_common_func!(FuncsHandler::reply_push_input, (4) -> ())); - builder.add_func(ReplyInputWGas, wrap_common_func!(FuncsHandler::reply_input_wgas, (6) -> ())); - builder.add_func(Send, wrap_common_func!(FuncsHandler::send, (6) -> ())); - builder.add_func(SendCommit, wrap_common_func!(FuncsHandler::send_commit, (5) -> ())); - builder.add_func(SendCommitWGas, wrap_common_func!(FuncsHandler::send_commit_wgas, (6) -> ())); - builder.add_func(SendInit, wrap_common_func!(FuncsHandler::send_init, (2) -> ())); - builder.add_func(SendPush, wrap_common_func!(FuncsHandler::send_push, (5) -> ())); - builder.add_func(SendWGas, wrap_common_func!(FuncsHandler::send_wgas, (7) -> ())); - builder.add_func(SendInput, wrap_common_func!(FuncsHandler::send_input, (6) -> ())); - builder.add_func(SendPushInput, wrap_common_func!(FuncsHandler::send_push_input, (5) -> ())); - builder.add_func(SendInputWGas, wrap_common_func!(FuncsHandler::send_input_wgas, (7) -> ())); - builder.add_func(Size, wrap_common_func!(FuncsHandler::size, (2) -> ())); - builder.add_func(Source, wrap_common_func!(FuncsHandler::source, (2) -> ())); - builder.add_func(Value, wrap_common_func!(FuncsHandler::value, (2) -> ())); - builder.add_func(ValueAvailable, wrap_common_func!(FuncsHandler::value_available, (2) -> ())); - builder.add_func(Wait, wrap_common_func!(FuncsHandler::wait, (1) -> ())); - builder.add_func(WaitFor, wrap_common_func!(FuncsHandler::wait_for, (2) -> ())); - builder.add_func(WaitUpTo, wrap_common_func!(FuncsHandler::wait_up_to, (2) -> ())); - builder.add_func(Wake, wrap_common_func!(FuncsHandler::wake, (4) -> ())); - builder.add_func(SystemReserveGas, wrap_common_func!(FuncsHandler::system_reserve_gas, (3) -> ())); - builder.add_func(ReservationReply, wrap_common_func!(FuncsHandler::reservation_reply, (5) -> ())); - builder.add_func(ReservationReplyCommit, wrap_common_func!(FuncsHandler::reservation_reply_commit, (3) -> ())); - builder.add_func(ReservationSend, wrap_common_func!(FuncsHandler::reservation_send, (6) -> ())); - builder.add_func(ReservationSendCommit, wrap_common_func!(FuncsHandler::reservation_send_commit, (5) -> ())); - builder.add_func(OutOfGas, wrap_common_func!(FuncsHandler::out_of_gas, (1) -> ())); - - builder.add_func(Alloc, wrap_common_func!(FuncsHandler::alloc, (2) -> (1))); - builder.add_func(Free, wrap_common_func!(FuncsHandler::free, (2) -> (1))); - - builder.add_func(CreateProgram, |caller, args| { - let mut caller = CallerWrap::prepare(caller)?; - FuncsHandler::execute(&mut caller, args, FuncsHandler::create_program2) - }); + builder.add_func(BlockHeight, wrap_syscall!(block_height)); + builder.add_func(BlockTimestamp,wrap_syscall!(block_timestamp)); + builder.add_func(CreateProgram, wrap_syscall!(create_program)); + builder.add_func(CreateProgramWGas, wrap_syscall!(create_program_wgas)); + builder.add_func(Debug, wrap_syscall!(debug)); + builder.add_func(Panic, wrap_syscall!(panic)); + builder.add_func(OomPanic, wrap_syscall!(oom_panic)); + builder.add_func(Exit, wrap_syscall!(exit)); + builder.add_func(ReplyCode, wrap_syscall!(reply_code)); + builder.add_func(SignalCode, wrap_syscall!(signal_code)); + builder.add_func(ReserveGas, wrap_syscall!(reserve_gas)); + builder.add_func(ReplyDeposit, wrap_syscall!(reply_deposit)); + builder.add_func(UnreserveGas, wrap_syscall!(unreserve_gas)); + builder.add_func(GasAvailable, wrap_syscall!(gas_available)); + builder.add_func(Leave, wrap_syscall!(leave)); + builder.add_func(MessageId, wrap_syscall!(message_id)); + builder.add_func(PayProgramRent, wrap_syscall!(pay_program_rent)); + builder.add_func(ProgramId, wrap_syscall!(program_id)); + builder.add_func(Random, wrap_syscall!(random)); + builder.add_func(Read, wrap_syscall!(read)); + builder.add_func(Reply, wrap_syscall!(reply)); + builder.add_func(ReplyCommit, wrap_syscall!(reply_commit)); + builder.add_func(ReplyCommitWGas, wrap_syscall!(reply_commit_wgas)); + builder.add_func(ReplyPush, wrap_syscall!(reply_push)); + builder.add_func(ReplyTo, wrap_syscall!(reply_to)); + builder.add_func(SignalFrom, wrap_syscall!(signal_from)); + builder.add_func(ReplyWGas, wrap_syscall!(reply_wgas)); + builder.add_func(ReplyInput, wrap_syscall!(reply_input)); + builder.add_func(ReplyPushInput, wrap_syscall!(reply_push_input)); + builder.add_func(ReplyInputWGas, wrap_syscall!(reply_input_wgas)); + builder.add_func(Send, wrap_syscall!(send)); + builder.add_func(SendCommit, wrap_syscall!(send_commit)); + builder.add_func(SendCommitWGas, wrap_syscall!(send_commit_wgas)); + builder.add_func(SendInit, wrap_syscall!(send_init)); + builder.add_func(SendPush, wrap_syscall!(send_push)); + builder.add_func(SendWGas, wrap_syscall!(send_wgas)); + builder.add_func(SendInput, wrap_syscall!(send_input)); + builder.add_func(SendPushInput, wrap_syscall!(send_push_input)); + builder.add_func(SendInputWGas, wrap_syscall!(send_input_wgas)); + builder.add_func(Size, wrap_syscall!(size)); + builder.add_func(Source, wrap_syscall!(source)); + builder.add_func(Value, wrap_syscall!(value)); + builder.add_func(ValueAvailable, wrap_syscall!(value_available)); + builder.add_func(Wait, wrap_syscall!(wait)); + builder.add_func(WaitFor, wrap_syscall!(wait_for)); + builder.add_func(WaitUpTo, wrap_syscall!(wait_up_to)); + builder.add_func(Wake, wrap_syscall!(wake)); + builder.add_func(SystemReserveGas, wrap_syscall!(system_reserve_gas)); + builder.add_func(ReservationReply, wrap_syscall!(reservation_reply)); + builder.add_func(ReservationReplyCommit, wrap_syscall!(reservation_reply_commit)); + builder.add_func(ReservationSend, wrap_syscall!(reservation_send)); + builder.add_func(ReservationSendCommit, wrap_syscall!(reservation_send_commit)); + builder.add_func(OutOfGas, wrap_syscall!(out_of_gas)); + + builder.add_func(Alloc, wrap_syscall!(alloc)); + builder.add_func(Free, wrap_syscall!(free)); } } diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index d646fbb9c63..b39b8149b8c 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -24,7 +24,6 @@ use crate::{ TrapExplanation, UndefinedTerminationReason, UnrecoverableExecutionError, UnrecoverableMemoryError, }, - env::SandboxValue, memory::{MemoryAccessError, WasmMemoryRead}, runtime::CallerWrap, BackendExternalities, @@ -37,12 +36,12 @@ use gear_core::{ costs::RuntimeCosts, env::{DropPayloadLockBound, Externalities}, gas::CounterType, + ids::{MessageId, ProgramId}, message::{ HandlePacket, InitPacket, MessageWaitedType, Payload, PayloadSizeError, ReplyPacket, }, pages::{PageNumber, PageU32Size, WasmPage}, }; -use gear_core_backend_codegen::host; use gear_core_errors::{MessageError, ReplyCode, SignalCode}; use gear_sandbox::{ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; @@ -103,6 +102,12 @@ impl From<()> for SysCallReturnValue { } } +impl From for SysCallReturnValue { + fn from(value: i32) -> Self { + Self(ReturnValue::Value(Value::I32(value))) + } +} + impl From for SysCallReturnValue { fn from(value: u32) -> Self { Self(ReturnValue::Value(Value::I32(value as i32))) @@ -123,7 +128,7 @@ pub trait SysCall { ) -> Result<(u64, T), HostError>; } -pub trait SysCallFabric { +pub trait SysCallFabric { fn create(self, args: &[Value]) -> Result; } @@ -138,32 +143,66 @@ where } } -impl SysCallFabric for H +impl SysCallFabric for H where - H: Fn(u32) -> S, + H: for<'a> Fn(&'a [Value]) -> S, S: SysCall, { fn create(self, args: &[Value]) -> Result { - let [a]: [Value; 1] = args.try_into().map_err(|_| HostError)?; - let a = SandboxValue(a).try_into()?; - Ok((self)(a)) + Ok((self)(args)) } } -impl SysCallFabric for H +macro_rules! impl_syscall_fabric { + ($($generic:ident),+) => { + #[allow(non_snake_case)] + impl SysCallFabric + for Handler + where + Handler: Fn($($generic),+) -> Call, + Call: SysCall, + $( $generic: TryFrom,)+ + { + fn create(self, args: &[Value]) -> Result { + const ARGS_AMOUNT: usize = impl_syscall_fabric!(@count $($generic),+); + + let [$($generic),+]: [Value; ARGS_AMOUNT] = args.try_into().map_err(|_| HostError)?; + $( + let $generic = SandboxValue($generic).try_into()?; + )+ + Ok((self)($($generic),+)) + } + } + }; + (@count $generic:ident) => { 1 }; + (@count $generic:ident, $($generics:ident),+) => { 1 + impl_syscall_fabric!(@count $($generics),+) }; +} + +impl_syscall_fabric!(A); +impl_syscall_fabric!(A, B); +impl_syscall_fabric!(A, B, C); +impl_syscall_fabric!(A, B, C, D); +impl_syscall_fabric!(A, B, C, D, E); +impl_syscall_fabric!(A, B, C, D, E, F); +impl_syscall_fabric!(A, B, C, D, E, F, G); + +type SimpleSysCall = F; + +impl SysCall for SimpleSysCall where - H: Fn(u32, u32, u32, u32, u32, u32) -> S, - S: SysCall, + F: Fn(&mut CallerWrap) -> Result, + Ext: BackendExternalities + 'static, { - fn create(self, args: &[Value]) -> Result { - let [a, b, c, d, e, f]: [Value; 6] = args.try_into().map_err(|_| HostError)?; - let a = SandboxValue(a).try_into()?; - let b = SandboxValue(b).try_into()?; - let c = SandboxValue(c).try_into()?; - let d = SandboxValue(d).try_into()?; - let e = SandboxValue(e).try_into()?; - let f = SandboxValue(f).try_into()?; - Ok((self)(a, b, c, d, e, f)) + type Context = InfallibleSysCallContext; + + fn execute( + &self, + caller: &mut CallerWrap, + ctx: Self::Context, + ) -> Result<(u64, T), HostError> { + let res = (self)(caller)?; + let InfallibleSysCallContext { gas } = ctx; + Ok((gas, res)) } } @@ -256,6 +295,7 @@ where ) -> Result where H: SysCallFabric, + Args: ?Sized, S: SysCall, R: Into, { @@ -294,706 +334,858 @@ where .map_err(RunFallibleError::FallibleExt) } - pub fn forbidden2() -> impl SysCall { - (RuntimeCosts::Null, |_: &mut CallerWrap| { - Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) - }) + fn send_inner( + ctx: &mut CallerWrap, + pid_value_ptr: u32, + payload_ptr: u32, + len: u32, + gas_limit: Option, + delay: u32, + ) -> Result { + let read_hash_val = ctx.manager.register_read_as(pid_value_ptr); + let read_payload = ctx.manager.register_read(payload_ptr, len); + let HashWithValue { + hash: destination, + value, + } = ctx.read_as(read_hash_val)?; + let payload = Self::read_message_payload(ctx, read_payload)?; + + let packet = if let Some(gas_limit) = gas_limit { + HandlePacket::new_with_gas(destination.into(), payload, gas_limit, value) + } else { + HandlePacket::new(destination.into(), payload, value) + }; + + ctx.ext_mut().send(packet, delay).map_err(Into::into) } - pub fn alloc2(pages: u32) -> impl SysCall { + pub fn send(pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32) -> impl SysCall { ( - RuntimeCosts::Alloc(pages), + RuntimeCosts::Send(len), + FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { - let res = ctx.alloc(pages); - let res = ctx.process_alloc_func_result(res)?; - - let page = match res { - Ok(page) => { - log::trace!("Alloc {pages:?} pages at {page:?}"); - page.raw() - } - Err(err) => { - log::trace!("Alloc failed: {err}"); - u32::MAX - } - }; - Ok(page) + Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, None, delay) }, ) } - pub fn create_program2( - cid_value_ptr: u32, - salt_ptr: u32, - salt_len: u32, + pub fn send_wgas( + pid_value_ptr: u32, payload_ptr: u32, - payload_len: u32, + len: u32, + gas_limit: u64, delay: u32, ) -> impl SysCall { ( - RuntimeCosts::CreateProgram(payload_len, salt_len), - FallibleSysCallError::::default(), - move |ctx: &mut CallerWrap| -> Result<_, RunFallibleError> { - let read_cid_value = ctx.manager.register_read_as(cid_value_ptr); - let read_salt = ctx.manager.register_read(salt_ptr, salt_len); - let read_payload = ctx.manager.register_read(payload_ptr, payload_len); - let HashWithValue { - hash: code_id, - value, - } = ctx.read_as(read_cid_value)?; - let salt = Self::read_message_payload(ctx, read_salt)?; - let payload = Self::read_message_payload(ctx, read_payload)?; - - ctx.ext_mut() - .create_program(InitPacket::new(code_id.into(), salt, payload, value), delay) - .map_err(Into::into) + RuntimeCosts::Send(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, Some(gas_limit), delay) }, ) } - pub fn size2(size_ptr: u32) -> impl SysCall { - (RuntimeCosts::Size, move |ctx: &mut CallerWrap| { - let size = ctx.ext_mut().size()? as u32; - - let write_size = ctx.manager.register_write_as(size_ptr); - ctx.write_as(write_size, size.to_le_bytes()) - .map_err(Into::into) - }) - } - - // TODO #3037 - #[allow(clippy::too_many_arguments)] - #[host(fallible, wgas, cost = RuntimeCosts::Send(len))] - pub fn send( - ctx: &mut CallerWrap<'_, '_, Ext>, + fn send_commit_inner( + ctx: &mut CallerWrap, + handle: u32, pid_value_ptr: u32, - payload_ptr: u32, - len: u32, + gas_limit: Option, delay: u32, - ) -> Result<(), HostError> { - let read_hash_val = ctx.manager.register_read_as(pid_value_ptr); - let read_payload = ctx.manager.register_read(payload_ptr, len); + ) -> Result { + let read_pid_value = ctx.manager.register_read_as(pid_value_ptr); let HashWithValue { hash: destination, value, - } = ctx.read_as(read_hash_val)?; - let payload = Self::read_message_payload(ctx, read_payload)?; + } = ctx.read_as(read_pid_value)?; + + let packet = if let Some(gas_limit) = gas_limit { + HandlePacket::new_with_gas(destination.into(), Default::default(), gas_limit, value) + } else { + HandlePacket::new(destination.into(), Default::default(), value) + }; ctx.ext_mut() - .send(HandlePacket::new(destination.into(), payload, value), delay) + .send_commit(handle, packet, delay) .map_err(Into::into) } - #[host(fallible, wgas, cost = RuntimeCosts::SendCommit)] - pub fn send_commit( - ctx: &mut CallerWrap<'_, '_, Ext>, + pub fn send_commit(handle: u32, pid_value_ptr: u32, delay: u32) -> impl SysCall { + ( + RuntimeCosts::SendCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::send_commit_inner(ctx, handle, pid_value_ptr, None, delay) + }, + ) + } + + pub fn send_commit_wgas( handle: u32, pid_value_ptr: u32, + gas_limit: u64, delay: u32, - ) -> Result<(), HostError> { - let read_pid_value = ctx.manager.register_read_as(pid_value_ptr); - let HashWithValue { - hash: destination, - value, - } = ctx.read_as(read_pid_value)?; - - ctx.ext_mut() - .send_commit( - handle, - HandlePacket::new(destination.into(), Default::default(), value), - delay, - ) - .map_err(Into::into) + ) -> impl SysCall { + ( + RuntimeCosts::SendCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::send_commit_inner(ctx, handle, pid_value_ptr, Some(gas_limit), delay) + }, + ) } - #[host(fallible, cost = RuntimeCosts::SendInit, err = ErrorWithHandle)] - pub fn send_init(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut().send_init().map_err(Into::into) + pub fn send_init() -> impl SysCall { + ( + RuntimeCosts::SendInit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| ctx.ext_mut().send_init().map_err(Into::into), + ) } - #[host(fallible, cost = RuntimeCosts::SendPush(len), err = ErrorBytes)] - pub fn send_push( - ctx: &mut CallerWrap<'_, '_, Ext>, - handle: u32, - payload_ptr: u32, - len: u32, - ) -> Result<(), HostError> { - let read_payload = ctx.manager.register_read(payload_ptr, len); - let payload = ctx.read(read_payload)?; + pub fn send_push(handle: u32, payload_ptr: u32, len: u32) -> impl SysCall { + ( + RuntimeCosts::SendPush(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_payload = ctx.manager.register_read(payload_ptr, len); + let payload = ctx.read(read_payload)?; - ctx.ext_mut() - .send_push(handle, &payload) - .map_err(Into::into) + ctx.ext_mut() + .send_push(handle, &payload) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::ReservationSend(len))] pub fn reservation_send( - ctx: &mut CallerWrap<'_, '_, Ext>, rid_pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32, - ) -> Result<(), HostError> { - let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); - let read_payload = ctx.manager.register_read(payload_ptr, len); - let TwoHashesWithValue { - hash1: reservation_id, - hash2: destination, - value, - } = ctx.read_as(read_rid_pid_value)?; - let payload = Self::read_message_payload(ctx, read_payload)?; + ) -> impl SysCall { + ( + RuntimeCosts::ReservationSend(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); + let read_payload = ctx.manager.register_read(payload_ptr, len); + let TwoHashesWithValue { + hash1: reservation_id, + hash2: destination, + value, + } = ctx.read_as(read_rid_pid_value)?; + let payload = Self::read_message_payload(ctx, read_payload)?; - ctx.ext_mut() - .reservation_send( - reservation_id.into(), - HandlePacket::new(destination.into(), payload, value), - delay, - ) - .map_err(Into::into) + ctx.ext_mut() + .reservation_send( + reservation_id.into(), + HandlePacket::new(destination.into(), payload, value), + delay, + ) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::ReservationSendCommit)] pub fn reservation_send_commit( - ctx: &mut CallerWrap<'_, '_, Ext>, handle: u32, rid_pid_value_ptr: u32, delay: u32, - ) -> Result<(), HostError> { - let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); - let TwoHashesWithValue { - hash1: reservation_id, - hash2: destination, - value, - } = ctx.read_as(read_rid_pid_value)?; + ) -> impl SysCall { + ( + RuntimeCosts::ReservationSendCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); + let TwoHashesWithValue { + hash1: reservation_id, + hash2: destination, + value, + } = ctx.read_as(read_rid_pid_value)?; - ctx.ext_mut() - .reservation_send_commit( - reservation_id.into(), - handle, - HandlePacket::new(destination.into(), Default::default(), value), - delay, - ) - .map_err(Into::into) + ctx.ext_mut() + .reservation_send_commit( + reservation_id.into(), + handle, + HandlePacket::new(destination.into(), Default::default(), value), + delay, + ) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::Read, err = ErrorBytes)] - pub fn read( - ctx: &mut CallerWrap<'_, '_, Ext>, - at: u32, - len: u32, - buffer_ptr: u32, - ) -> Result<(), HostError> { - let payload_lock = ctx.ext_mut().lock_payload(at, len)?; - payload_lock - .drop_with::(|payload_access| { - let write_buffer = ctx.manager.register_write(buffer_ptr, len); - let write_res = ctx.write(write_buffer, payload_access.as_slice()); - let unlock_bound = ctx.ext_mut().unlock_payload(payload_access.into_lock()); - - DropPayloadLockBound::from((unlock_bound, write_res)) - }) - .into_inner() - .map_err(Into::into) + pub fn read(at: u32, len: u32, buffer_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::Read, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let payload_lock = ctx.ext_mut().lock_payload(at, len)?; + payload_lock + .drop_with::(|payload_access| { + let write_buffer = ctx.manager.register_write(buffer_ptr, len); + let write_res = ctx.write(write_buffer, payload_access.as_slice()); + let unlock_bound = ctx.ext_mut().unlock_payload(payload_access.into_lock()); + + DropPayloadLockBound::from((unlock_bound, write_res)) + }) + .into_inner() + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::Size)] - pub fn size(ctx: &mut CallerWrap<'_, '_, Ext>, size_ptr: u32) -> Result<(), HostError> { - let size = ctx.ext_mut().size()? as u32; + pub fn size(size_ptr: u32) -> impl SysCall { + (RuntimeCosts::Size, move |ctx: &mut CallerWrap| { + let size = ctx.ext_mut().size()? as u32; - let write_size = ctx.manager.register_write_as(size_ptr); - ctx.write_as(write_size, size.to_le_bytes()) - .map_err(Into::into) + let write_size = ctx.manager.register_write_as(size_ptr); + ctx.write_as(write_size, size.to_le_bytes()) + .map_err(Into::into) + }) } - #[host(cost = RuntimeCosts::Exit)] - pub fn exit(ctx: &mut CallerWrap<'_, '_, Ext>, inheritor_id_ptr: u32) -> Result<(), HostError> { - let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); - let inheritor_id = ctx.read_decoded(read_inheritor_id)?; - Err(ActorTerminationReason::Exit(inheritor_id).into()) + pub fn exit(inheritor_id_ptr: u32) -> impl SysCall { + (RuntimeCosts::Exit, move |ctx: &mut CallerWrap| { + let read_inheritor_id = ctx.manager.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 CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut() - .reply_code() - .map(ReplyCode::to_bytes) - .map_err(Into::into) + pub fn reply_code() -> impl SysCall { + ( + RuntimeCosts::ReplyCode, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + ctx.ext_mut() + .reply_code() + .map(ReplyCode::to_bytes) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::SignalCode, err = ErrorWithSignalCode)] - pub fn signal_code(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut() - .signal_code() - .map(SignalCode::to_u32) - .map_err(Into::into) + pub fn signal_code() -> impl SysCall { + ( + RuntimeCosts::SignalCode, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + ctx.ext_mut() + .signal_code() + .map(SignalCode::to_u32) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::Alloc(pages))] - pub fn alloc(ctx: &mut CallerWrap<'_, '_, Ext>, pages: u32) -> Result { - let res = ctx.alloc(pages); - let res = ctx.process_alloc_func_result(res)?; + pub fn alloc(pages: u32) -> impl SysCall { + ( + RuntimeCosts::Alloc(pages), + move |ctx: &mut CallerWrap| { + let res = ctx.alloc(pages); + let res = ctx.process_alloc_func_result(res)?; - let page = match res { - Ok(page) => { - log::trace!("Alloc {pages:?} pages at {page:?}"); - page.raw() - } - Err(err) => { - log::trace!("Alloc failed: {err}"); - u32::MAX - } - }; - Ok(page) + let page = match res { + Ok(page) => { + log::trace!("Alloc {pages:?} pages at {page:?}"); + page.raw() + } + Err(err) => { + log::trace!("Alloc failed: {err}"); + u32::MAX + } + }; + Ok(page) + }, + ) } - #[host(cost = RuntimeCosts::Free)] - pub fn free(ctx: &mut CallerWrap<'_, '_, Ext>, page_no: u32) -> Result { - let page = WasmPage::new(page_no).map_err(|_| { - UndefinedTerminationReason::Actor(ActorTerminationReason::Trap( - TrapExplanation::Unknown, - )) - })?; + pub fn free(page_no: u32) -> impl SysCall { + (RuntimeCosts::Free, move |ctx: &mut CallerWrap| { + let page = WasmPage::new(page_no).map_err(|_| { + UndefinedTerminationReason::Actor(ActorTerminationReason::Trap( + TrapExplanation::Unknown, + )) + })?; - let res = ctx.ext_mut().free(page); - let res = ctx.process_alloc_func_result(res)?; + let res = ctx.ext_mut().free(page); + let res = ctx.process_alloc_func_result(res)?; - match &res { - Ok(()) => { - log::trace!("Free {page:?}"); - } - Err(err) => { - log::trace!("Free failed: {err}"); - } - }; + match &res { + Ok(()) => { + log::trace!("Free {page:?}"); + } + Err(err) => { + log::trace!("Free failed: {err}"); + } + }; - Ok(res.is_err() as i32) + Ok(res.is_err() as i32) + }) } - #[host(cost = RuntimeCosts::BlockHeight)] - pub fn block_height( - ctx: &mut CallerWrap<'_, '_, Ext>, - height_ptr: u32, - ) -> Result<(), HostError> { - let height = ctx.ext_mut().block_height()?; + pub fn block_height(height_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::BlockHeight, + move |ctx: &mut CallerWrap| { + let height = ctx.ext_mut().block_height()?; - let write_height = ctx.manager.register_write_as(height_ptr); - ctx.write_as(write_height, height.to_le_bytes()) - .map_err(Into::into) + let write_height = ctx.manager.register_write_as(height_ptr); + ctx.write_as(write_height, height.to_le_bytes()) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::BlockTimestamp)] - pub fn block_timestamp( - ctx: &mut CallerWrap<'_, '_, Ext>, - timestamp_ptr: u32, - ) -> Result<(), HostError> { - let timestamp = ctx.ext_mut().block_timestamp()?; + pub fn block_timestamp(timestamp_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::BlockTimestamp, + move |ctx: &mut CallerWrap| { + let timestamp = ctx.ext_mut().block_timestamp()?; - let write_timestamp = ctx.manager.register_write_as(timestamp_ptr); - ctx.write_as(write_timestamp, timestamp.to_le_bytes()) - .map_err(Into::into) + let write_timestamp = ctx.manager.register_write_as(timestamp_ptr); + ctx.write_as(write_timestamp, timestamp.to_le_bytes()) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::Random)] - pub fn random( - ctx: &mut CallerWrap<'_, '_, Ext>, - subject_ptr: u32, - bn_random_ptr: u32, - ) -> Result<(), HostError> { - let read_subject = ctx.manager.register_read_decoded(subject_ptr); - let write_bn_random = ctx.manager.register_write_as(bn_random_ptr); + pub fn random(subject_ptr: u32, bn_random_ptr: u32) -> impl SysCall { + (RuntimeCosts::Random, move |ctx: &mut CallerWrap| { + let read_subject = ctx.manager.register_read_decoded(subject_ptr); + let write_bn_random = ctx.manager.register_write_as(bn_random_ptr); - let raw_subject: Hash = ctx.read_decoded(read_subject)?; + let raw_subject: Hash = ctx.read_decoded(read_subject)?; - let (random, bn) = ctx.ext_mut().random()?; - let subject = [&raw_subject, random].concat(); + let (random, bn) = ctx.ext_mut().random()?; + let subject = [&raw_subject, random].concat(); - let mut hash = [0; 32]; - hash.copy_from_slice(blake2b(32, &[], &subject).as_bytes()); + let mut hash = [0; 32]; + hash.copy_from_slice(blake2b(32, &[], &subject).as_bytes()); - ctx.write_as(write_bn_random, BlockNumberWithHash { bn, hash }) - .map_err(Into::into) + ctx.write_as(write_bn_random, BlockNumberWithHash { bn, hash }) + .map_err(Into::into) + }) } - #[host(fallible, wgas, cost = RuntimeCosts::Reply(len))] - pub fn reply( - ctx: &mut CallerWrap<'_, '_, Ext>, + /* + gas: u64, + payload_ptr: u32, + len: u32, + gas_limit: u64, + value_ptr: u32, + err_mid_ptr: u32 + */ + + fn reply_inner( + ctx: &mut CallerWrap, payload_ptr: u32, len: u32, + gas_limit: Option, value_ptr: u32, - ) -> Result<(), HostError> { + ) -> Result { let read_payload = ctx.manager.register_read(payload_ptr, len); let value = Self::register_and_read_value(ctx, value_ptr)?; let payload = Self::read_message_payload(ctx, read_payload)?; - ctx.ext_mut() - .reply(ReplyPacket::new(payload, value)) - .map_err(Into::into) - } + let packet = if let Some(gas_limit) = gas_limit { + ReplyPacket::new_with_gas(payload, gas_limit, value) + } else { + ReplyPacket::new(payload, value) + }; - #[host(fallible, wgas, cost = RuntimeCosts::ReplyCommit)] - pub fn reply_commit( - ctx: &mut CallerWrap<'_, '_, Ext>, - value_ptr: u32, - ) -> Result<(), HostError> { - let value = Self::register_and_read_value(ctx, value_ptr)?; + ctx.ext_mut().reply(packet).map_err(Into::into) + } - ctx.ext_mut() - .reply_commit(ReplyPacket::new(Default::default(), value)) - .map_err(Into::into) + pub fn reply(payload_ptr: u32, len: u32, value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::Reply(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::reply_inner(ctx, payload_ptr, len, None, value_ptr) + }, + ) } - #[host(fallible, cost = RuntimeCosts::ReservationReply(len))] - pub fn reservation_reply( - ctx: &mut CallerWrap<'_, '_, Ext>, - rid_value_ptr: u32, + pub fn reply_wgas( payload_ptr: u32, len: u32, - ) -> Result<(), HostError> { - let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); - let read_payload = ctx.manager.register_read(payload_ptr, len); - let HashWithValue { - hash: reservation_id, - value, - } = ctx.read_as(read_rid_value)?; - let payload = Self::read_message_payload(ctx, read_payload)?; + gas_limit: u64, + value_ptr: u32, + ) -> impl SysCall { + ( + RuntimeCosts::Reply(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::reply_inner(ctx, payload_ptr, len, Some(gas_limit), value_ptr) + }, + ) + } - ctx.ext_mut() - .reservation_reply(reservation_id.into(), ReplyPacket::new(payload, value)) - .map_err(Into::into) + fn reply_commit_inner( + ctx: &mut CallerWrap, + gas_limit: Option, + value_ptr: u32, + ) -> Result { + let value = Self::register_and_read_value(ctx, value_ptr)?; + + let packet = if let Some(gas_limit) = gas_limit { + ReplyPacket::new_with_gas(Default::default(), gas_limit, value) + } else { + ReplyPacket::new(Default::default(), value) + }; + + ctx.ext_mut().reply_commit(packet).map_err(Into::into) } - #[host(fallible, cost = RuntimeCosts::ReservationReplyCommit)] - pub fn reservation_reply_commit( - ctx: &mut CallerWrap<'_, '_, Ext>, - rid_value_ptr: u32, - ) -> Result<(), HostError> { - let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); - let HashWithValue { - hash: reservation_id, - value, - } = ctx.read_as(read_rid_value)?; + pub fn reply_commit(value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::ReplyCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| Self::reply_commit_inner(ctx, None, value_ptr), + ) + } - ctx.ext_mut() - .reservation_reply_commit( - reservation_id.into(), - ReplyPacket::new(Default::default(), value), - ) - .map_err(Into::into) + pub fn reply_commit_wgas(gas_limit: u64, value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::ReplyCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::reply_commit_inner(ctx, Some(gas_limit), value_ptr) + }, + ) } - #[host(fallible, cost = RuntimeCosts::ReplyTo)] - pub fn reply_to(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut().reply_to().map_err(Into::into) + pub fn reservation_reply(rid_value_ptr: u32, payload_ptr: u32, len: u32) -> impl SysCall { + ( + RuntimeCosts::ReservationReply(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); + let read_payload = ctx.manager.register_read(payload_ptr, len); + let HashWithValue { + hash: reservation_id, + value, + } = ctx.read_as(read_rid_value)?; + let payload = Self::read_message_payload(ctx, read_payload)?; + + ctx.ext_mut() + .reservation_reply(reservation_id.into(), ReplyPacket::new(payload, value)) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::SignalFrom)] - pub fn signal_from(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut().signal_from().map_err(Into::into) + pub fn reservation_reply_commit(rid_value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::ReservationReplyCommit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); + let HashWithValue { + hash: reservation_id, + value, + } = ctx.read_as(read_rid_value)?; + + ctx.ext_mut() + .reservation_reply_commit( + reservation_id.into(), + ReplyPacket::new(Default::default(), value), + ) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::ReplyPush(len), err = ErrorBytes)] - pub fn reply_push( - ctx: &mut CallerWrap<'_, '_, Ext>, - payload_ptr: u32, - len: u32, - ) -> Result<(), HostError> { - let read_payload = ctx.manager.register_read(payload_ptr, len); - let payload = ctx.read(read_payload)?; + pub fn reply_to() -> impl SysCall { + ( + RuntimeCosts::ReplyTo, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| ctx.ext_mut().reply_to().map_err(Into::into), + ) + } - ctx.ext_mut().reply_push(&payload).map_err(Into::into) + pub fn signal_from() -> impl SysCall { + ( + RuntimeCosts::SignalFrom, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| ctx.ext_mut().signal_from().map_err(Into::into), + ) } - #[host(fallible, wgas, cost = RuntimeCosts::ReplyInput)] - pub fn reply_input( - ctx: &mut CallerWrap<'_, '_, Ext>, + pub fn reply_push(payload_ptr: u32, len: u32) -> impl SysCall { + ( + RuntimeCosts::ReplyPush(len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_payload = ctx.manager.register_read(payload_ptr, len); + let payload = ctx.read(read_payload)?; + + ctx.ext_mut().reply_push(&payload).map_err(Into::into) + }, + ) + } + + fn reply_input_inner( + ctx: &mut CallerWrap, offset: u32, len: u32, + gas_limit: Option, value_ptr: u32, - ) -> Result<(), HostError> { - // Charge for `len` is inside `reply_push_input` + ) -> Result { let value = Self::register_and_read_value(ctx, value_ptr)?; - let mut f = || { - ctx.ext_mut().reply_push_input(offset, len)?; - ctx.ext_mut() - .reply_commit(ReplyPacket::new(Default::default(), value)) + // Charge for `len` is inside `reply_push_input` + ctx.ext_mut().reply_push_input(offset, len)?; + + let packet = if let Some(gas_limit) = gas_limit { + ReplyPacket::new_with_gas(Default::default(), gas_limit, value) + } else { + ReplyPacket::new(Default::default(), value) }; - f().map_err(Into::into) + ctx.ext_mut().reply_commit(packet).map_err(Into::into) } - #[host(fallible, cost = RuntimeCosts::ReplyPushInput, err = ErrorBytes)] - pub fn reply_push_input( - ctx: &mut CallerWrap<'_, '_, Ext>, + pub fn reply_input(offset: u32, len: u32, value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::ReplyInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::reply_input_inner(ctx, offset, len, None, value_ptr) + }, + ) + } + + pub fn reply_input_wgas( offset: u32, len: u32, - ) -> Result<(), HostError> { - ctx.ext_mut() - .reply_push_input(offset, len) - .map_err(Into::into) + gas_limit: u64, + value_ptr: u32, + ) -> impl SysCall { + ( + RuntimeCosts::ReplyInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::reply_input_inner(ctx, offset, len, Some(gas_limit), value_ptr) + }, + ) } - #[allow(clippy::too_many_arguments)] - #[host(fallible, wgas, cost = RuntimeCosts::SendInput)] - pub fn send_input( - ctx: &mut CallerWrap<'_, '_, Ext>, + pub fn reply_push_input(offset: u32, len: u32) -> impl SysCall { + ( + RuntimeCosts::ReplyPushInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + ctx.ext_mut() + .reply_push_input(offset, len) + .map_err(Into::into) + }, + ) + } + + fn send_input_inner( + ctx: &mut CallerWrap, pid_value_ptr: u32, offset: u32, len: u32, + gas_limit: Option, delay: u32, - ) -> Result<(), HostError> { - // Charge for `len` inside `send_push_input` + ) -> Result { let read_pid_value = ctx.manager.register_read_as(pid_value_ptr); let HashWithValue { hash: destination, value, } = ctx.read_as(read_pid_value)?; - let mut f = || { - let handle = ctx.ext_mut().send_init()?; - ctx.ext_mut().send_push_input(handle, offset, len)?; - ctx.ext_mut().send_commit( - handle, - HandlePacket::new(destination.into(), Default::default(), value), - delay, - ) + let handle = ctx.ext_mut().send_init()?; + // Charge for `len` inside `send_push_input` + ctx.ext_mut().send_push_input(handle, offset, len)?; + + let packet = if let Some(gas_limit) = gas_limit { + HandlePacket::new_with_gas(destination.into(), Default::default(), gas_limit, value) + } else { + HandlePacket::new(destination.into(), Default::default(), value) }; - f().map_err(Into::into) + ctx.ext_mut() + .send_commit(handle, packet, delay) + .map_err(Into::into) + } + + pub fn send_input(pid_value_ptr: u32, offset: u32, len: u32, delay: u32) -> impl SysCall { + ( + RuntimeCosts::SendInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::send_input_inner(ctx, pid_value_ptr, offset, len, None, delay) + }, + ) } - #[host(fallible, cost = RuntimeCosts::SendPushInput, err = ErrorBytes)] - pub fn send_push_input( - ctx: &mut CallerWrap<'_, '_, Ext>, - handle: u32, + pub fn send_input_wgas( + pid_value_ptr: u32, offset: u32, len: u32, - ) -> Result<(), HostError> { - ctx.ext_mut() - .send_push_input(handle, offset, len) - .map_err(Into::into) + gas_limit: u64, + delay: u32, + ) -> impl SysCall { + ( + RuntimeCosts::SendInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::send_input_inner(ctx, pid_value_ptr, offset, len, Some(gas_limit), delay) + }, + ) } - #[host(cost = RuntimeCosts::Debug(data_len))] - pub fn debug( - ctx: &mut CallerWrap<'_, '_, Ext>, - data_ptr: u32, - data_len: u32, - ) -> Result<(), HostError> { - let read_data = ctx.manager.register_read(data_ptr, data_len); - let data: RuntimeBuffer = ctx - .read(read_data)? - .try_into() - .map_err(|RuntimeBufferSizeError| { - UnrecoverableMemoryError::RuntimeAllocOutOfBounds.into() - }) - .map_err(TrapExplanation::UnrecoverableExt)?; - - let s = String::from_utf8(data.into_vec()) - .map_err(|_err| UnrecoverableExecutionError::InvalidDebugString.into()) - .map_err(TrapExplanation::UnrecoverableExt)?; - ctx.ext_mut().debug(&s)?; + pub fn send_push_input(handle: u32, offset: u32, len: u32) -> impl SysCall { + ( + RuntimeCosts::SendPushInput, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + ctx.ext_mut() + .send_push_input(handle, offset, len) + .map_err(Into::into) + }, + ) + } - Ok(()) + pub fn debug(data_ptr: u32, data_len: u32) -> impl SysCall { + ( + RuntimeCosts::Debug(data_len), + move |ctx: &mut CallerWrap| { + let read_data = ctx.manager.register_read(data_ptr, data_len); + let data: RuntimeBuffer = ctx + .read(read_data)? + .try_into() + .map_err(|RuntimeBufferSizeError| { + UnrecoverableMemoryError::RuntimeAllocOutOfBounds.into() + }) + .map_err(TrapExplanation::UnrecoverableExt)?; + + let s = String::from_utf8(data.into_vec()) + .map_err(|_err| UnrecoverableExecutionError::InvalidDebugString.into()) + .map_err(TrapExplanation::UnrecoverableExt)?; + ctx.ext_mut().debug(&s)?; + + Ok(()) + }, + ) } - #[host(cost = RuntimeCosts::Null)] - pub fn panic( - ctx: &mut CallerWrap<'_, '_, Ext>, - data_ptr: u32, - data_len: u32, - ) -> Result<(), HostError> { - let read_data = ctx.manager.register_read(data_ptr, data_len); - let data = ctx.read(read_data).unwrap_or_default(); + pub fn panic(data_ptr: u32, data_len: u32) -> impl SysCall { + (RuntimeCosts::Null, move |ctx: &mut CallerWrap| { + let read_data = ctx.manager.register_read(data_ptr, data_len); + let data = ctx.read(read_data).unwrap_or_default(); - let s = String::from_utf8_lossy(&data).to_string(); + let s = String::from_utf8_lossy(&data).to_string(); - Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) + Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) + }) } - #[host(cost = RuntimeCosts::Null)] - pub fn oom_panic(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) + pub fn oom_panic() -> impl SysCall { + (RuntimeCosts::Null, |_ctx: &mut CallerWrap| { + Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) + }) } - #[host(fallible, cost = RuntimeCosts::ReserveGas)] - pub fn reserve_gas( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas_value: u64, - duration: u32, - ) -> Result<(), HostError> { - ctx.ext_mut() - .reserve_gas(gas_value, duration) - .map_err(Into::into) + pub fn reserve_gas(gas_value: u64, duration: u32) -> impl SysCall { + ( + RuntimeCosts::ReserveGas, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + 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 CallerWrap<'_, '_, Ext>, - message_id_ptr: u32, - gas_value: u64, - ) -> Result<(), HostError> { - let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); - let message_id = ctx.read_decoded(read_message_id)?; + pub fn reply_deposit(message_id_ptr: u32, gas_value: u64) -> impl SysCall { + ( + RuntimeCosts::ReplyDeposit, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); + let message_id = ctx.read_decoded(read_message_id)?; - ctx.ext_mut() - .reply_deposit(message_id, gas_value) - .map_err(Into::into) + ctx.ext_mut() + .reply_deposit(message_id, gas_value) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::UnreserveGas, err = ErrorWithGas)] - pub fn unreserve_gas( - ctx: &mut CallerWrap<'_, '_, Ext>, - reservation_id_ptr: u32, - ) -> Result<(), HostError> { - let read_reservation_id = ctx.manager.register_read_decoded(reservation_id_ptr); - let reservation_id = ctx.read_decoded(read_reservation_id)?; + pub fn unreserve_gas(reservation_id_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::UnreserveGas, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_reservation_id = ctx.manager.register_read_decoded(reservation_id_ptr); + let reservation_id = ctx.read_decoded(read_reservation_id)?; - ctx.ext_mut() - .unreserve_gas(reservation_id) - .map_err(Into::into) + ctx.ext_mut() + .unreserve_gas(reservation_id) + .map_err(Into::into) + }, + ) } - #[host(fallible, cost = RuntimeCosts::SystemReserveGas, err = ErrorBytes)] - pub fn system_reserve_gas( - ctx: &mut CallerWrap<'_, '_, Ext>, - gas_value: u64, - ) -> Result<(), HostError> { - ctx.ext_mut() - .system_reserve_gas(gas_value) - .map_err(Into::into) + pub fn system_reserve_gas(gas_value: u64) -> impl SysCall { + ( + RuntimeCosts::SystemReserveGas, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + ctx.ext_mut() + .system_reserve_gas(gas_value) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::GasAvailable)] - pub fn gas_available(ctx: &mut CallerWrap<'_, '_, Ext>, gas_ptr: u32) -> Result<(), HostError> { - let gas_available = ctx.ext_mut().gas_available()?; + pub fn gas_available(gas_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::GasAvailable, + move |ctx: &mut CallerWrap| { + let gas_available = ctx.ext_mut().gas_available()?; - let write_gas = ctx.manager.register_write_as(gas_ptr); - ctx.write_as(write_gas, gas_available.to_le_bytes()) - .map_err(Into::into) + let write_gas = ctx.manager.register_write_as(gas_ptr); + ctx.write_as(write_gas, gas_available.to_le_bytes()) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::MessageId)] - pub fn message_id( - ctx: &mut CallerWrap<'_, '_, Ext>, - message_id_ptr: u32, - ) -> Result<(), HostError> { - let message_id = ctx.ext_mut().message_id()?; + pub fn message_id(message_id_ptr: u32) -> impl SysCall { + (RuntimeCosts::MsgId, move |ctx: &mut CallerWrap| { + let message_id = ctx.ext_mut().message_id()?; - let write_message_id = ctx.manager.register_write_as(message_id_ptr); - ctx.write_as(write_message_id, message_id.into_bytes()) - .map_err(Into::into) + let write_message_id = ctx.manager.register_write_as(message_id_ptr); + ctx.write_as(write_message_id, message_id.into_bytes()) + .map_err(Into::into) + }) } - #[host(cost = RuntimeCosts::ProgramId)] - pub fn program_id( - ctx: &mut CallerWrap<'_, '_, Ext>, - program_id_ptr: u32, - ) -> Result<(), HostError> { - let program_id = ctx.ext_mut().program_id()?; + pub fn program_id(program_id_ptr: u32) -> impl SysCall { + (RuntimeCosts::ProgramId, move |ctx: &mut CallerWrap| { + let program_id = ctx.ext_mut().program_id()?; - let write_program_id = ctx.manager.register_write_as(program_id_ptr); - ctx.write_as(write_program_id, program_id.into_bytes()) - .map_err(Into::into) + let write_program_id = ctx.manager.register_write_as(program_id_ptr); + ctx.write_as(write_program_id, program_id.into_bytes()) + .map_err(Into::into) + }) } - #[host(fallible, cost = RuntimeCosts::PayProgramRent, err = ErrorWithBlockNumberAndValue)] - pub fn pay_program_rent( - ctx: &mut CallerWrap<'_, '_, Ext>, - rent_pid_ptr: u32, - ) -> Result<(), HostError> { - let read_rent_pid = ctx.manager.register_read_as(rent_pid_ptr); + pub fn pay_program_rent(rent_pid_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::PayProgramRent, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_rent_pid = ctx.manager.register_read_as(rent_pid_ptr); - let HashWithValue { - hash: program_id, - value: rent, - } = ctx.read_as(read_rent_pid)?; + let HashWithValue { + hash: program_id, + value: rent, + } = ctx.read_as(read_rent_pid)?; - ctx.ext_mut() - .pay_program_rent(program_id.into(), rent) - .map_err(Into::into) + ctx.ext_mut() + .pay_program_rent(program_id.into(), rent) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::Source)] - pub fn source(ctx: &mut CallerWrap<'_, '_, Ext>, source_ptr: u32) -> Result<(), HostError> { - let source = ctx.ext_mut().source()?; + pub fn source(source_ptr: u32) -> impl SysCall { + (RuntimeCosts::Source, move |ctx: &mut CallerWrap| { + let source = ctx.ext_mut().source()?; - let write_source = ctx.manager.register_write_as(source_ptr); - ctx.write_as(write_source, source.into_bytes()) - .map_err(Into::into) + let write_source = ctx.manager.register_write_as(source_ptr); + ctx.write_as(write_source, source.into_bytes()) + .map_err(Into::into) + }) } - #[host(cost = RuntimeCosts::Value)] - pub fn value(ctx: &mut CallerWrap<'_, '_, Ext>, value_ptr: u32) -> Result<(), HostError> { - let value = ctx.ext_mut().value()?; + pub fn value(value_ptr: u32) -> impl SysCall { + (RuntimeCosts::Value, move |ctx: &mut CallerWrap| { + let value = ctx.ext_mut().value()?; - let write_value = ctx.manager.register_write_as(value_ptr); - ctx.write_as(write_value, value.to_le_bytes()) - .map_err(Into::into) + let write_value = ctx.manager.register_write_as(value_ptr); + ctx.write_as(write_value, value.to_le_bytes()) + .map_err(Into::into) + }) } - #[host(cost = RuntimeCosts::ValueAvailable)] - pub fn value_available( - ctx: &mut CallerWrap<'_, '_, Ext>, - value_ptr: u32, - ) -> Result<(), HostError> { - let value_available = ctx.ext_mut().value_available()?; + pub fn value_available(value_ptr: u32) -> impl SysCall { + ( + RuntimeCosts::ValueAvailable, + move |ctx: &mut CallerWrap| { + let value_available = ctx.ext_mut().value_available()?; - let write_value = ctx.manager.register_write_as(value_ptr); - ctx.write_as(write_value, value_available.to_le_bytes()) - .map_err(Into::into) + let write_value = ctx.manager.register_write_as(value_ptr); + ctx.write_as(write_value, value_available.to_le_bytes()) + .map_err(Into::into) + }, + ) } - #[host(cost = RuntimeCosts::Leave)] - pub fn leave(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - Err(ActorTerminationReason::Leave.into()) + pub fn leave() -> impl SysCall { + (RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| { + Err(ActorTerminationReason::Leave.into()) + }) } - #[host(cost = RuntimeCosts::Wait)] - pub fn wait(ctx: &mut CallerWrap<'_, '_, Ext>) -> Result<(), HostError> { - ctx.ext_mut().wait()?; - Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) + pub fn wait() -> impl SysCall { + (RuntimeCosts::Wait, move |ctx: &mut CallerWrap| { + ctx.ext_mut().wait()?; + Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) + }) } - #[host(cost = RuntimeCosts::WaitFor)] - pub fn wait_for(ctx: &mut CallerWrap<'_, '_, Ext>, duration: u32) -> Result<(), HostError> { - ctx.ext_mut().wait_for(duration)?; - Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) + pub fn wait_for(duration: u32) -> impl SysCall { + (RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap| { + 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 CallerWrap<'_, '_, Ext>, duration: u32) -> Result<(), HostError> { - let waited_type = if ctx.ext_mut().wait_up_to(duration)? { - MessageWaitedType::WaitUpToFull - } else { - MessageWaitedType::WaitUpTo - }; - Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) + pub fn wait_up_to(duration: u32) -> impl SysCall { + (RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap| { + let waited_type = if ctx.ext_mut().wait_up_to(duration)? { + MessageWaitedType::WaitUpToFull + } else { + MessageWaitedType::WaitUpTo + }; + Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) + }) } - #[host(fallible, cost = RuntimeCosts::Wake, err = ErrorBytes)] - pub fn wake( - ctx: &mut CallerWrap<'_, '_, Ext>, - message_id_ptr: u32, - delay: u32, - ) -> Result<(), HostError> { - let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); - let message_id = ctx.read_decoded(read_message_id)?; + pub fn wake(message_id_ptr: u32, delay: u32) -> impl SysCall { + ( + RuntimeCosts::Wake, + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); + let message_id = ctx.read_decoded(read_message_id)?; - ctx.ext_mut().wake(message_id, delay).map_err(Into::into) + ctx.ext_mut().wake(message_id, delay).map_err(Into::into) + }, + ) } #[allow(clippy::too_many_arguments)] - #[host(fallible, wgas, cost = RuntimeCosts::CreateProgram(payload_len, salt_len), err = ErrorWithTwoHashes)] - pub fn create_program( - ctx: &mut CallerWrap<'_, '_, Ext>, + fn create_program_inner( + ctx: &mut CallerWrap, cid_value_ptr: u32, salt_ptr: u32, salt_len: u32, payload_ptr: u32, payload_len: u32, + gas_limit: Option, delay: u32, - ) -> Result<(), HostError> { + ) -> Result<(MessageId, ProgramId), RunFallibleError> { let read_cid_value = ctx.manager.register_read_as(cid_value_ptr); let read_salt = ctx.manager.register_read(salt_ptr, salt_len); let read_payload = ctx.manager.register_read(payload_ptr, payload_len); @@ -1006,41 +1198,99 @@ where let message_id = ctx.ext_mut().message_id()?; - ctx.ext_mut() - .create_program( - InitPacket::new(code_id.into(), salt, payload, Some(message_id), value), - delay, + let packet = if let Some(gas_limit) = gas_limit { + InitPacket::new_with_gas( + code_id.into(), + salt, + payload, + Some(message_id), + gas_limit, + value, ) + } else { + InitPacket::new(code_id.into(), salt, payload, Some(message_id), value) + }; + + ctx.ext_mut() + .create_program(packet, delay) .map_err(Into::into) } - pub fn forbidden(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> { - syscall_trace!("forbidden"); + pub fn create_program( + cid_value_ptr: u32, + salt_ptr: u32, + salt_len: u32, + payload_ptr: u32, + payload_len: u32, + delay: u32, + ) -> impl SysCall { + ( + RuntimeCosts::CreateProgram(payload_len, salt_len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| -> Result<_, RunFallibleError> { + Self::create_program_inner( + ctx, + cid_value_ptr, + salt_ptr, + salt_len, + payload_ptr, + payload_len, + None, + delay, + ) + }, + ) + } + + pub fn create_program_wgas( + cid_value_ptr: u32, + salt_ptr: u32, + salt_len: u32, + payload_ptr: u32, + payload_len: u32, + gas_limit: u64, + delay: u32, + ) -> impl SysCall { + ( + RuntimeCosts::CreateProgramWGas(payload_len, salt_len), + FallibleSysCallError::::default(), + move |ctx: &mut CallerWrap| { + Self::create_program_inner( + ctx, + cid_value_ptr, + salt_ptr, + salt_len, + payload_ptr, + payload_len, + Some(gas_limit), + delay, + ) + }, + ) + } - ctx.run_any(gas, RuntimeCosts::Null, |_| { + pub fn forbidden(_args: &[Value]) -> impl SysCall { + (RuntimeCosts::Null, |_: &mut CallerWrap| { Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) }) } - pub fn out_of_gas( - ctx: &mut CallerWrap<'_, '_, Ext>, - _gas: u64, - ) -> Result<(u64, ()), HostError> { - syscall_trace!("out_of_gas"); - - let ext = ctx.ext_mut(); - let current_counter = ext.current_counter_type(); - log::trace!(target: "syscalls", "[out_of_gas] Current counter in global represents {current_counter:?}"); + pub fn out_of_gas() -> impl SysCall { + |ctx: &mut CallerWrap| { + let ext = ctx.ext_mut(); + let current_counter = ext.current_counter_type(); + log::trace!(target: "syscalls", "[out_of_gas] Current counter in global represents {current_counter:?}"); - if current_counter == CounterType::GasAllowance { - // We manually decrease it to 0 because global won't be affected - // since it didn't pass comparison to argument of `gas_charge()` - ext.decrease_current_counter_to(0); - } + if current_counter == CounterType::GasAllowance { + // We manually decrease it to 0 because global won't be affected + // since it didn't pass comparison to argument of `gas_charge()` + ext.decrease_current_counter_to(0); + } - let termination_reason: ActorTerminationReason = current_counter.into(); + let termination_reason: ActorTerminationReason = current_counter.into(); - ctx.set_termination_reason(termination_reason.into()); - Err(HostError) + ctx.set_termination_reason(termination_reason.into()); + Err(HostError) + } } } From fec314454360bec8e3f9580b01d3c18d756a0778 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sat, 23 Sep 2023 01:27:40 +0300 Subject: [PATCH 11/37] Introduce `maybe_with_gas` constructor for packets --- core-backend/src/funcs.rs | 112 ++++++++++++++++++------------------- core/src/message/handle.rs | 13 +++++ core/src/message/init.rs | 17 ++++++ core/src/message/reply.rs | 8 +++ 4 files changed, 94 insertions(+), 56 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index b39b8149b8c..9cb0e5825ec 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -350,13 +350,12 @@ where } = ctx.read_as(read_hash_val)?; let payload = Self::read_message_payload(ctx, read_payload)?; - let packet = if let Some(gas_limit) = gas_limit { - HandlePacket::new_with_gas(destination.into(), payload, gas_limit, value) - } else { - HandlePacket::new(destination.into(), payload, value) - }; - - ctx.ext_mut().send(packet, delay).map_err(Into::into) + ctx.ext_mut() + .send( + HandlePacket::maybe_with_gas(destination.into(), payload, gas_limit, value), + delay, + ) + .map_err(Into::into) } pub fn send(pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32) -> impl SysCall { @@ -398,14 +397,17 @@ where value, } = ctx.read_as(read_pid_value)?; - let packet = if let Some(gas_limit) = gas_limit { - HandlePacket::new_with_gas(destination.into(), Default::default(), gas_limit, value) - } else { - HandlePacket::new(destination.into(), Default::default(), value) - }; - ctx.ext_mut() - .send_commit(handle, packet, delay) + .send_commit( + handle, + HandlePacket::maybe_with_gas( + destination.into(), + Default::default(), + gas_limit, + value, + ), + delay, + ) .map_err(Into::into) } @@ -566,6 +568,7 @@ where ) } + // TODO: write proper benchmark #2825 pub fn signal_code() -> impl SysCall { ( RuntimeCosts::SignalCode, @@ -689,13 +692,9 @@ where let value = Self::register_and_read_value(ctx, value_ptr)?; let payload = Self::read_message_payload(ctx, read_payload)?; - let packet = if let Some(gas_limit) = gas_limit { - ReplyPacket::new_with_gas(payload, gas_limit, value) - } else { - ReplyPacket::new(payload, value) - }; - - ctx.ext_mut().reply(packet).map_err(Into::into) + ctx.ext_mut() + .reply(ReplyPacket::maybe_with_gas(payload, gas_limit, value)) + .map_err(Into::into) } pub fn reply(payload_ptr: u32, len: u32, value_ptr: u32) -> impl SysCall { @@ -730,13 +729,13 @@ where ) -> Result { let value = Self::register_and_read_value(ctx, value_ptr)?; - let packet = if let Some(gas_limit) = gas_limit { - ReplyPacket::new_with_gas(Default::default(), gas_limit, value) - } else { - ReplyPacket::new(Default::default(), value) - }; - - ctx.ext_mut().reply_commit(packet).map_err(Into::into) + ctx.ext_mut() + .reply_commit(ReplyPacket::maybe_with_gas( + Default::default(), + gas_limit, + value, + )) + .map_err(Into::into) } pub fn reply_commit(value_ptr: u32) -> impl SysCall { @@ -806,6 +805,7 @@ where ) } + // TODO: write proper benchmark #2825 pub fn signal_from() -> impl SysCall { ( RuntimeCosts::SignalFrom, @@ -839,13 +839,13 @@ where // Charge for `len` is inside `reply_push_input` ctx.ext_mut().reply_push_input(offset, len)?; - let packet = if let Some(gas_limit) = gas_limit { - ReplyPacket::new_with_gas(Default::default(), gas_limit, value) - } else { - ReplyPacket::new(Default::default(), value) - }; - - ctx.ext_mut().reply_commit(packet).map_err(Into::into) + ctx.ext_mut() + .reply_commit(ReplyPacket::maybe_with_gas( + Default::default(), + gas_limit, + value, + )) + .map_err(Into::into) } pub fn reply_input(offset: u32, len: u32, value_ptr: u32) -> impl SysCall { @@ -903,14 +903,17 @@ where // Charge for `len` inside `send_push_input` ctx.ext_mut().send_push_input(handle, offset, len)?; - let packet = if let Some(gas_limit) = gas_limit { - HandlePacket::new_with_gas(destination.into(), Default::default(), gas_limit, value) - } else { - HandlePacket::new(destination.into(), Default::default(), value) - }; - ctx.ext_mut() - .send_commit(handle, packet, delay) + .send_commit( + handle, + HandlePacket::maybe_with_gas( + destination.into(), + Default::default(), + gas_limit, + value, + ), + delay, + ) .map_err(Into::into) } @@ -1198,21 +1201,18 @@ where let message_id = ctx.ext_mut().message_id()?; - let packet = if let Some(gas_limit) = gas_limit { - InitPacket::new_with_gas( - code_id.into(), - salt, - payload, - Some(message_id), - gas_limit, - value, - ) - } else { - InitPacket::new(code_id.into(), salt, payload, Some(message_id), value) - }; - ctx.ext_mut() - .create_program(packet, delay) + .create_program( + InitPacket::maybe_with_gas( + code_id.into(), + salt, + payload, + Some(message_id), + gas_limit, + value, + ), + delay, + ) .map_err(Into::into) } diff --git a/core/src/message/handle.rs b/core/src/message/handle.rs index 5070f11ed82..92b88985469 100644 --- a/core/src/message/handle.rs +++ b/core/src/message/handle.rs @@ -153,6 +153,19 @@ impl HandlePacket { } } + /// Create new packet with optional gas. + pub fn maybe_with_gas( + destination: ProgramId, + payload: Payload, + gas_limit: Option, + value: Value, + ) -> Self { + match gas_limit { + None => Self::new(destination, payload, value), + Some(gas_limit) => Self::new_with_gas(destination, payload, gas_limit, value), + } + } + /// Prepend payload. pub(super) fn try_prepend(&mut self, data: Payload) -> Result<(), PayloadSizeError> { self.payload.try_prepend(data) diff --git a/core/src/message/init.rs b/core/src/message/init.rs index 9aec00466e7..09ba29eb19b 100644 --- a/core/src/message/init.rs +++ b/core/src/message/init.rs @@ -178,6 +178,23 @@ impl InitPacket { } } + /// Create new InitPacket with optional gas. + pub fn maybe_with_gas( + code_id: CodeId, + salt: Salt, + payload: Payload, + message_id: Option, + gas_limit: Option, + value: Value, + ) -> Self { + match gas_limit { + None => Self::new(code_id, salt, payload, message_id, value), + Some(gas_limit) => { + Self::new_with_gas(code_id, salt, payload, message_id, gas_limit, value) + } + } + } + /// Packet destination (newly created program id). pub fn destination(&self) -> ProgramId { self.program_id diff --git a/core/src/message/reply.rs b/core/src/message/reply.rs index bcfb04cd1b3..9b647fa0568 100644 --- a/core/src/message/reply.rs +++ b/core/src/message/reply.rs @@ -193,6 +193,14 @@ impl ReplyPacket { } } + /// Create new manual ReplyPacket with optional gas. + pub fn maybe_with_gas(payload: Payload, gas_limit: Option, value: Value) -> Self { + match gas_limit { + None => Self::new(payload, value), + Some(gas_limit) => Self::new_with_gas(payload, gas_limit, value), + } + } + // TODO: consider using here `impl CoreError` and/or provide `AsStatusCode` // trait or append such functionality to `CoreError` (issue #1083). /// Create new system generated ReplyPacket. From 2bab8381526d0a31c307674d4660313926ae9a3b Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sat, 23 Sep 2023 01:32:49 +0300 Subject: [PATCH 12/37] Remove `host` backend macro --- Cargo.lock | 10 -- Cargo.toml | 2 - core-backend/Cargo.toml | 1 - core-backend/codegen/Cargo.toml | 19 --- core-backend/codegen/src/host.rs | 281 ------------------------------- core-backend/codegen/src/lib.rs | 91 ---------- 6 files changed, 404 deletions(-) delete mode 100644 core-backend/codegen/Cargo.toml delete mode 100644 core-backend/codegen/src/host.rs delete mode 100644 core-backend/codegen/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 2a1e220ef61..94828b0fab0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3928,7 +3928,6 @@ dependencies = [ "blake2-rfc", "derive_more", "gear-core", - "gear-core-backend-codegen", "gear-core-errors", "gear-lazy-pages-common", "gear-sandbox", @@ -3939,15 +3938,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "gear-core-backend-codegen" -version = "1.0.1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.31", -] - [[package]] name = "gear-core-errors" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index cac8fee647f..9e4bb868a2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ members = [ "common/codegen", "core", "core-backend", - "core-backend/codegen", "core-processor", "core-errors", "examples/async", @@ -196,7 +195,6 @@ gsys = { path = "gsys" } gtest = { path = "gtest" } gmeta = { path = "gmeta" } gear-authorship = { path = "node/authorship" } -gear-core-backend-codegen = { path = "core-backend/codegen" } gear-core-backend = { path = "core-backend", default-features = false } gear-call-gen = { path = "utils/call-gen" } gear-common = { path = "common", default-features = false } diff --git a/core-backend/Cargo.toml b/core-backend/Cargo.toml index 0a1de42cad0..7343023cbb6 100644 --- a/core-backend/Cargo.toml +++ b/core-backend/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true [dependencies] gear-core.workspace = true gear-core-errors = { workspace = true, features = ["codec"] } -gear-core-backend-codegen.workspace = true gear-lazy-pages-common.workspace = true gsys = { workspace = true } diff --git a/core-backend/codegen/Cargo.toml b/core-backend/codegen/Cargo.toml deleted file mode 100644 index 8f7bb632556..00000000000 --- a/core-backend/codegen/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "gear-core-backend-codegen" -description = "Code generation library for gear-core-backend" -keywords = ["gear", "wasm", "codegen"] -categories = ["wasm"] -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[lib] -proc-macro = true - -[dependencies] -syn = { workspace = true, features = ["full", "fold"] } -quote.workspace = true -proc-macro2.workspace = true diff --git a/core-backend/codegen/src/host.rs b/core-backend/codegen/src/host.rs deleted file mode 100644 index 1b9ebeb774f..00000000000 --- a/core-backend/codegen/src/host.rs +++ /dev/null @@ -1,281 +0,0 @@ -// This file is part of Gear. -// -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use quote::{quote, ToTokens}; -use syn::{ - fold::Fold, parse::Parse, parse_quote, punctuated::Punctuated, Block, Expr, ExprCall, ExprPath, - FnArg, GenericArgument, ItemFn, Meta, Pat, PatType, Path, PathArguments, ReturnType, Signature, - Token, Type, -}; - -/// Host function builder. -pub struct HostFn { - item: ItemFn, - meta: HostFnMeta, -} - -impl HostFn { - /// Create a new host function builder. - pub fn new(meta: HostFnMeta, item: ItemFn) -> Self { - Self { item, meta } - } - - /// Build the host function. - pub fn build(mut self) -> TokenStream { - let maybe_wgas = self.meta.fold_item_fn(ItemFn { - attrs: self.item.attrs.clone(), - vis: self.item.vis.clone(), - sig: self.build_sig(), - block: self.build_block(), - }); - - if !self.meta.wgas { - return maybe_wgas.into_token_stream().into(); - } - - self.meta.wgas = false; - let without_gas = ItemFn { - attrs: self.item.attrs.clone(), - vis: self.item.vis.clone(), - sig: self.build_sig(), - block: self.build_block(), - }; - - quote! { - #without_gas - - #maybe_wgas - } - .into() - } - - /// Build inputs from the function signature. - fn build_inputs(&self) -> Vec { - let mut inputs = self.item.sig.inputs.iter().cloned().collect::>(); - - inputs.insert(1, parse_quote!(gas: u64)); - - if matches!(self.meta.call_type, CallType::Fallible) { - inputs.push(parse_quote!(err_mid_ptr: u32)); - } - - if !self.meta.wgas { - return inputs; - } - - let mut injected = false; - let mut new_inputs = vec![]; - inputs.into_iter().for_each(|a| { - if let FnArg::Typed(PatType { pat, .. }) = a.clone() { - if let Pat::Ident(ident) = pat.as_ref() { - // TODO #2722 - if !injected && (ident.ident == "value_ptr" || ident.ident == "delay") { - new_inputs.push(parse_quote!(gas_limit: u64)); - injected = true; - } - } - } - - new_inputs.push(a); - }); - - new_inputs - } - - /// Build the signature of the function. - fn build_sig(&self) -> Signature { - let name = self.item.sig.ident.clone(); - let inputs = self.build_inputs(); - - let mut output = self.item.sig.output.clone(); - if let ReturnType::Type(_rarrow, ty) = &mut output { - if let Type::Path(type_path) = ty.as_mut() { - let segment = type_path.path.segments.first_mut().unwrap(); - if let PathArguments::AngleBracketed(generic_args) = &mut segment.arguments { - let generic_arg = generic_args.args.first_mut().unwrap(); - if let GenericArgument::Type(ty) = generic_arg { - *ty = parse_quote! { (u64, #ty) }; - } - } - } - } - let output = output.clone().into_token_stream(); - - parse_quote! { - fn #name(#(#inputs),*) #output - } - } - - /// Build the function body. - fn build_block(&self) -> Box { - let mut name = self.item.sig.ident.clone().to_string(); - if self.meta.wgas { - name += "_wgas"; - } - - let cost = self.meta.runtime_costs.clone(); - let err = self.meta.err.clone(); - let inner_block = self.item.block.clone(); - let inputs = self.build_inputs(); - - let run: Expr = match self.meta.call_type { - CallType::Any => { - parse_quote! { - ctx.run_any(gas, #cost, |ctx| { - #inner_block - }) - } - } - CallType::Fallible => { - parse_quote! { - ctx.run_fallible::<_, _, #err>(gas, err_mid_ptr, #cost, |ctx| { - #inner_block - }) - } - } - }; - - let mut log_args: Vec = vec![parse_quote!(#name)]; - log_args.extend( - inputs - .into_iter() - .skip(1) - .filter_map(|a| match a { - FnArg::Typed(PatType { pat, .. }) => match pat.as_ref() { - Pat::Ident(ident) => Some(Expr::Path(ExprPath { - attrs: Default::default(), - qself: None, - path: Path::from(ident.clone().ident), - })), - _ => None, - }, - _ => None, - }) - .collect::>(), - ); - - parse_quote! ({ - syscall_trace!(#(#log_args),*); - - #run - }) - } -} - -impl From for TokenStream { - fn from(host_fn: HostFn) -> Self { - host_fn.build() - } -} - -/// Call type of the host function. -#[derive(Default)] -pub enum CallType { - #[default] - Any, - Fallible, -} - -/// Attribute meta of the host function. -pub struct HostFnMeta { - /// Call type of the host function. - pub call_type: CallType, - /// If the host function is wgas. - pub wgas: bool, - /// The runtime costs of the host function. - runtime_costs: Expr, - /// The length of the error. - pub err: Expr, -} - -impl Parse for HostFnMeta { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut call_type = Default::default(); - let mut wgas = false; - let mut runtime_costs = parse_quote!(RuntimeCosts::Null); - let mut err = parse_quote!(ErrorWithHash); - - let meta_list = Punctuated::::parse_terminated(input)?; - for meta in meta_list { - let ident = meta.path().get_ident().expect("Missing ident"); - match ident.to_string().as_ref() { - "fallible" => call_type = CallType::Fallible, - "wgas" => wgas = true, - "cost" => runtime_costs = meta.require_name_value()?.value.clone(), - "err" => err = meta.require_name_value()?.value.clone(), - _ => {} - } - } - - Ok(Self { - call_type, - wgas, - runtime_costs, - err, - }) - } -} - -impl Fold for HostFnMeta { - fn fold_item_fn(&mut self, mut item: ItemFn) -> ItemFn { - if !self.wgas { - return item; - } - - item.sig.ident = Ident::new( - &(item.sig.ident.to_token_stream().to_string() + "_wgas"), - Span::call_site(), - ); - - item.block = Box::new(self.fold_block(*item.block)); - item - } - - fn fold_expr_call(&mut self, mut expr: ExprCall) -> ExprCall { - if !self.wgas { - return expr; - } - - if let Expr::Path(ExprPath { - path: Path { segments, .. }, - .. - }) = &mut *expr.func - { - if segments - .first() - .map(|i| i.to_token_stream().to_string().ends_with("Packet")) - != Some(true) - { - return expr; - } - - if let Some(new) = segments.last_mut() { - new.ident = Ident::new("new_with_gas", Span::call_site()); - } - } - - if let Some(value) = expr.args.pop() { - expr.args.push(parse_quote!(gas_limit)); - expr.args.push(value.value().clone()); - } - - expr - } -} diff --git a/core-backend/codegen/src/lib.rs b/core-backend/codegen/src/lib.rs deleted file mode 100644 index 427ff085416..00000000000 --- a/core-backend/codegen/src/lib.rs +++ /dev/null @@ -1,91 +0,0 @@ -// This file is part of Gear. -// -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use host::{HostFn, HostFnMeta}; -use proc_macro::TokenStream; -use syn::ItemFn; - -mod host; - -/// Apply host state wrapper to host functions. -/// -/// Supported meta attributes: -/// * `fallible` - if the host function executes fallible call. -/// * `wgas` - if the host function supports with-gas version. -/// * `cost` - RuntimeCosts definition, for example `#[host(cost = RuntimeCosts::Null)]` -/// * `err` - Structure definition with error code, for example `#[host(err = ErrorWithHash)]` -/// -/// # Example -/// -/// ```ignore -/// #[host(fallible, wgas, cost = RuntimeCosts::Reply(len))] -/// pub fn reply( -/// ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// value_ptr: u32, -/// delay: u32, -/// ) -> Result<(), R::Error> { -/// let read_payload = ctx.register_read(payload_ptr, len); -/// let value = ctx.register_and_read_value(value_ptr)?; -/// let payload = ctx.read(read_payload)?.try_into()?; -/// -/// let state = ctx.host_state_mut(); -/// state.ext.reply(ReplyPacket::new(payload, value), delay) -/// .map_err(Into::into) -/// } -/// ``` -/// -/// will generate -/// -/// ```ignore -/// pub fn reply(ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// value_ptr: u32, -/// delay: u32 -/// ) -> Result<(), R::Error> { -/// syscall_trace!("reply", payload_ptr, len, value_ptr, delay, err_mid_ptr); -/// -/// ctx.run_fallible::<_, _, ErrorWithHash>(err_mid_ptr, RuntimeCosts::Reply(len), |ctx| { -/// // ... -/// }) -/// } -/// -/// pub fn reply_wgas( -/// ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// gas_limit: u64, -/// value_ptr: u32, -/// delay: u32 -/// ) -> Result<(), R::Error> { -/// syscall_trace!("reply_wgas", payload_ptr, len, gas_limit, value_ptr, delay, err_mid_ptr); -/// -/// ctx.run_fallible::<_, _, ErrorWithHash>(err_mid_ptr, RuntimeCosts::ReplyWGas(len), |ctx| { -/// // ... -/// }) -/// } -/// ``` -#[proc_macro_attribute] -pub fn host(meta: TokenStream, item: TokenStream) -> TokenStream { - let meta: HostFnMeta = syn::parse_macro_input!(meta); - let item: ItemFn = syn::parse_macro_input!(item); - - HostFn::new(meta, item).into() -} From cd528fa33a6da49a14e1d0356e2e77228a7bbb7c Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sat, 23 Sep 2023 01:37:30 +0300 Subject: [PATCH 13/37] Remove obsolete comment --- core-backend/src/funcs.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 9cb0e5825ec..d013483a997 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -672,15 +672,6 @@ where }) } - /* - gas: u64, - payload_ptr: u32, - len: u32, - gas_limit: u64, - value_ptr: u32, - err_mid_ptr: u32 - */ - fn reply_inner( ctx: &mut CallerWrap, payload_ptr: u32, From 8a12d4e990726e939144f6f43344946fc50f6a54 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sat, 23 Sep 2023 01:40:08 +0300 Subject: [PATCH 14/37] Fix gasfull costs are forgotten --- core-backend/src/funcs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index d013483a997..a0922d2bf1e 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -376,7 +376,7 @@ where delay: u32, ) -> impl SysCall { ( - RuntimeCosts::Send(len), + RuntimeCosts::SendWGas(len), FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, Some(gas_limit), delay) @@ -428,7 +428,7 @@ where delay: u32, ) -> impl SysCall { ( - RuntimeCosts::SendCommit, + RuntimeCosts::SendCommitWGas, FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_commit_inner(ctx, handle, pid_value_ptr, Some(gas_limit), delay) @@ -705,7 +705,7 @@ where value_ptr: u32, ) -> impl SysCall { ( - RuntimeCosts::Reply(len), + RuntimeCosts::ReplyWGas(len), FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_inner(ctx, payload_ptr, len, Some(gas_limit), value_ptr) @@ -739,7 +739,7 @@ where pub fn reply_commit_wgas(gas_limit: u64, value_ptr: u32) -> impl SysCall { ( - RuntimeCosts::ReplyCommit, + RuntimeCosts::ReplyCommitWGas, FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_commit_inner(ctx, Some(gas_limit), value_ptr) @@ -856,7 +856,7 @@ where value_ptr: u32, ) -> impl SysCall { ( - RuntimeCosts::ReplyInput, + RuntimeCosts::ReplyInputWGas, FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_input_inner(ctx, offset, len, Some(gas_limit), value_ptr) @@ -926,7 +926,7 @@ where delay: u32, ) -> impl SysCall { ( - RuntimeCosts::SendInput, + RuntimeCosts::SendInputWGas, FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_input_inner(ctx, pid_value_ptr, offset, len, Some(gas_limit), delay) From def32c040c5ac35e8131f77798766d3c749dfbb9 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sun, 24 Sep 2023 18:59:35 +0300 Subject: [PATCH 15/37] `SysCallFabric` -> `SysCallBuilder` --- core-backend/src/funcs.rs | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index a0922d2bf1e..4d1ce8c4102 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -128,43 +128,43 @@ pub trait SysCall { ) -> Result<(u64, T), HostError>; } -pub trait SysCallFabric { - fn create(self, args: &[Value]) -> Result; +pub trait SysCallBuilder { + fn build(self, args: &[Value]) -> Result; } -impl SysCallFabric for H +impl SysCallBuilder for H where H: Fn() -> S, S: SysCall, { - fn create(self, args: &[Value]) -> Result { + fn build(self, args: &[Value]) -> Result { let _: [Value; 0] = args.try_into().map_err(|_| HostError)?; Ok((self)()) } } -impl SysCallFabric for H +impl SysCallBuilder for H where H: for<'a> Fn(&'a [Value]) -> S, S: SysCall, { - fn create(self, args: &[Value]) -> Result { + fn build(self, args: &[Value]) -> Result { Ok((self)(args)) } } -macro_rules! impl_syscall_fabric { +macro_rules! impl_syscall_builder { ($($generic:ident),+) => { #[allow(non_snake_case)] - impl SysCallFabric + impl SysCallBuilder for Handler where Handler: Fn($($generic),+) -> Call, Call: SysCall, $( $generic: TryFrom,)+ { - fn create(self, args: &[Value]) -> Result { - const ARGS_AMOUNT: usize = impl_syscall_fabric!(@count $($generic),+); + fn build(self, args: &[Value]) -> Result { + const ARGS_AMOUNT: usize = impl_syscall_builder!(@count $($generic),+); let [$($generic),+]: [Value; ARGS_AMOUNT] = args.try_into().map_err(|_| HostError)?; $( @@ -175,16 +175,16 @@ macro_rules! impl_syscall_fabric { } }; (@count $generic:ident) => { 1 }; - (@count $generic:ident, $($generics:ident),+) => { 1 + impl_syscall_fabric!(@count $($generics),+) }; + (@count $generic:ident, $($generics:ident),+) => { 1 + impl_syscall_builder!(@count $($generics),+) }; } -impl_syscall_fabric!(A); -impl_syscall_fabric!(A, B); -impl_syscall_fabric!(A, B, C); -impl_syscall_fabric!(A, B, C, D); -impl_syscall_fabric!(A, B, C, D, E); -impl_syscall_fabric!(A, B, C, D, E, F); -impl_syscall_fabric!(A, B, C, D, E, F, G); +impl_syscall_builder!(A); +impl_syscall_builder!(A, B); +impl_syscall_builder!(A, B, C); +impl_syscall_builder!(A, B, C, D); +impl_syscall_builder!(A, B, C, D, E); +impl_syscall_builder!(A, B, C, D, E, F); +impl_syscall_builder!(A, B, C, D, E, F, G); type SimpleSysCall = F; @@ -294,13 +294,13 @@ where handler: H, ) -> Result where - H: SysCallFabric, + H: SysCallBuilder, Args: ?Sized, S: SysCall, R: Into, { let (ctx, args) = S::Context::from_args(args)?; - let sys_call = SysCallFabric::create(handler, args)?; + let sys_call = SysCallBuilder::build(handler, args)?; let (gas, value) = sys_call.execute(caller, ctx)?; let value = value.into(); From 30b96970a3d64d8d62a01f9e25dfcd176353b303 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sun, 24 Sep 2023 19:03:57 +0300 Subject: [PATCH 16/37] Lower trait bound requirements --- core-backend/src/funcs.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 4d1ce8c4102..bd9ebe121ad 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -122,7 +122,7 @@ pub trait SysCall { type Context: SysCallContext; fn execute( - &self, + self, caller: &mut CallerWrap, ctx: Self::Context, ) -> Result<(u64, T), HostError>; @@ -134,7 +134,7 @@ pub trait SysCallBuilder { impl SysCallBuilder for H where - H: Fn() -> S, + H: FnOnce() -> S, S: SysCall, { fn build(self, args: &[Value]) -> Result { @@ -145,7 +145,7 @@ where impl SysCallBuilder for H where - H: for<'a> Fn(&'a [Value]) -> S, + H: for<'a> FnOnce(&'a [Value]) -> S, S: SysCall, { fn build(self, args: &[Value]) -> Result { @@ -159,7 +159,7 @@ macro_rules! impl_syscall_builder { impl SysCallBuilder for Handler where - Handler: Fn($($generic),+) -> Call, + Handler: FnOnce($($generic),+) -> Call, Call: SysCall, $( $generic: TryFrom,)+ { @@ -190,13 +190,13 @@ type SimpleSysCall = F; impl SysCall for SimpleSysCall where - F: Fn(&mut CallerWrap) -> Result, + F: FnOnce(&mut CallerWrap) -> Result, Ext: BackendExternalities + 'static, { type Context = InfallibleSysCallContext; fn execute( - &self, + self, caller: &mut CallerWrap, ctx: Self::Context, ) -> Result<(u64, T), HostError> { @@ -228,20 +228,20 @@ type FallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); impl SysCall for FallibleSysCall where - F: Fn(&mut CallerWrap) -> Result, + F: FnOnce(&mut CallerWrap) -> Result, E: From>, Ext: BackendExternalities + 'static, { type Context = FallibleSysCallContext; fn execute( - &self, + self, caller: &mut CallerWrap, context: Self::Context, ) -> Result<(u64, ()), HostError> { let (costs, _error, func) = self; let FallibleSysCallContext { gas, res_ptr } = context; - caller.run_fallible::(gas, res_ptr, *costs, |ctx| (func)(ctx)) + caller.run_fallible::(gas, res_ptr, costs, func) } } @@ -267,13 +267,13 @@ where type Context = InfallibleSysCallContext; fn execute( - &self, + self, caller: &mut CallerWrap, ctx: Self::Context, ) -> Result<(u64, T), HostError> { let (costs, func) = self; let InfallibleSysCallContext { gas } = ctx; - caller.run_any::(gas, *costs, |ctx| (func)(ctx)) + caller.run_any::(gas, costs, func) } } From 722d0cf9c0ca895e9c647191aaa81c99b77e1eed Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sun, 24 Sep 2023 19:06:41 +0300 Subject: [PATCH 17/37] Move and rename `SandboxValue` into funcs.rs --- core-backend/src/env.rs | 47 +------------------------------- core-backend/src/funcs.rs | 56 +++++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index c2761e6d61c..13d1bad2deb 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -51,7 +51,7 @@ use gear_sandbox::{ default_executor::{ EnvironmentDefinitionBuilder, Instance, Memory as DefaultExecutorMemory, Store, }, - AsContextExt, HostError, HostFuncType, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, + AsContextExt, HostFuncType, ReturnValue, SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory, SandboxStore, Value, }; use gear_wasm_instrument::{ @@ -59,51 +59,6 @@ use gear_wasm_instrument::{ GLOBAL_NAME_GAS, STACK_END_EXPORT_NAME, }; -#[derive(Clone, Copy)] -pub struct SandboxValue(pub Value); - -impl From for SandboxValue { - fn from(value: i32) -> Self { - SandboxValue(Value::I32(value)) - } -} - -impl From for SandboxValue { - fn from(value: u32) -> Self { - SandboxValue(Value::I32(value as i32)) - } -} - -impl From for SandboxValue { - fn from(value: i64) -> Self { - SandboxValue(Value::I64(value)) - } -} - -impl TryFrom for u32 { - type Error = HostError; - - fn try_from(val: SandboxValue) -> Result { - if let Value::I32(val) = val.0 { - Ok(val as u32) - } else { - Err(HostError) - } - } -} - -impl TryFrom for u64 { - type Error = HostError; - - fn try_from(val: SandboxValue) -> Result { - if let Value::I64(val) = val.0 { - Ok(val as u64) - } else { - Err(HostError) - } - } -} - macro_rules! wrap_syscall { ($func:ident) => { |caller, args| { diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index bd9ebe121ad..8acd5529c52 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -87,6 +87,52 @@ macro_rules! syscall_trace { const PTR_SPECIAL: u32 = u32::MAX; +/// Actually just wrapper around [`Value`] to implement conversions. +#[derive(Clone, Copy)] +struct SysCallValue(Value); + +impl From for SysCallValue { + fn from(value: i32) -> Self { + SysCallValue(Value::I32(value)) + } +} + +impl From for SysCallValue { + fn from(value: u32) -> Self { + SysCallValue(Value::I32(value as i32)) + } +} + +impl From for SysCallValue { + fn from(value: i64) -> Self { + SysCallValue(Value::I64(value)) + } +} + +impl TryFrom for u32 { + type Error = HostError; + + fn try_from(val: SysCallValue) -> Result { + if let Value::I32(val) = val.0 { + Ok(val as u32) + } else { + Err(HostError) + } + } +} + +impl TryFrom for u64 { + type Error = HostError; + + fn try_from(val: SysCallValue) -> Result { + if let Value::I64(val) = val.0 { + Ok(val as u64) + } else { + Err(HostError) + } + } +} + /// Actually just wrapper around [`ReturnValue`] to implement conversions. pub struct SysCallReturnValue(ReturnValue); @@ -161,14 +207,14 @@ macro_rules! impl_syscall_builder { where Handler: FnOnce($($generic),+) -> Call, Call: SysCall, - $( $generic: TryFrom,)+ + $( $generic: TryFrom,)+ { fn build(self, args: &[Value]) -> Result { const ARGS_AMOUNT: usize = impl_syscall_builder!(@count $($generic),+); let [$($generic),+]: [Value; ARGS_AMOUNT] = args.try_into().map_err(|_| HostError)?; $( - let $generic = SandboxValue($generic).try_into()?; + let $generic = SysCallValue($generic).try_into()?; )+ Ok((self)($($generic),+)) } @@ -214,9 +260,9 @@ struct FallibleSysCallContext { impl SysCallContext for FallibleSysCallContext { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = SandboxValue(*gas).try_into()?; + let gas: u64 = SysCallValue(*gas).try_into()?; let (res_ptr, args) = args.split_last().ok_or(HostError)?; - let res_ptr: u32 = SandboxValue(*res_ptr).try_into()?; + let res_ptr: u32 = SysCallValue(*res_ptr).try_into()?; Ok((FallibleSysCallContext { gas, res_ptr }, args)) } } @@ -252,7 +298,7 @@ pub struct InfallibleSysCallContext { impl SysCallContext for InfallibleSysCallContext { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = SandboxValue(*gas).try_into()?; + let gas: u64 = SysCallValue(*gas).try_into()?; Ok((Self { gas }, args)) } } From aefa730328dca3eb0c6251d6c47fc0c44be07a05 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Sun, 24 Sep 2023 20:23:15 +0300 Subject: [PATCH 18/37] Trace log sys-calls --- core-backend/src/funcs.rs | 61 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 8acd5529c52..df226376569 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -30,7 +30,7 @@ use crate::{ }; use alloc::string::{String, ToString}; use blake2_rfc::blake2b::blake2b; -use core::marker::PhantomData; +use core::{fmt, marker::PhantomData}; use gear_core::{ buffer::{RuntimeBuffer, RuntimeBufferSizeError}, costs::RuntimeCosts, @@ -51,41 +51,44 @@ use gsys::{ HashWithValue, TwoHashesWithValue, }; -#[macro_export(local_inner_macros)] -macro_rules! syscall_args_trace { - ($val:expr) => { - { - let s = ::core::stringify!($val); - if s.ends_with("_ptr") { - alloc::format!(", {} = {:#x?}", s, $val) - } else { - alloc::format!(", {} = {:?}", s, $val) - } - } - }; - ($val:expr, $($rest:expr),+) => { - { - let mut s = syscall_args_trace!($val); - s.push_str(&syscall_args_trace!($($rest),+)); - s +const PTR_SPECIAL: u32 = u32::MAX; + +struct ValueFormatter<'a>(&'a Value); + +impl fmt::Display for ValueFormatter<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Value::I32(i32) => fmt::Display::fmt(i32, f), + Value::I64(i64) => fmt::Display::fmt(i64, f), + Value::F32(f32) => fmt::Display::fmt(f32, f), + Value::F64(f64) => fmt::Display::fmt(f64, f), } - }; + } } -macro_rules! syscall_trace { - ($name:expr, $($args:expr),+) => { - { - ::log::trace!(target: "syscalls", "{}{}", $name, syscall_args_trace!($($args),+)); +struct ArgsFormatter<'a>(&'a [Value]); + +impl fmt::Display for ArgsFormatter<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut iter = self.0.iter(); + + if let Some(value) = iter.next() { + write!(f, "{}", ValueFormatter(value))?; } - }; - ($name:expr) => { - { - ::log::trace!(target: "syscalls", "{}", $name); + + for value in iter { + write!(f, ", {}", ValueFormatter(value))?; } + + Ok(()) } } -const PTR_SPECIAL: u32 = u32::MAX; +fn function_name() -> &'static str { + let s = core::any::type_name::(); + let pos = s.rfind("::").unwrap(); + &s[pos + 2..] +} /// Actually just wrapper around [`Value`] to implement conversions. #[derive(Clone, Copy)] @@ -345,6 +348,8 @@ where S: SysCall, R: Into, { + log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); + let (ctx, args) = S::Context::from_args(args)?; let sys_call = SysCallBuilder::build(handler, args)?; let (gas, value) = sys_call.execute(caller, ctx)?; From cbe69632126cdd30b9ff32e06dabe57a12ef4dfa Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Mon, 25 Sep 2023 20:45:04 +0300 Subject: [PATCH 19/37] Make traits crate public --- core-backend/src/funcs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index df226376569..63700c426c2 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -163,11 +163,11 @@ impl From for SysCallReturnValue { } } -pub trait SysCallContext: Sized { +pub(crate) trait SysCallContext: Sized { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError>; } -pub trait SysCall { +pub(crate) trait SysCall { type Context: SysCallContext; fn execute( @@ -177,7 +177,7 @@ pub trait SysCall { ) -> Result<(u64, T), HostError>; } -pub trait SysCallBuilder { +pub(crate) trait SysCallBuilder { fn build(self, args: &[Value]) -> Result; } From 73d9d64a027831af6c29d7bb5ba4e69b69a4b452 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Tue, 26 Sep 2023 16:40:10 +0300 Subject: [PATCH 20/37] Don't create caller in macro --- core-backend/src/env.rs | 6 +----- core-backend/src/funcs.rs | 9 ++++++--- core-backend/src/runtime.rs | 9 +++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 13d1bad2deb..94d9796b49b 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -26,7 +26,6 @@ use crate::{ funcs::FuncsHandler, memory::MemoryWrap, runtime, - runtime::CallerWrap, state::{HostState, State}, BackendExternalities, }; @@ -61,10 +60,7 @@ use gear_wasm_instrument::{ macro_rules! wrap_syscall { ($func:ident) => { - |caller, args| { - let mut caller = CallerWrap::prepare(caller)?; - FuncsHandler::execute(&mut caller, args, FuncsHandler::$func) - } + |caller, args| FuncsHandler::execute(caller, args, FuncsHandler::$func) }; } diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 63700c426c2..58151f0d1d0 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -24,8 +24,9 @@ use crate::{ TrapExplanation, UndefinedTerminationReason, UnrecoverableExecutionError, UnrecoverableMemoryError, }, - memory::{MemoryAccessError, WasmMemoryRead}, + memory::{ExecutorMemory, MemoryAccessError, WasmMemoryRead}, runtime::CallerWrap, + state::HostState, BackendExternalities, }; use alloc::string::{String, ToString}; @@ -338,7 +339,7 @@ where Ext::AllocError: BackendAllocSyscallError, { pub fn execute( - caller: &mut CallerWrap, + caller: &mut gear_sandbox::default_executor::Caller>, args: &[Value], handler: H, ) -> Result @@ -350,9 +351,11 @@ where { log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); + let mut caller = CallerWrap::prepare(caller); + let (ctx, args) = S::Context::from_args(args)?; let sys_call = SysCallBuilder::build(handler, args)?; - let (gas, value) = sys_call.execute(caller, ctx)?; + let (gas, value) = sys_call.execute(&mut caller, ctx)?; let value = value.into(); Ok(WasmReturnValue { diff --git a/core-backend/src/runtime.rs b/core-backend/src/runtime.rs index c5ee4388ab3..619fe7deba9 100644 --- a/core-backend/src/runtime.rs +++ b/core-backend/src/runtime.rs @@ -130,16 +130,13 @@ impl<'a, 'b, Ext: BackendExternalities + 'static> CallerWrap<'a, 'b, Ext> { res } - #[track_caller] - pub fn prepare( - caller: &'a mut Caller<'b, HostState>, - ) -> Result { + pub fn prepare(caller: &'a mut Caller<'b, HostState>) -> Self { let memory = caller_host_state_mut(caller).memory.clone(); - Ok(Self { + Self { caller, manager: Default::default(), memory, - }) + } } #[track_caller] From f7cd9cb01cd5f3b1641a41a2b5123859ad12fe4a Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Tue, 26 Sep 2023 16:41:45 +0300 Subject: [PATCH 21/37] Rename builder generics --- core-backend/src/funcs.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 58151f0d1d0..65d2ca3da20 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -182,9 +182,9 @@ pub(crate) trait SysCallBuilder { fn build(self, args: &[Value]) -> Result; } -impl SysCallBuilder for H +impl SysCallBuilder for B where - H: FnOnce() -> S, + B: FnOnce() -> S, S: SysCall, { fn build(self, args: &[Value]) -> Result { @@ -193,9 +193,9 @@ where } } -impl SysCallBuilder for H +impl SysCallBuilder for B where - H: for<'a> FnOnce(&'a [Value]) -> S, + B: for<'a> FnOnce(&'a [Value]) -> S, S: SysCall, { fn build(self, args: &[Value]) -> Result { @@ -206,10 +206,10 @@ where macro_rules! impl_syscall_builder { ($($generic:ident),+) => { #[allow(non_snake_case)] - impl SysCallBuilder - for Handler + impl SysCallBuilder + for Builder where - Handler: FnOnce($($generic),+) -> Call, + Builder: FnOnce($($generic),+) -> Call, Call: SysCall, $( $generic: TryFrom,)+ { @@ -338,23 +338,23 @@ where RunFallibleError: From, Ext::AllocError: BackendAllocSyscallError, { - pub fn execute( + pub fn execute( caller: &mut gear_sandbox::default_executor::Caller>, args: &[Value], - handler: H, + builder: B, ) -> Result where - H: SysCallBuilder, + B: SysCallBuilder, Args: ?Sized, S: SysCall, R: Into, { - log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); + log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); let mut caller = CallerWrap::prepare(caller); let (ctx, args) = S::Context::from_args(args)?; - let sys_call = SysCallBuilder::build(handler, args)?; + let sys_call = builder.build(args)?; let (gas, value) = sys_call.execute(&mut caller, ctx)?; let value = value.into(); From 3a62d20046010fd49a64601b28d48d7533b22568 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Tue, 26 Sep 2023 16:45:29 +0300 Subject: [PATCH 22/37] Add comment to `wrap_syscall` --- core-backend/src/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 94d9796b49b..1f0b4fdf24e 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -58,6 +58,9 @@ use gear_wasm_instrument::{ GLOBAL_NAME_GAS, STACK_END_EXPORT_NAME, }; +// we have requirement to pass function pointer for `gear_sandbox` +// so the only reason this macro exists is const function pointers are not stabilized yet +// so we create non-capturing closure that can be coerced into function pointer macro_rules! wrap_syscall { ($func:ident) => { |caller, args| FuncsHandler::execute(caller, args, FuncsHandler::$func) From 151921f360fb0ec8fc00fbf817c141b8ef691937 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 5 Oct 2023 18:43:19 +0300 Subject: [PATCH 23/37] Add comment for `impl_syscall_builder` --- core-backend/src/funcs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 65d2ca3da20..0515c5d313a 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -203,6 +203,7 @@ where } } +// implement [`SysCallBuilder`] for functions with different amount of arguments macro_rules! impl_syscall_builder { ($($generic:ident),+) => { #[allow(non_snake_case)] From 638e86305bc90d8f6b171ebbb8d6c711d0d7d6ab Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 5 Oct 2023 18:54:29 +0300 Subject: [PATCH 24/37] Refactor `InitPacket` constructors --- core-backend/src/funcs.rs | 4 ++-- core/src/message/init.rs | 49 +++++++++------------------------------ pallets/gear/src/lib.rs | 6 ++--- 3 files changed, 15 insertions(+), 44 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 0515c5d313a..7f2ba139873 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -1249,11 +1249,11 @@ where ctx.ext_mut() .create_program( - InitPacket::maybe_with_gas( + InitPacket::new_from_program( code_id.into(), salt, payload, - Some(message_id), + message_id, gas_limit, value, ), diff --git a/core/src/message/init.rs b/core/src/message/init.rs index 09ba29eb19b..fee255a2573 100644 --- a/core/src/message/init.rs +++ b/core/src/message/init.rs @@ -131,67 +131,40 @@ pub struct InitPacket { } impl InitPacket { - /// Create new InitPacket without gas. - pub fn new( + /// Create new InitPacket via user. + pub fn new_from_user( code_id: CodeId, salt: Salt, payload: Payload, - message_id: Option, + gas_limit: GasLimit, value: Value, ) -> Self { - let program_id = if let Some(id) = message_id { - ProgramId::generate_from_program(code_id, salt.inner(), id) - } else { - ProgramId::generate_from_user(code_id, salt.inner()) - }; Self { - program_id, + program_id: ProgramId::generate_from_user(code_id, salt.inner()), code_id, salt, payload, + gas_limit: Some(gas_limit), value, - gas_limit: None, } } - /// Create new InitPacket with gas. - pub fn new_with_gas( + /// Create new InitPacket via program. + pub fn new_from_program( code_id: CodeId, salt: Salt, payload: Payload, - message_id: Option, - gas_limit: GasLimit, + message_id: MessageId, + gas_limit: Option, value: Value, ) -> Self { - let program_id = if let Some(id) = message_id { - ProgramId::generate_from_program(code_id, salt.inner(), id) - } else { - ProgramId::generate_from_user(code_id, salt.inner()) - }; Self { - program_id, + program_id: ProgramId::generate_from_program(code_id, salt.inner(), message_id), code_id, salt, payload, + gas_limit, value, - gas_limit: Some(gas_limit), - } - } - - /// Create new InitPacket with optional gas. - pub fn maybe_with_gas( - code_id: CodeId, - salt: Salt, - payload: Payload, - message_id: Option, - gas_limit: Option, - value: Value, - ) -> Self { - match gas_limit { - None => Self::new(code_id, salt, payload, message_id, value), - Some(gas_limit) => { - Self::new_with_gas(code_id, salt, payload, message_id, gas_limit, value) - } } } diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index 5bef97c2c9c..88b6b962ace 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -572,14 +572,13 @@ pub mod pallet { let code_and_id = CodeAndId::new(code); let code_info = CodeInfo::from_code_and_id(&code_and_id); - let packet = InitPacket::new_with_gas( + let packet = InitPacket::new_from_user( code_and_id.code_id(), salt.try_into() .map_err(|err: PayloadSizeError| DispatchError::Other(err.into()))?, init_payload .try_into() .map_err(|err: PayloadSizeError| DispatchError::Other(err.into()))?, - None, gas_limit, value.unique_saturated_into(), ); @@ -1174,14 +1173,13 @@ pub mod pallet { gas_limit: u64, value: BalanceOf, ) -> Result { - let packet = InitPacket::new_with_gas( + let packet = InitPacket::new_from_user( code_id, salt.try_into() .map_err(|err: PayloadSizeError| DispatchError::Other(err.into()))?, init_payload .try_into() .map_err(|err: PayloadSizeError| DispatchError::Other(err.into()))?, - None, gas_limit, value.unique_saturated_into(), ); From 0fb6821b2ebb0270ed582421eda0d2bbab56ca6f Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:03:50 +0300 Subject: [PATCH 25/37] Return `#[track_caller]` back for `prepare` --- core-backend/src/runtime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core-backend/src/runtime.rs b/core-backend/src/runtime.rs index 619fe7deba9..c59d4d50b9f 100644 --- a/core-backend/src/runtime.rs +++ b/core-backend/src/runtime.rs @@ -130,6 +130,7 @@ impl<'a, 'b, Ext: BackendExternalities + 'static> CallerWrap<'a, 'b, Ext> { res } + #[track_caller] pub fn prepare(caller: &'a mut Caller<'b, HostState>) -> Self { let memory = caller_host_state_mut(caller).memory.clone(); Self { From 8a53782994062597866468744f7be893a9dd47e6 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:23:43 +0300 Subject: [PATCH 26/37] Move log entities into special module --- core-backend/src/funcs.rs | 41 ++------------------------ core-backend/src/lib.rs | 1 + core-backend/src/log.rs | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 core-backend/src/log.rs diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 7f2ba139873..1c5232b2cea 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -31,7 +31,7 @@ use crate::{ }; use alloc::string::{String, ToString}; use blake2_rfc::blake2b::blake2b; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; use gear_core::{ buffer::{RuntimeBuffer, RuntimeBufferSizeError}, costs::RuntimeCosts, @@ -54,43 +54,6 @@ use gsys::{ const PTR_SPECIAL: u32 = u32::MAX; -struct ValueFormatter<'a>(&'a Value); - -impl fmt::Display for ValueFormatter<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - Value::I32(i32) => fmt::Display::fmt(i32, f), - Value::I64(i64) => fmt::Display::fmt(i64, f), - Value::F32(f32) => fmt::Display::fmt(f32, f), - Value::F64(f64) => fmt::Display::fmt(f64, f), - } - } -} - -struct ArgsFormatter<'a>(&'a [Value]); - -impl fmt::Display for ArgsFormatter<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut iter = self.0.iter(); - - if let Some(value) = iter.next() { - write!(f, "{}", ValueFormatter(value))?; - } - - for value in iter { - write!(f, ", {}", ValueFormatter(value))?; - } - - Ok(()) - } -} - -fn function_name() -> &'static str { - let s = core::any::type_name::(); - let pos = s.rfind("::").unwrap(); - &s[pos + 2..] -} - /// Actually just wrapper around [`Value`] to implement conversions. #[derive(Clone, Copy)] struct SysCallValue(Value); @@ -350,7 +313,7 @@ where S: SysCall, R: Into, { - log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); + crate::log::trace_syscall::(args); let mut caller = CallerWrap::prepare(caller); diff --git a/core-backend/src/lib.rs b/core-backend/src/lib.rs index 1a20d9bae1f..601e2b843f8 100644 --- a/core-backend/src/lib.rs +++ b/core-backend/src/lib.rs @@ -25,6 +25,7 @@ extern crate alloc; pub mod env; pub mod error; mod funcs; +mod log; pub mod memory; #[cfg(any(feature = "mock", test))] pub mod mock; diff --git a/core-backend/src/log.rs b/core-backend/src/log.rs new file mode 100644 index 00000000000..a5203908f7c --- /dev/null +++ b/core-backend/src/log.rs @@ -0,0 +1,61 @@ +// This file is part of Gear. + +// Copyright (C) 2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use core::fmt; +use gear_sandbox::Value; + +struct ValueFormatter<'a>(&'a Value); + +impl fmt::Display for ValueFormatter<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Value::I32(i32) => fmt::Display::fmt(i32, f), + Value::I64(i64) => fmt::Display::fmt(i64, f), + Value::F32(f32) => fmt::Display::fmt(f32, f), + Value::F64(f64) => fmt::Display::fmt(f64, f), + } + } +} + +struct ArgsFormatter<'a>(&'a [Value]); + +impl fmt::Display for ArgsFormatter<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut iter = self.0.iter(); + + if let Some(value) = iter.next() { + write!(f, "{}", ValueFormatter(value))?; + } + + for value in iter { + write!(f, ", {}", ValueFormatter(value))?; + } + + Ok(()) + } +} + +fn function_name() -> &'static str { + let s = core::any::type_name::(); + let pos = s.rfind("::").unwrap(); + &s[pos + 2..] +} + +pub fn trace_syscall(args: &[Value]) { + log::trace!(target: "syscalls", "{}({})", function_name::(), ArgsFormatter(args)); +} From b796d330c8a6d1658907b7cc3e420aac646633f6 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:25:22 +0300 Subject: [PATCH 27/37] Use `Gas` alias --- core-backend/src/funcs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 1c5232b2cea..93504e44eb9 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -48,7 +48,7 @@ use gear_sandbox::{ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, - ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Hash, + ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Gas, Hash, HashWithValue, TwoHashesWithValue, }; @@ -213,7 +213,7 @@ where self, caller: &mut CallerWrap, ctx: Self::Context, - ) -> Result<(u64, T), HostError> { + ) -> Result<(Gas, T), HostError> { let res = (self)(caller)?; let InfallibleSysCallContext { gas } = ctx; Ok((gas, res)) @@ -221,14 +221,14 @@ where } struct FallibleSysCallContext { - gas: u64, + gas: Gas, res_ptr: u32, } impl SysCallContext for FallibleSysCallContext { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = SysCallValue(*gas).try_into()?; + let gas: Gas = SysCallValue(*gas).try_into()?; let (res_ptr, args) = args.split_last().ok_or(HostError)?; let res_ptr: u32 = SysCallValue(*res_ptr).try_into()?; Ok((FallibleSysCallContext { gas, res_ptr }, args)) @@ -260,13 +260,13 @@ where } pub struct InfallibleSysCallContext { - gas: u64, + gas: Gas, } impl SysCallContext for InfallibleSysCallContext { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { let (gas, args) = args.split_first().ok_or(HostError)?; - let gas: u64 = SysCallValue(*gas).try_into()?; + let gas: Gas = SysCallValue(*gas).try_into()?; Ok((Self { gas }, args)) } } From b1631d17900f0af4fdb941fd611fd5f0667f1dc6 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:27:13 +0300 Subject: [PATCH 28/37] Remove accidental comment --- core-backend/src/funcs.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 93504e44eb9..5b2036d2a3b 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -586,7 +586,6 @@ where ) } - // TODO: write proper benchmark #2825 pub fn signal_code() -> impl SysCall { ( RuntimeCosts::SignalCode, @@ -814,7 +813,6 @@ where ) } - // TODO: write proper benchmark #2825 pub fn signal_from() -> impl SysCall { ( RuntimeCosts::SignalFrom, From e09e69f39cdcc48d18905ecc1120a1171dc5eaee Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:29:10 +0300 Subject: [PATCH 29/37] Import `Caller` --- core-backend/src/funcs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 5b2036d2a3b..a3006d33c4a 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -44,7 +44,7 @@ use gear_core::{ pages::{PageNumber, PageU32Size, WasmPage}, }; use gear_core_errors::{MessageError, ReplyCode, SignalCode}; -use gear_sandbox::{ReturnValue, Value}; +use gear_sandbox::{default_executor::Caller, ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, @@ -303,7 +303,7 @@ where Ext::AllocError: BackendAllocSyscallError, { pub fn execute( - caller: &mut gear_sandbox::default_executor::Caller>, + caller: &mut Caller>, args: &[Value], builder: B, ) -> Result From 188e7dded149e2ed678aa234f2091e555fbc3be5 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:41:04 +0300 Subject: [PATCH 30/37] Turn `FallibleSysCall` into structure --- core-backend/src/funcs.rs | 165 ++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 95 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index a3006d33c4a..af6652aff3b 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -235,10 +235,21 @@ impl SysCallContext for FallibleSysCallContext { } } -#[derive(Default)] -struct FallibleSysCallError(PhantomData); +struct FallibleSysCall { + costs: RuntimeCosts, + error: PhantomData, + f: F, +} -type FallibleSysCall = (RuntimeCosts, FallibleSysCallError, F); +impl FallibleSysCall<(), F> { + fn new(costs: RuntimeCosts, f: F) -> FallibleSysCall { + FallibleSysCall { + costs, + error: PhantomData, + f, + } + } +} impl SysCall for FallibleSysCall where @@ -253,9 +264,13 @@ where caller: &mut CallerWrap, context: Self::Context, ) -> Result<(u64, ()), HostError> { - let (costs, _error, func) = self; + let Self { + costs, + error: _error, + f, + } = self; let FallibleSysCallContext { gas, res_ptr } = context; - caller.run_fallible::(gas, res_ptr, costs, func) + caller.run_fallible::(gas, res_ptr, costs, f) } } @@ -377,9 +392,8 @@ where } pub fn send(pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::Send(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, None, delay) }, @@ -393,9 +407,8 @@ where gas_limit: u64, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendWGas(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, Some(gas_limit), delay) }, @@ -430,9 +443,8 @@ where } pub fn send_commit(handle: u32, pid_value_ptr: u32, delay: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendCommit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_commit_inner(ctx, handle, pid_value_ptr, None, delay) }, @@ -445,9 +457,8 @@ where gas_limit: u64, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendCommitWGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_commit_inner(ctx, handle, pid_value_ptr, Some(gas_limit), delay) }, @@ -455,17 +466,15 @@ where } pub fn send_init() -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendInit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| ctx.ext_mut().send_init().map_err(Into::into), ) } pub fn send_push(handle: u32, payload_ptr: u32, len: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendPush(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_payload = ctx.manager.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -483,9 +492,8 @@ where len: u32, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReservationSend(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); let read_payload = ctx.manager.register_read(payload_ptr, len); @@ -512,9 +520,8 @@ where rid_pid_value_ptr: u32, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReservationSendCommit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_rid_pid_value = ctx.manager.register_read_as(rid_pid_value_ptr); let TwoHashesWithValue { @@ -536,23 +543,19 @@ where } pub fn read(at: u32, len: u32, buffer_ptr: u32) -> impl SysCall { - ( - RuntimeCosts::Read, - FallibleSysCallError::::default(), - move |ctx: &mut CallerWrap| { - let payload_lock = ctx.ext_mut().lock_payload(at, len)?; - payload_lock - .drop_with::(|payload_access| { - let write_buffer = ctx.manager.register_write(buffer_ptr, len); - let write_res = ctx.write(write_buffer, payload_access.as_slice()); - let unlock_bound = ctx.ext_mut().unlock_payload(payload_access.into_lock()); - - DropPayloadLockBound::from((unlock_bound, write_res)) - }) - .into_inner() - .map_err(Into::into) - }, - ) + FallibleSysCall::new::(RuntimeCosts::Read, move |ctx: &mut CallerWrap| { + let payload_lock = ctx.ext_mut().lock_payload(at, len)?; + payload_lock + .drop_with::(|payload_access| { + let write_buffer = ctx.manager.register_write(buffer_ptr, len); + let write_res = ctx.write(write_buffer, payload_access.as_slice()); + let unlock_bound = ctx.ext_mut().unlock_payload(payload_access.into_lock()); + + DropPayloadLockBound::from((unlock_bound, write_res)) + }) + .into_inner() + .map_err(Into::into) + }) } pub fn size(size_ptr: u32) -> impl SysCall { @@ -574,9 +577,8 @@ where } pub fn reply_code() -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyCode, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .reply_code() @@ -587,9 +589,8 @@ where } pub fn signal_code() -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SignalCode, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .signal_code() @@ -706,9 +707,8 @@ where } pub fn reply(payload_ptr: u32, len: u32, value_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::Reply(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_inner(ctx, payload_ptr, len, None, value_ptr) }, @@ -721,9 +721,8 @@ where gas_limit: u64, value_ptr: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyWGas(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_inner(ctx, payload_ptr, len, Some(gas_limit), value_ptr) }, @@ -747,17 +746,15 @@ where } pub fn reply_commit(value_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyCommit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| Self::reply_commit_inner(ctx, None, value_ptr), ) } pub fn reply_commit_wgas(gas_limit: u64, value_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyCommitWGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_commit_inner(ctx, Some(gas_limit), value_ptr) }, @@ -765,9 +762,8 @@ where } pub fn reservation_reply(rid_value_ptr: u32, payload_ptr: u32, len: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReservationReply(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); let read_payload = ctx.manager.register_read(payload_ptr, len); @@ -785,9 +781,8 @@ where } pub fn reservation_reply_commit(rid_value_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReservationReplyCommit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_rid_value = ctx.manager.register_read_as(rid_value_ptr); let HashWithValue { @@ -806,25 +801,22 @@ where } pub fn reply_to() -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyTo, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| ctx.ext_mut().reply_to().map_err(Into::into), ) } pub fn signal_from() -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SignalFrom, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| ctx.ext_mut().signal_from().map_err(Into::into), ) } pub fn reply_push(payload_ptr: u32, len: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyPush(len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_payload = ctx.manager.register_read(payload_ptr, len); let payload = ctx.read(read_payload)?; @@ -856,9 +848,8 @@ where } pub fn reply_input(offset: u32, len: u32, value_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyInput, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_input_inner(ctx, offset, len, None, value_ptr) }, @@ -871,9 +862,8 @@ where gas_limit: u64, value_ptr: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyInputWGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::reply_input_inner(ctx, offset, len, Some(gas_limit), value_ptr) }, @@ -881,9 +871,8 @@ where } pub fn reply_push_input(offset: u32, len: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyPushInput, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .reply_push_input(offset, len) @@ -925,9 +914,8 @@ where } pub fn send_input(pid_value_ptr: u32, offset: u32, len: u32, delay: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendInput, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_input_inner(ctx, pid_value_ptr, offset, len, None, delay) }, @@ -941,9 +929,8 @@ where gas_limit: u64, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendInputWGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::send_input_inner(ctx, pid_value_ptr, offset, len, Some(gas_limit), delay) }, @@ -951,9 +938,8 @@ where } pub fn send_push_input(handle: u32, offset: u32, len: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SendPushInput, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .send_push_input(handle, offset, len) @@ -1003,9 +989,8 @@ where } pub fn reserve_gas(gas_value: u64, duration: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReserveGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .reserve_gas(gas_value, duration) @@ -1015,9 +1000,8 @@ where } pub fn reply_deposit(message_id_ptr: u32, gas_value: u64) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::ReplyDeposit, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); let message_id = ctx.read_decoded(read_message_id)?; @@ -1030,9 +1014,8 @@ where } pub fn unreserve_gas(reservation_id_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::UnreserveGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_reservation_id = ctx.manager.register_read_decoded(reservation_id_ptr); let reservation_id = ctx.read_decoded(read_reservation_id)?; @@ -1045,9 +1028,8 @@ where } pub fn system_reserve_gas(gas_value: u64) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::SystemReserveGas, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { ctx.ext_mut() .system_reserve_gas(gas_value) @@ -1090,9 +1072,8 @@ where } pub fn pay_program_rent(rent_pid_ptr: u32) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::PayProgramRent, - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { let read_rent_pid = ctx.manager.register_read_as(rent_pid_ptr); @@ -1173,16 +1154,12 @@ where } pub fn wake(message_id_ptr: u32, delay: u32) -> impl SysCall { - ( - RuntimeCosts::Wake, - FallibleSysCallError::::default(), - move |ctx: &mut CallerWrap| { - let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); - let message_id = ctx.read_decoded(read_message_id)?; + FallibleSysCall::new::(RuntimeCosts::Wake, move |ctx: &mut CallerWrap| { + let read_message_id = ctx.manager.register_read_decoded(message_id_ptr); + let message_id = ctx.read_decoded(read_message_id)?; - ctx.ext_mut().wake(message_id, delay).map_err(Into::into) - }, - ) + ctx.ext_mut().wake(message_id, delay).map_err(Into::into) + }) } #[allow(clippy::too_many_arguments)] @@ -1231,9 +1208,8 @@ where payload_len: u32, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::CreateProgram(payload_len, salt_len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| -> Result<_, RunFallibleError> { Self::create_program_inner( ctx, @@ -1258,9 +1234,8 @@ where gas_limit: u64, delay: u32, ) -> impl SysCall { - ( + FallibleSysCall::new::( RuntimeCosts::CreateProgramWGas(payload_len, salt_len), - FallibleSysCallError::::default(), move |ctx: &mut CallerWrap| { Self::create_program_inner( ctx, From 84c3348c7d0e89cf5625e0ebbd77a5b3c0239c3a Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:46:28 +0300 Subject: [PATCH 31/37] Turn `InfallibleSysCall` into structure --- core-backend/src/funcs.rs | 57 ++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index af6652aff3b..3db0b7677e5 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -286,7 +286,16 @@ impl SysCallContext for InfallibleSysCallContext { } } -type InfallibleSysCall = (RuntimeCosts, F); +struct InfallibleSysCall { + costs: RuntimeCosts, + f: F, +} + +impl InfallibleSysCall { + fn new(costs: RuntimeCosts, f: F) -> Self { + Self { costs, f } + } +} impl SysCall for InfallibleSysCall where @@ -300,9 +309,9 @@ where caller: &mut CallerWrap, ctx: Self::Context, ) -> Result<(u64, T), HostError> { - let (costs, func) = self; + let Self { costs, f } = self; let InfallibleSysCallContext { gas } = ctx; - caller.run_any::(gas, costs, func) + caller.run_any::(gas, costs, f) } } @@ -559,7 +568,7 @@ where } pub fn size(size_ptr: u32) -> impl SysCall { - (RuntimeCosts::Size, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Size, move |ctx: &mut CallerWrap| { let size = ctx.ext_mut().size()? as u32; let write_size = ctx.manager.register_write_as(size_ptr); @@ -569,7 +578,7 @@ where } pub fn exit(inheritor_id_ptr: u32) -> impl SysCall { - (RuntimeCosts::Exit, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Exit, move |ctx: &mut CallerWrap| { let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); let inheritor_id = ctx.read_decoded(read_inheritor_id)?; Err(ActorTerminationReason::Exit(inheritor_id).into()) @@ -601,7 +610,7 @@ where } pub fn alloc(pages: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::Alloc(pages), move |ctx: &mut CallerWrap| { let res = ctx.alloc(pages); @@ -623,7 +632,7 @@ where } pub fn free(page_no: u32) -> impl SysCall { - (RuntimeCosts::Free, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Free, move |ctx: &mut CallerWrap| { let page = WasmPage::new(page_no).map_err(|_| { UndefinedTerminationReason::Actor(ActorTerminationReason::Trap( TrapExplanation::Unknown, @@ -647,7 +656,7 @@ where } pub fn block_height(height_ptr: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::BlockHeight, move |ctx: &mut CallerWrap| { let height = ctx.ext_mut().block_height()?; @@ -660,7 +669,7 @@ where } pub fn block_timestamp(timestamp_ptr: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::BlockTimestamp, move |ctx: &mut CallerWrap| { let timestamp = ctx.ext_mut().block_timestamp()?; @@ -673,7 +682,7 @@ where } pub fn random(subject_ptr: u32, bn_random_ptr: u32) -> impl SysCall { - (RuntimeCosts::Random, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Random, move |ctx: &mut CallerWrap| { let read_subject = ctx.manager.register_read_decoded(subject_ptr); let write_bn_random = ctx.manager.register_write_as(bn_random_ptr); @@ -949,7 +958,7 @@ where } pub fn debug(data_ptr: u32, data_len: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::Debug(data_len), move |ctx: &mut CallerWrap| { let read_data = ctx.manager.register_read(data_ptr, data_len); @@ -972,7 +981,7 @@ where } pub fn panic(data_ptr: u32, data_len: u32) -> impl SysCall { - (RuntimeCosts::Null, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Null, move |ctx: &mut CallerWrap| { let read_data = ctx.manager.register_read(data_ptr, data_len); let data = ctx.read(read_data).unwrap_or_default(); @@ -983,7 +992,7 @@ where } pub fn oom_panic() -> impl SysCall { - (RuntimeCosts::Null, |_ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Null, |_ctx: &mut CallerWrap| { Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) }) } @@ -1039,7 +1048,7 @@ where } pub fn gas_available(gas_ptr: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::GasAvailable, move |ctx: &mut CallerWrap| { let gas_available = ctx.ext_mut().gas_available()?; @@ -1052,7 +1061,7 @@ where } pub fn message_id(message_id_ptr: u32) -> impl SysCall { - (RuntimeCosts::MsgId, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::MsgId, move |ctx: &mut CallerWrap| { let message_id = ctx.ext_mut().message_id()?; let write_message_id = ctx.manager.register_write_as(message_id_ptr); @@ -1062,7 +1071,7 @@ where } pub fn program_id(program_id_ptr: u32) -> impl SysCall { - (RuntimeCosts::ProgramId, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::ProgramId, move |ctx: &mut CallerWrap| { let program_id = ctx.ext_mut().program_id()?; let write_program_id = ctx.manager.register_write_as(program_id_ptr); @@ -1090,7 +1099,7 @@ where } pub fn source(source_ptr: u32) -> impl SysCall { - (RuntimeCosts::Source, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Source, move |ctx: &mut CallerWrap| { let source = ctx.ext_mut().source()?; let write_source = ctx.manager.register_write_as(source_ptr); @@ -1100,7 +1109,7 @@ where } pub fn value(value_ptr: u32) -> impl SysCall { - (RuntimeCosts::Value, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Value, move |ctx: &mut CallerWrap| { let value = ctx.ext_mut().value()?; let write_value = ctx.manager.register_write_as(value_ptr); @@ -1110,7 +1119,7 @@ where } pub fn value_available(value_ptr: u32) -> impl SysCall { - ( + InfallibleSysCall::new( RuntimeCosts::ValueAvailable, move |ctx: &mut CallerWrap| { let value_available = ctx.ext_mut().value_available()?; @@ -1123,27 +1132,27 @@ where } pub fn leave() -> impl SysCall { - (RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| { Err(ActorTerminationReason::Leave.into()) }) } pub fn wait() -> impl SysCall { - (RuntimeCosts::Wait, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Wait, move |ctx: &mut CallerWrap| { ctx.ext_mut().wait()?; Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) }) } pub fn wait_for(duration: u32) -> impl SysCall { - (RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap| { ctx.ext_mut().wait_for(duration)?; Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) }) } pub fn wait_up_to(duration: u32) -> impl SysCall { - (RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap| { let waited_type = if ctx.ext_mut().wait_up_to(duration)? { MessageWaitedType::WaitUpToFull } else { @@ -1252,7 +1261,7 @@ where } pub fn forbidden(_args: &[Value]) -> impl SysCall { - (RuntimeCosts::Null, |_: &mut CallerWrap| { + InfallibleSysCall::new(RuntimeCosts::Null, |_: &mut CallerWrap| { Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) }) } From e0c21c6b7d820ac37fd0d93416fe57d30f2d8f69 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:51:09 +0300 Subject: [PATCH 32/37] Turn `SimpleSysCall` into structure --- core-backend/src/funcs.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 3db0b7677e5..f5dbf210411 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -131,6 +131,12 @@ pub(crate) trait SysCallContext: Sized { fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError>; } +impl SysCallContext for () { + fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> { + Ok(((), args)) + } +} + pub(crate) trait SysCall { type Context: SysCallContext; @@ -200,23 +206,27 @@ impl_syscall_builder!(A, B, C, D, E); impl_syscall_builder!(A, B, C, D, E, F); impl_syscall_builder!(A, B, C, D, E, F, G); -type SimpleSysCall = F; +struct SimpleSysCall(F); + +impl SimpleSysCall { + fn new(f: F) -> Self { + Self(f) + } +} impl SysCall for SimpleSysCall where - F: FnOnce(&mut CallerWrap) -> Result, + F: FnOnce(&mut CallerWrap) -> Result<(Gas, T), HostError>, Ext: BackendExternalities + 'static, { - type Context = InfallibleSysCallContext; + type Context = (); fn execute( self, caller: &mut CallerWrap, - ctx: Self::Context, + (): Self::Context, ) -> Result<(Gas, T), HostError> { - let res = (self)(caller)?; - let InfallibleSysCallContext { gas } = ctx; - Ok((gas, res)) + (self.0)(caller) } } @@ -1266,8 +1276,8 @@ where }) } - pub fn out_of_gas() -> impl SysCall { - |ctx: &mut CallerWrap| { + pub fn out_of_gas(_gas: Gas) -> impl SysCall { + SimpleSysCall::new(|ctx: &mut CallerWrap| { let ext = ctx.ext_mut(); let current_counter = ext.current_counter_type(); log::trace!(target: "syscalls", "[out_of_gas] Current counter in global represents {current_counter:?}"); @@ -1282,6 +1292,6 @@ where ctx.set_termination_reason(termination_reason.into()); Err(HostError) - } + }) } } From fd928f2fc8ff0da863fa6a100da321ba1a8538a5 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Wed, 18 Oct 2023 23:51:29 +0300 Subject: [PATCH 33/37] `SimpleSysCall` -> `RawSysCall` --- core-backend/src/funcs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index f5dbf210411..04a926ecee3 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -206,15 +206,15 @@ impl_syscall_builder!(A, B, C, D, E); impl_syscall_builder!(A, B, C, D, E, F); impl_syscall_builder!(A, B, C, D, E, F, G); -struct SimpleSysCall(F); +struct RawSysCall(F); -impl SimpleSysCall { +impl RawSysCall { fn new(f: F) -> Self { Self(f) } } -impl SysCall for SimpleSysCall +impl SysCall for RawSysCall where F: FnOnce(&mut CallerWrap) -> Result<(Gas, T), HostError>, Ext: BackendExternalities + 'static, @@ -1277,7 +1277,7 @@ where } pub fn out_of_gas(_gas: Gas) -> impl SysCall { - SimpleSysCall::new(|ctx: &mut CallerWrap| { + RawSysCall::new(|ctx: &mut CallerWrap| { let ext = ctx.ext_mut(); let current_counter = ext.current_counter_type(); log::trace!(target: "syscalls", "[out_of_gas] Current counter in global represents {current_counter:?}"); From ca927b222f51cd84b12a2a64d8dff4e7307277f4 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 19 Oct 2023 00:01:16 +0300 Subject: [PATCH 34/37] Add some docs --- core-backend/src/funcs.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 04a926ecee3..7a3244bd8ab 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -206,6 +206,7 @@ impl_syscall_builder!(A, B, C, D, E); impl_syscall_builder!(A, B, C, D, E, F); impl_syscall_builder!(A, B, C, D, E, F, G); +/// "raw" sys-call without any argument parsing or without calling [`CallerWrap`] helper methods struct RawSysCall(F); impl RawSysCall { @@ -230,6 +231,7 @@ where } } +/// Fallible sys-call context that parses `gas` and `err_ptr` arguments. struct FallibleSysCallContext { gas: Gas, res_ptr: u32, @@ -245,6 +247,7 @@ impl SysCallContext for FallibleSysCallContext { } } +/// Fallible sys-call that calls [`CallerWrap::run_fallible`] underneath. struct FallibleSysCall { costs: RuntimeCosts, error: PhantomData, @@ -284,6 +287,7 @@ where } } +/// Infallible sys-call context that parses `gas` argument. pub struct InfallibleSysCallContext { gas: Gas, } @@ -296,6 +300,7 @@ impl SysCallContext for InfallibleSysCallContext { } } +/// Infallible sys-call that calls [`CallerWrap::run_any`] underneath struct InfallibleSysCall { costs: RuntimeCosts, f: F, From 0c5bbb95014ca6c61d061600117ce944abb9d239 Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 19 Oct 2023 00:16:38 +0300 Subject: [PATCH 35/37] Use `Gas` alias in some other places too --- core-backend/src/funcs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 7a3244bd8ab..df867c59c10 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -144,7 +144,7 @@ pub(crate) trait SysCall { self, caller: &mut CallerWrap, ctx: Self::Context, - ) -> Result<(u64, T), HostError>; + ) -> Result<(Gas, T), HostError>; } pub(crate) trait SysCallBuilder { @@ -276,7 +276,7 @@ where self, caller: &mut CallerWrap, context: Self::Context, - ) -> Result<(u64, ()), HostError> { + ) -> Result<(Gas, ()), HostError> { let Self { costs, error: _error, @@ -323,7 +323,7 @@ where self, caller: &mut CallerWrap, ctx: Self::Context, - ) -> Result<(u64, T), HostError> { + ) -> Result<(Gas, T), HostError> { let Self { costs, f } = self; let InfallibleSysCallContext { gas } = ctx; caller.run_any::(gas, costs, f) From 20f53cfa236f1be18684f263d2fa010a7d52eb7a Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 19 Oct 2023 00:27:28 +0300 Subject: [PATCH 36/37] Rename generics --- core-backend/src/funcs.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index df867c59c10..848150de27f 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -147,27 +147,32 @@ pub(crate) trait SysCall { ) -> Result<(Gas, T), HostError>; } -pub(crate) trait SysCallBuilder { - fn build(self, args: &[Value]) -> Result; +/// Trait is implemented for functions. +/// +/// # Generics +/// `Args` is to make specialization based on function arguments +/// `Ext` and `Res` are for sys-call itself (`SysCall`) +pub(crate) trait SysCallBuilder { + fn build(self, args: &[Value]) -> Result; } -impl SysCallBuilder for B +impl SysCallBuilder for Builder where - B: FnOnce() -> S, - S: SysCall, + Builder: FnOnce() -> Call, + Call: SysCall, { - fn build(self, args: &[Value]) -> Result { + fn build(self, args: &[Value]) -> Result { let _: [Value; 0] = args.try_into().map_err(|_| HostError)?; Ok((self)()) } } -impl SysCallBuilder for B +impl SysCallBuilder for Builder where - B: for<'a> FnOnce(&'a [Value]) -> S, - S: SysCall, + Builder: for<'a> FnOnce(&'a [Value]) -> Call, + Call: SysCall, { - fn build(self, args: &[Value]) -> Result { + fn build(self, args: &[Value]) -> Result { Ok((self)(args)) } } From e870d2d125c336f95586588542dd3e50d919fc0a Mon Sep 17 00:00:00 2001 From: Arseniy Lyashenko Date: Thu, 19 Oct 2023 00:41:26 +0300 Subject: [PATCH 37/37] Rename generics in `execute` --- core-backend/src/funcs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 848150de27f..7bfe666ce92 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -346,22 +346,22 @@ where RunFallibleError: From, Ext::AllocError: BackendAllocSyscallError, { - pub fn execute( + pub fn execute( caller: &mut Caller>, args: &[Value], - builder: B, + builder: Builder, ) -> Result where - B: SysCallBuilder, + Builder: SysCallBuilder, Args: ?Sized, - S: SysCall, - R: Into, + Call: SysCall, + Res: Into, { - crate::log::trace_syscall::(args); + crate::log::trace_syscall::(args); let mut caller = CallerWrap::prepare(caller); - let (ctx, args) = S::Context::from_args(args)?; + let (ctx, args) = Call::Context::from_args(args)?; let sys_call = builder.build(args)?; let (gas, value) = sys_call.execute(&mut caller, ctx)?; let value = value.into();