Skip to content

Commit

Permalink
feat(rpc-call): Implement new call to send message and collect reply …
Browse files Browse the repository at this point in the history
…from on-chain state (#3790)
  • Loading branch information
breathx authored Mar 11, 2024
1 parent 52e538c commit 9455255
Show file tree
Hide file tree
Showing 12 changed files with 625 additions and 234 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions core-errors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ repository.workspace = true

[dependencies]
scale-info = { workspace = true, features = ["derive"], optional = true }
serde = { workspace = true, features = ["std", "derive"], optional = true }
derive_more.workspace = true
enum-iterator.workspace = true

[features]
codec = ["scale-info"]
serde = ["dep:serde"]
6 changes: 6 additions & 0 deletions core-errors/src/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use scale_info::{
derive_more::From,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Enum representing reply code with reason of its creation.
pub enum ReplyCode {
/// Success reply.
Expand Down Expand Up @@ -119,6 +120,7 @@ impl ReplyCode {
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, derive_more::Display,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Reason of success reply creation.
pub enum SuccessReplyReason {
/// Success reply was created by system automatically.
Expand Down Expand Up @@ -165,6 +167,7 @@ impl SuccessReplyReason {
derive_more::From,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Reason of error reply creation.
///
/// NOTE: Adding new variants to this enum you must also update `ErrorReplyReason::to_bytes` and
Expand Down Expand Up @@ -246,6 +249,7 @@ impl ErrorReplyReason {
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, derive_more::Display,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Simplified error occurred during execution.
pub enum SimpleExecutionError {
/// Message ran out of gas while executing.
Expand Down Expand Up @@ -302,6 +306,7 @@ impl SimpleExecutionError {
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, derive_more::Display,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Simplified error occurred during program creation.
pub enum SimpleProgramCreationError {
/// Given code id for program creation doesn't exist.
Expand Down Expand Up @@ -349,6 +354,7 @@ impl SimpleProgramCreationError {
derive_more::From,
)]
#[cfg_attr(feature = "codec", derive(Encode, Decode, TypeInfo, Sequence), codec(crate = scale), allow(clippy::unnecessary_cast))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Enum representing signal code and reason of its creation.
///
/// # Testing
Expand Down
6 changes: 5 additions & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ rand = { workspace = true, features = ["std", "std_rng"] }
[features]
default = []
strict = []
std = ["serde/std", "wasmparser/std"]
std = [
"serde/std",
"wasmparser/std",
"gear-core-errors/serde",
]
2 changes: 1 addition & 1 deletion core/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ impl From<(i64, i64)> for GasLeft {

/// The struct contains results of gas calculation required to process
/// a message.
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[derive(Clone, Debug, Decode, Default, Encode, PartialEq, Eq, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct GasInfo {
/// Represents minimum gas limit required for execution.
Expand Down
24 changes: 18 additions & 6 deletions core/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@

//! Message processing module.
use alloc::{collections::BTreeSet, string::String};
use scale_info::{
scale::{Decode, Encode},
TypeInfo,
};

mod common;
mod context;
mod handle;
Expand All @@ -47,8 +41,14 @@ pub use stored::{StoredDelayedDispatch, StoredDispatch, StoredMessage};
pub use user::{UserMessage, UserStoredMessage};

use super::buffer::LimitedVec;
use alloc::{collections::BTreeSet, string::String, vec::Vec};
use core::fmt::Display;
use gear_core_errors::ReplyCode;
use gear_wasm_instrument::syscalls::SyscallName;
use scale_info::{
scale::{Decode, Encode},
TypeInfo,
};

/// Max payload size which one message can have (8 MiB).
pub const MAX_PAYLOAD_SIZE: usize = 8 * 1024 * 1024;
Expand Down Expand Up @@ -230,3 +230,15 @@ pub trait Packet {
/// Packet value.
fn value(&self) -> Value;
}

/// The struct contains results of read only send message RPC call.
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct ReplyInfo {
/// Payload of the reply.
pub payload: Vec<u8>,
/// Value sent with reply.
pub value: u128,
/// Reply code of the reply.
pub code: ReplyCode,
}
5 changes: 4 additions & 1 deletion pallets/gear/rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@
#![doc(html_logo_url = "https://docs.gear.rs/logo.svg")]
#![doc(html_favicon_url = "https://gear-tech.io/favicons/favicon.ico")]

pub use pallet_gear::{manager::HandleKind, GasInfo};
pub use pallet_gear::{manager::HandleKind, GasInfo, ReplyInfo};
use sp_core::H256;
use sp_runtime::traits::Block as BlockT;
use sp_std::vec::Vec;

sp_api::decl_runtime_apis! {
#[api_version(2)]
pub trait GearApi {
#[allow(clippy::too_many_arguments)]
fn calculate_reply_for_handle(origin: H256, destination: H256, payload: Vec<u8>, gas_limit: u64, value: u128, allowance_multiplier: u64) -> Result<ReplyInfo, Vec<u8>>;

#[allow(clippy::too_many_arguments)]
fn calculate_gas_info(source: H256, kind: HandleKind, payload: Vec<u8>, value: u128, allow_other_panics: bool, initial_gas: Option<u64>, allowance_multiplier: Option<u64>) -> Result<GasInfo, Vec<u8>>;

Expand Down
45 changes: 40 additions & 5 deletions pallets/gear/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use jsonrpsee::{
types::error::{CallError, ErrorObject},
};
pub use pallet_gear_rpc_runtime_api::GearApi as GearRuntimeApi;
use pallet_gear_rpc_runtime_api::{GasInfo, HandleKind};
use pallet_gear_rpc_runtime_api::{GasInfo, HandleKind, ReplyInfo};
use sp_api::{ApiError, ApiExt, ApiRef, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_core::{Bytes, H256};
Expand All @@ -50,7 +50,18 @@ fn runtime_error_into_rpc_error(err: impl std::fmt::Display) -> JsonRpseeError {

#[rpc(server)]
pub trait GearApi<BlockHash, ResponseType> {
#[method(name = "gear_calculateInitCreateGas")]
#[method(name = "gear_calculateReplyForHandle")]
fn calculate_reply_for_handle(
&self,
origin: H256,
destination: H256,
payload: Bytes,
gas_limit: u64,
value: u128,
at: Option<BlockHash>,
) -> RpcResult<ReplyInfo>;

#[method(name = "gear_calculateInitCreateGas", aliases = ["gear_calculateGasForCreate"])]
fn get_init_create_gas_spent(
&self,
source: H256,
Expand All @@ -61,7 +72,7 @@ pub trait GearApi<BlockHash, ResponseType> {
at: Option<BlockHash>,
) -> RpcResult<GasInfo>;

#[method(name = "gear_calculateInitUploadGas")]
#[method(name = "gear_calculateInitUploadGas", aliases = ["gear_calculateGasForUpload"])]
fn get_init_upload_gas_spent(
&self,
source: H256,
Expand All @@ -72,7 +83,7 @@ pub trait GearApi<BlockHash, ResponseType> {
at: Option<BlockHash>,
) -> RpcResult<GasInfo>;

#[method(name = "gear_calculateHandleGas")]
#[method(name = "gear_calculateHandleGas", aliases = ["gear_calculateGasForHandle"])]
fn get_handle_gas_spent(
&self,
source: H256,
Expand All @@ -83,7 +94,7 @@ pub trait GearApi<BlockHash, ResponseType> {
at: Option<BlockHash>,
) -> RpcResult<GasInfo>;

#[method(name = "gear_calculateReplyGas")]
#[method(name = "gear_calculateReplyGas", aliases = ["gear_calculateGasForReply"])]
fn get_reply_gas_spent(
&self,
source: H256,
Expand Down Expand Up @@ -257,6 +268,30 @@ where
C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
C::Api: GearRuntimeApi<Block>,
{
fn calculate_reply_for_handle(
&self,
origin: H256,
destination: H256,
payload: Bytes,
gas_limit: u64,
value: u128,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<ReplyInfo> {
let at_hash = at.unwrap_or_else(|| self.client.info().best_hash);

self.run_with_api_copy(|api| {
api.calculate_reply_for_handle(
at_hash,
origin,
destination,
payload.to_vec(),
gas_limit,
value,
self.allowance_multiplier,
)
})
}

fn get_init_create_gas_spent(
&self,
source: H256,
Expand Down
89 changes: 62 additions & 27 deletions pallets/gear/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ pub use crate::{
pallet::*,
schedule::{HostFnWeights, InstructionWeights, Limits, MemoryWeights, Schedule},
};
pub use gear_core::gas::GasInfo;
pub use gear_core::{gas::GasInfo, message::ReplyInfo};
pub use weights::WeightInfo;

use alloc::{format, string::String};
use alloc::{
format,
string::{String, ToString},
};
use common::{
self, event::*, gas_provider::GasNodeId, paused_program_storage::SessionId, scheduler::*,
storage::*, BlockLimiter, CodeMetadata, CodeStorage, GasProvider, GasTree, Origin,
Expand Down Expand Up @@ -100,6 +103,7 @@ pub(crate) type BalanceOf<T> = <CurrencyOf<T> as Currency<AccountIdOf<T>>>::Bala
pub(crate) type SentOf<T> = <<T as Config>::Messenger as Messenger>::Sent;
pub(crate) type DbWeightOf<T> = <T as frame_system::Config>::DbWeight;
pub(crate) type DequeuedOf<T> = <<T as Config>::Messenger as Messenger>::Dequeued;
pub(crate) type PalletInfoOf<T> = <T as frame_system::Config>::PalletInfo;
pub(crate) type QueueProcessingOf<T> = <<T as Config>::Messenger as Messenger>::QueueProcessing;
pub(crate) type QueueOf<T> = <<T as Config>::Messenger as Messenger>::Queue;
pub(crate) type MailboxOf<T> = <<T as Config>::Messenger as Messenger>::Mailbox;
Expand Down Expand Up @@ -722,6 +726,7 @@ pub mod pallet {
false,
gas_allowance,
)
.map_err(|e| e.into_bytes())
}

#[cfg(test)]
Expand Down Expand Up @@ -763,42 +768,72 @@ pub mod pallet {

let GasInfo {
min_limit, waited, ..
} = Self::run_with_ext_copy(|| {
calc_gas(BlockGasLimitOf::<T>::get()).map_err(|e| {
String::from_utf8(e)
.unwrap_or_else(|_| String::from("Failed to parse error to string"))
})
})?;
} = Self::run_with_ext_copy(|| calc_gas(BlockGasLimitOf::<T>::get()))?;

log::debug!("\n--- SECOND TRY ---\n");

let res = Self::run_with_ext_copy(|| {
calc_gas(min_limit)
.map(
|GasInfo {
reserved,
burned,
may_be_returned,
..
}| GasInfo {
min_limit,
reserved,
burned,
may_be_returned,
waited,
},
)
.map_err(|e| {
String::from_utf8(e)
.unwrap_or_else(|_| String::from("Failed to parse error to string"))
})
calc_gas(min_limit).map(
|GasInfo {
reserved,
burned,
may_be_returned,
..
}| GasInfo {
min_limit,
reserved,
burned,
may_be_returned,
waited,
},
)
});

log::debug!("\n==============================\n");

res
}

#[cfg(not(test))]
pub fn calculate_reply_for_handle(
origin: H256,
destination: H256,
payload: Vec<u8>,
gas_limit: u64,
value: u128,
allowance_multiplier: u64,
) -> Result<ReplyInfo, Vec<u8>> {
Self::calculate_reply_for_handle_impl(
origin,
destination.cast(),
payload,
gas_limit,
value,
allowance_multiplier,
)
.map_err(|v| v.into_bytes())
}

#[cfg(test)]
pub fn calculate_reply_for_handle(
origin: AccountIdOf<T>,
destination: ProgramId,
payload: Vec<u8>,
gas_limit: u64,
value: u128,
) -> Result<ReplyInfo, String> {
Self::run_with_ext_copy(|| {
Self::calculate_reply_for_handle_impl(
origin.cast(),
destination,
payload,
gas_limit,
value,
crate::runtime_api::RUNTIME_API_BLOCK_LIMITS_COUNT,
)
})
}

pub fn run_with_ext_copy<R, F: FnOnce() -> R>(f: F) -> R {
sp_externalities::with_externalities(|ext| {
ext.storage_start_transaction();
Expand Down
Loading

0 comments on commit 9455255

Please sign in to comment.