diff --git a/Cargo.lock b/Cargo.lock
index 22bdae51378..53af44bb54b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4070,7 +4070,6 @@ dependencies = [
"blake2-rfc",
"derive_more",
"gear-core",
- "gear-core-backend-codegen",
"gear-core-errors",
"gear-lazy-pages-common",
"gear-sandbox",
@@ -4081,15 +4080,6 @@ dependencies = [
"parity-scale-codec",
]
-[[package]]
-name = "gear-core-backend-codegen"
-version = "1.0.2"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.31",
-]
-
[[package]]
name = "gear-core-errors"
version = "1.0.2"
diff --git a/Cargo.toml b/Cargo.toml
index 7a6f1da38bc..77dda8cb2c1 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 dd241427d31..00000000000
--- a/core-backend/codegen/src/host.rs
+++ /dev/null
@@ -1,265 +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, ItemFn, Meta, Pat, PatType, Path, Signature, Token,
-};
-
-/// 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::>();
-
- 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 output = self.item.sig.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()
-}
diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs
index 625eec6e8b0..1f0b4fdf24e 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,
};
@@ -51,110 +50,21 @@ use gear_sandbox::{
default_executor::{
EnvironmentDefinitionBuilder, Instance, Memory as DefaultExecutorMemory, Store,
},
- AsContextExt, HostError, HostFuncType, IntoValue, ReturnValue, SandboxEnvironmentBuilder,
- SandboxInstance, SandboxMemory, SandboxStore, Value,
+ AsContextExt, 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,
};
-#[derive(Clone, Copy)]
-struct SandboxValue(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_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,
- })
- }
- }
-}
-
-#[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) };
+// 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)
+ };
}
fn store_host_state_mut(
@@ -242,11 +152,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,62 +184,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(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 3b064431d60..7bfe666ce92 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};
@@ -36,55 +37,303 @@ 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_env::HostError;
+use gear_sandbox::{default_executor::Caller, 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,
};
-#[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)
- }
+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)
}
- };
- ($val:expr, $($rest:expr),+) => {
- {
- let mut s = syscall_args_trace!($val);
- s.push_str(&syscall_args_trace!($($rest),+));
- s
+ }
+}
+
+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);
+
+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: 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)))
+ }
+}
+
+pub(crate) trait SysCallContext: Sized {
+ fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError>;
}
-macro_rules! syscall_trace {
- ($name:expr, $($args:expr),+) => {
+impl SysCallContext for () {
+ fn from_args(args: &[Value]) -> Result<(Self, &[Value]), HostError> {
+ Ok(((), args))
+ }
+}
+
+pub(crate) trait SysCall {
+ type Context: SysCallContext;
+
+ fn execute(
+ self,
+ caller: &mut CallerWrap,
+ ctx: Self::Context,
+ ) -> Result<(Gas, T), HostError>;
+}
+
+/// 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 Builder
+where
+ Builder: FnOnce() -> Call,
+ Call: SysCall,
+{
+ fn build(self, args: &[Value]) -> Result {
+ let _: [Value; 0] = args.try_into().map_err(|_| HostError)?;
+ Ok((self)())
+ }
+}
+
+impl SysCallBuilder for Builder
+where
+ Builder: for<'a> FnOnce(&'a [Value]) -> Call,
+ Call: SysCall,
+{
+ fn build(self, args: &[Value]) -> Result {
+ Ok((self)(args))
+ }
+}
+
+// implement [`SysCallBuilder`] for functions with different amount of arguments
+macro_rules! impl_syscall_builder {
+ ($($generic:ident),+) => {
+ #[allow(non_snake_case)]
+ impl SysCallBuilder
+ for Builder
+ where
+ Builder: FnOnce($($generic),+) -> Call,
+ Call: SysCall,
+ $( $generic: TryFrom,)+
{
- ::log::trace!(target: "syscalls", "{}{}", $name, syscall_args_trace!($($args),+));
+ 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 = SysCallValue($generic).try_into()?;
+ )+
+ Ok((self)($($generic),+))
+ }
}
};
- ($name:expr) => {
- {
- ::log::trace!(target: "syscalls", "{}", $name);
+ (@count $generic:ident) => { 1 };
+ (@count $generic:ident, $($generics:ident),+) => { 1 + impl_syscall_builder!(@count $($generics),+) };
+}
+
+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);
+
+/// "raw" sys-call without any argument parsing or without calling [`CallerWrap`] helper methods
+struct RawSysCall(F);
+
+impl RawSysCall {
+ fn new(f: F) -> Self {
+ Self(f)
+ }
+}
+
+impl SysCall for RawSysCall
+where
+ F: FnOnce(&mut CallerWrap) -> Result<(Gas, T), HostError>,
+ Ext: BackendExternalities + 'static,
+{
+ type Context = ();
+
+ fn execute(
+ self,
+ caller: &mut CallerWrap,
+ (): Self::Context,
+ ) -> Result<(Gas, T), HostError> {
+ (self.0)(caller)
+ }
+}
+
+/// Fallible sys-call context that parses `gas` and `err_ptr` arguments.
+struct FallibleSysCallContext {
+ 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: 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))
+ }
+}
+
+/// Fallible sys-call that calls [`CallerWrap::run_fallible`] underneath.
+struct FallibleSysCall {
+ costs: RuntimeCosts,
+ error: PhantomData,
+ f: F,
+}
+
+impl FallibleSysCall<(), F> {
+ fn new(costs: RuntimeCosts, f: F) -> FallibleSysCall {
+ FallibleSysCall {
+ costs,
+ error: PhantomData,
+ f,
}
}
}
-const PTR_SPECIAL: u32 = u32::MAX;
+impl SysCall for FallibleSysCall
+where
+ F: FnOnce(&mut CallerWrap) -> Result,
+ E: From>,
+ Ext: BackendExternalities + 'static,
+{
+ type Context = FallibleSysCallContext;
+
+ fn execute(
+ self,
+ caller: &mut CallerWrap,
+ context: Self::Context,
+ ) -> Result<(Gas, ()), HostError> {
+ let Self {
+ costs,
+ error: _error,
+ f,
+ } = self;
+ let FallibleSysCallContext { gas, res_ptr } = context;
+ caller.run_fallible::(gas, res_ptr, costs, f)
+ }
+}
+
+/// Infallible sys-call context that parses `gas` argument.
+pub struct InfallibleSysCallContext {
+ 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: Gas = SysCallValue(*gas).try_into()?;
+ Ok((Self { gas }, args))
+ }
+}
+
+/// Infallible sys-call that calls [`CallerWrap::run_any`] underneath
+struct InfallibleSysCall {
+ costs: RuntimeCosts,
+ f: F,
+}
+
+impl InfallibleSysCall {
+ fn new(costs: RuntimeCosts, f: F) -> Self {
+ Self { costs, 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<(Gas, T), HostError> {
+ let Self { costs, f } = self;
+ let InfallibleSysCallContext { gas } = ctx;
+ caller.run_any::(gas, costs, f)
+ }
+}
pub(crate) struct FuncsHandler {
_phantom: PhantomData,
@@ -97,6 +346,32 @@ where
RunFallibleError: From,
Ext::AllocError: BackendAllocSyscallError,
{
+ pub fn execute(
+ caller: &mut Caller>,
+ args: &[Value],
+ builder: Builder,
+ ) -> Result
+ where
+ Builder: SysCallBuilder,
+ Args: ?Sized,
+ Call: SysCall,
+ Res: Into,
+ {
+ crate::log::trace_syscall::(args);
+
+ let mut caller = CallerWrap::prepare(caller);
+
+ 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();
+
+ Ok(WasmReturnValue {
+ gas: gas as i64,
+ inner: value.0,
+ })
+ }
+
/// !!! Usage warning: make sure to do it before any other read/write,
/// because it may contain registered read.
fn register_and_read_value(
@@ -121,17 +396,14 @@ where
.map_err(RunFallibleError::FallibleExt)
}
- // TODO #3037
- #[allow(clippy::too_many_arguments)]
- #[host(fallible, wgas, cost = RuntimeCosts::Send(len))]
- pub fn send(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ fn send_inner(
+ ctx: &mut CallerWrap,
pid_value_ptr: u32,
payload_ptr: u32,
len: u32,
+ gas_limit: Option,
delay: u32,
- ) -> Result<(u64, ()), HostError> {
+ ) -> 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 {
@@ -141,18 +413,44 @@ where
let payload = Self::read_message_payload(ctx, read_payload)?;
ctx.ext_mut()
- .send(HandlePacket::new(destination.into(), payload, value), delay)
+ .send(
+ HandlePacket::maybe_with_gas(destination.into(), payload, gas_limit, value),
+ delay,
+ )
.map_err(Into::into)
}
- #[host(fallible, wgas, cost = RuntimeCosts::SendCommit)]
- pub fn send_commit(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ pub fn send(pid_value_ptr: u32, payload_ptr: u32, len: u32, delay: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::Send(len),
+ move |ctx: &mut CallerWrap| {
+ Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, None, delay)
+ },
+ )
+ }
+
+ pub fn send_wgas(
+ pid_value_ptr: u32,
+ payload_ptr: u32,
+ len: u32,
+ gas_limit: u64,
+ delay: u32,
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendWGas(len),
+ move |ctx: &mut CallerWrap| {
+ Self::send_inner(ctx, pid_value_ptr, payload_ptr, len, Some(gas_limit), delay)
+ },
+ )
+ }
+
+ fn send_commit_inner(
+ ctx: &mut CallerWrap,
handle: u32,
pid_value_ptr: u32,
+ gas_limit: Option,
delay: u32,
- ) -> Result<(u64, ()), HostError> {
+ ) -> Result {
let read_pid_value = ctx.manager.register_read_as(pid_value_ptr);
let HashWithValue {
hash: destination,
@@ -162,670 +460,748 @@ where
ctx.ext_mut()
.send_commit(
handle,
- HandlePacket::new(destination.into(), Default::default(), value),
+ HandlePacket::maybe_with_gas(
+ destination.into(),
+ Default::default(),
+ gas_limit,
+ value,
+ ),
delay,
)
.map_err(Into::into)
}
- #[host(fallible, cost = RuntimeCosts::SendInit, err = ErrorWithHandle)]
- pub fn send_init(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> {
- ctx.ext_mut().send_init().map_err(Into::into)
+ pub fn send_commit(handle: u32, pid_value_ptr: u32, delay: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendCommit,
+ move |ctx: &mut CallerWrap| {
+ Self::send_commit_inner(ctx, handle, pid_value_ptr, None, delay)
+ },
+ )
}
- #[host(fallible, cost = RuntimeCosts::SendPush(len), err = ErrorBytes)]
- pub fn send_push(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ pub fn send_commit_wgas(
handle: u32,
- payload_ptr: u32,
- len: u32,
- ) -> Result<(u64, ()), HostError> {
- let read_payload = ctx.manager.register_read(payload_ptr, len);
- let payload = ctx.read(read_payload)?;
+ pid_value_ptr: u32,
+ gas_limit: u64,
+ delay: u32,
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendCommitWGas,
+ move |ctx: &mut CallerWrap| {
+ Self::send_commit_inner(ctx, handle, pid_value_ptr, Some(gas_limit), delay)
+ },
+ )
+ }
- ctx.ext_mut()
- .send_push(handle, &payload)
- .map_err(Into::into)
+ pub fn send_init() -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendInit,
+ 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),
+ 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)
+ },
+ )
}
- #[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> {
- 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)
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReservationSend(len),
+ 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)
+ },
+ )
}
- #[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> {
- 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)
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReservationSendCommit,
+ 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)
+ },
+ )
}
- #[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> {
- 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 {
+ 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)
+ })
}
- #[host(cost = RuntimeCosts::Size)]
- pub fn size(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- size_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- let size = ctx.ext_mut().size()? as u32;
+ pub fn size(size_ptr: u32) -> impl SysCall {
+ 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);
- 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>,
- gas: u64,
- inheritor_id_ptr: u32,
- ) -> Result<(u64, ()), 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 {
+ 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())
+ })
}
- #[host(fallible, cost = RuntimeCosts::ReplyCode, err = ErrorWithReplyCode)]
- pub fn reply_code(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .reply_code()
- .map(ReplyCode::to_bytes)
- .map_err(Into::into)
+ pub fn reply_code() -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyCode,
+ 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>,
- gas: u64,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .signal_code()
- .map(SignalCode::to_u32)
- .map_err(Into::into)
+ pub fn signal_code() -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SignalCode,
+ 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>,
- gas: u64,
- pages: u32,
- ) -> Result<(u64, u32), HostError> {
- 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 alloc(pages: u32) -> impl SysCall {
+ InfallibleSysCall::new(
+ 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)
+ },
+ )
}
- #[host(cost = RuntimeCosts::Free)]
- pub fn free(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- page_no: u32,
- ) -> Result<(u64, i32), HostError> {
- 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)?;
-
- match &res {
- Ok(()) => {
- log::trace!("Free {page:?}");
- }
- Err(err) => {
- log::trace!("Free failed: {err}");
- }
- };
-
- Ok(res.is_err() as i32)
+ pub fn free(page_no: u32) -> impl SysCall {
+ InfallibleSysCall::new(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)?;
+
+ match &res {
+ Ok(()) => {
+ log::trace!("Free {page:?}");
+ }
+ Err(err) => {
+ log::trace!("Free failed: {err}");
+ }
+ };
+
+ Ok(res.is_err() as i32)
+ })
}
- #[host(cost = RuntimeCosts::BlockHeight)]
- pub fn block_height(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- height_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ pub fn block_height(height_ptr: u32) -> impl SysCall {
+ InfallibleSysCall::new(
+ 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)
+ },
+ )
}
- #[host(cost = RuntimeCosts::BlockTimestamp)]
- pub fn block_timestamp(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- timestamp_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ pub fn block_timestamp(timestamp_ptr: u32) -> impl SysCall {
+ InfallibleSysCall::new(
+ 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)
+ },
+ )
}
- #[host(cost = RuntimeCosts::Random)]
- pub fn random(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- subject_ptr: u32,
- bn_random_ptr: u32,
- ) -> Result<(u64, ()), 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 {
+ 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);
- 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,
+ fn reply_inner(
+ ctx: &mut CallerWrap,
payload_ptr: u32,
len: u32,
+ gas_limit: Option,
value_ptr: u32,
- ) -> Result<(u64, ()), 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))
+ .reply(ReplyPacket::maybe_with_gas(payload, gas_limit, value))
.map_err(Into::into)
}
- #[host(fallible, wgas, cost = RuntimeCosts::ReplyCommit)]
- pub fn reply_commit(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ pub fn reply(payload_ptr: u32, len: u32, value_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::Reply(len),
+ move |ctx: &mut CallerWrap| {
+ Self::reply_inner(ctx, payload_ptr, len, None, value_ptr)
+ },
+ )
+ }
+
+ pub fn reply_wgas(
+ payload_ptr: u32,
+ len: u32,
+ gas_limit: u64,
+ value_ptr: u32,
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyWGas(len),
+ move |ctx: &mut CallerWrap| {
+ Self::reply_inner(ctx, payload_ptr, len, Some(gas_limit), value_ptr)
+ },
+ )
+ }
+
+ fn reply_commit_inner(
+ ctx: &mut CallerWrap,
+ gas_limit: Option,
value_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
+ ) -> Result {
let value = Self::register_and_read_value(ctx, value_ptr)?;
ctx.ext_mut()
- .reply_commit(ReplyPacket::new(Default::default(), value))
+ .reply_commit(ReplyPacket::maybe_with_gas(
+ Default::default(),
+ gas_limit,
+ value,
+ ))
.map_err(Into::into)
}
- #[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> {
- 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)?;
+ pub fn reply_commit(value_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyCommit,
+ move |ctx: &mut CallerWrap| Self::reply_commit_inner(ctx, None, value_ptr),
+ )
+ }
- ctx.ext_mut()
- .reservation_reply(reservation_id.into(), ReplyPacket::new(payload, value))
- .map_err(Into::into)
+ pub fn reply_commit_wgas(gas_limit: u64, value_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyCommitWGas,
+ move |ctx: &mut CallerWrap| {
+ Self::reply_commit_inner(ctx, Some(gas_limit), value_ptr)
+ },
+ )
}
- #[host(fallible, cost = RuntimeCosts::ReservationReplyCommit)]
- pub fn reservation_reply_commit(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- rid_value_ptr: u32,
- ) -> Result<(u64, ()), 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 reservation_reply(rid_value_ptr: u32, payload_ptr: u32, len: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReservationReply(len),
+ 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)
+ },
+ )
+ }
- ctx.ext_mut()
- .reservation_reply_commit(
- reservation_id.into(),
- ReplyPacket::new(Default::default(), value),
- )
- .map_err(Into::into)
+ pub fn reservation_reply_commit(rid_value_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReservationReplyCommit,
+ 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::ReplyTo)]
- pub fn reply_to(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> {
- ctx.ext_mut().reply_to().map_err(Into::into)
+ pub fn reply_to() -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyTo,
+ move |ctx: &mut CallerWrap| 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> {
- ctx.ext_mut().signal_from().map_err(Into::into)
+ pub fn signal_from() -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SignalFrom,
+ move |ctx: &mut CallerWrap| 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> {
- let read_payload = ctx.manager.register_read(payload_ptr, len);
- let payload = ctx.read(read_payload)?;
+ pub fn reply_push(payload_ptr: u32, len: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyPush(len),
+ 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)
+ ctx.ext_mut().reply_push(&payload).map_err(Into::into)
+ },
+ )
}
- #[host(fallible, wgas, cost = RuntimeCosts::ReplyInput)]
- pub fn reply_input(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ fn reply_input_inner(
+ ctx: &mut CallerWrap,
offset: u32,
len: u32,
+ gas_limit: Option,
value_ptr: u32,
- ) -> Result<(u64, ()), 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)?;
+
+ ctx.ext_mut()
+ .reply_commit(ReplyPacket::maybe_with_gas(
+ Default::default(),
+ gas_limit,
+ value,
+ ))
+ .map_err(Into::into)
+ }
- f().map_err(Into::into)
+ pub fn reply_input(offset: u32, len: u32, value_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyInput,
+ move |ctx: &mut CallerWrap| {
+ Self::reply_input_inner(ctx, offset, len, None, value_ptr)
+ },
+ )
}
- #[host(fallible, cost = RuntimeCosts::ReplyPushInput, err = ErrorBytes)]
- pub fn reply_push_input(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ pub fn reply_input_wgas(
offset: u32,
len: u32,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .reply_push_input(offset, len)
- .map_err(Into::into)
+ gas_limit: u64,
+ value_ptr: u32,
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyInputWGas,
+ 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>,
- gas: u64,
+ pub fn reply_push_input(offset: u32, len: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyPushInput,
+ 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<(u64, ()), 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(
+ let handle = ctx.ext_mut().send_init()?;
+ // Charge for `len` inside `send_push_input`
+ ctx.ext_mut().send_push_input(handle, offset, len)?;
+
+ ctx.ext_mut()
+ .send_commit(
handle,
- HandlePacket::new(destination.into(), Default::default(), value),
+ HandlePacket::maybe_with_gas(
+ destination.into(),
+ Default::default(),
+ gas_limit,
+ value,
+ ),
delay,
)
- };
+ .map_err(Into::into)
+ }
- f().map_err(Into::into)
+ pub fn send_input(pid_value_ptr: u32, offset: u32, len: u32, delay: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendInput,
+ 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>,
- gas: u64,
- handle: u32,
+ pub fn send_input_wgas(
+ pid_value_ptr: u32,
offset: u32,
len: u32,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .send_push_input(handle, offset, len)
- .map_err(Into::into)
+ gas_limit: u64,
+ delay: u32,
+ ) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendInputWGas,
+ 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>,
- gas: u64,
- data_ptr: u32,
- data_len: u32,
- ) -> Result<(u64, ()), 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 {
+ FallibleSysCall::new::(
+ RuntimeCosts::SendPushInput,
+ 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 {
+ InfallibleSysCall::new(
+ 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>,
- gas: u64,
- data_ptr: u32,
- data_len: u32,
- ) -> Result<(u64, ()), 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 {
+ 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();
- 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>, gas: u64) -> Result<(u64, ()), HostError> {
- Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into())
+ pub fn oom_panic() -> impl SysCall {
+ InfallibleSysCall::new(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: u64,
- gas_value: u64,
- duration: u32,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .reserve_gas(gas_value, duration)
- .map_err(Into::into)
+ pub fn reserve_gas(gas_value: u64, duration: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReserveGas,
+ 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>,
- gas: u64,
- message_id_ptr: u32,
- gas_value: u64,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ pub fn reply_deposit(message_id_ptr: u32, gas_value: u64) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::ReplyDeposit,
+ 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)
+ },
+ )
}
- #[host(fallible, cost = RuntimeCosts::UnreserveGas, err = ErrorWithGas)]
- pub fn unreserve_gas(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- reservation_id_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ pub fn unreserve_gas(reservation_id_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::UnreserveGas,
+ 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)
+ },
+ )
}
- #[host(fallible, cost = RuntimeCosts::SystemReserveGas, err = ErrorBytes)]
- pub fn system_reserve_gas(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- gas_value: u64,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut()
- .system_reserve_gas(gas_value)
- .map_err(Into::into)
+ pub fn system_reserve_gas(gas_value: u64) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::SystemReserveGas,
+ 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: u64,
- gas_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ 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()?;
+
+ 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::MsgId)]
- pub fn message_id(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
- message_id_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- let message_id = ctx.ext_mut().message_id()?;
+ pub fn message_id(message_id_ptr: u32) -> impl SysCall {
+ 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);
- 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>,
- gas: u64,
- program_id_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- let program_id = ctx.ext_mut().program_id()?;
+ pub fn program_id(program_id_ptr: u32) -> impl SysCall {
+ 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);
- 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>,
- gas: u64,
- rent_pid_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)?;
-
- ctx.ext_mut()
- .pay_program_rent(program_id.into(), rent)
- .map_err(Into::into)
+ pub fn pay_program_rent(rent_pid_ptr: u32) -> impl SysCall {
+ FallibleSysCall::new::(
+ RuntimeCosts::PayProgramRent,
+ 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)?;
+
+ 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>,
- gas: u64,
- source_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- let source = ctx.ext_mut().source()?;
+ pub fn source(source_ptr: u32) -> impl SysCall {
+ InfallibleSysCall::new(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>,
- gas: u64,
- value_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- let value = ctx.ext_mut().value()?;
+ pub fn value(value_ptr: u32) -> impl SysCall {
+ InfallibleSysCall::new(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>,
- gas: u64,
- value_ptr: u32,
- ) -> Result<(u64, ()), HostError> {
- 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)
+ 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()?;
+
+ 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>, gas: u64) -> Result<(u64, ()), HostError> {
- Err(ActorTerminationReason::Leave.into())
+ pub fn leave() -> impl SysCall {
+ InfallibleSysCall::new(RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| {
+ Err(ActorTerminationReason::Leave.into())
+ })
}
- #[host(cost = RuntimeCosts::Wait)]
- pub fn wait(ctx: &mut CallerWrap<'_, '_, Ext>, gas: u64) -> Result<(u64, ()), HostError> {
- ctx.ext_mut().wait()?;
- Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into())
+ pub fn wait() -> impl SysCall {
+ InfallibleSysCall::new(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>,
- gas: u64,
- duration: u32,
- ) -> Result<(u64, ()), HostError> {
- ctx.ext_mut().wait_for(duration)?;
- Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into())
+ pub fn wait_for(duration: u32) -> impl SysCall {
+ InfallibleSysCall::new(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>,
- gas: u64,
- duration: u32,
- ) -> Result<(u64, ()), 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 {
+ InfallibleSysCall::new(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>,
- gas: u64,
- message_id_ptr: u32,
- delay: u32,
- ) -> Result<(u64, ()), 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 {
+ 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)]
- #[host(fallible, wgas, cost = RuntimeCosts::CreateProgram(payload_len, salt_len), err = ErrorWithTwoHashes)]
- pub fn create_program(
- ctx: &mut CallerWrap<'_, '_, Ext>,
- gas: u64,
+ 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<(u64, ()), 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);
@@ -840,39 +1216,92 @@ where
ctx.ext_mut()
.create_program(
- InitPacket::new(code_id.into(), salt, payload, Some(message_id), value),
+ InitPacket::new_from_program(
+ code_id.into(),
+ salt,
+ payload,
+ message_id,
+ gas_limit,
+ value,
+ ),
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 {
+ FallibleSysCall::new::(
+ RuntimeCosts::CreateProgram(payload_len, salt_len),
+ 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 {
+ FallibleSysCall::new::(
+ RuntimeCosts::CreateProgramWGas(payload_len, salt_len),
+ 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 {
+ InfallibleSysCall::new(RuntimeCosts::Null, |_: &mut CallerWrap