#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate gear_common_codegen;
pub mod event;
pub mod scheduler;
pub mod storage;
#[cfg(feature = "std")]
pub mod memory_dump;
pub mod code_storage;
pub use code_storage::{CodeStorage, Error as CodeStorageError};
pub mod program_storage;
pub use program_storage::{Error as ProgramStorageError, ProgramStorage};
pub mod paused_program_storage;
pub use paused_program_storage::PausedProgramStorage;
pub mod gas_provider;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
use core::fmt;
use frame_support::{
codec::{self, Decode, Encode},
dispatch::DispatchError,
scale_info::{self, TypeInfo},
sp_runtime::{
self,
generic::{CheckedExtrinsic, UncheckedExtrinsic},
traits::{Dispatchable, SignedExtension},
},
traits::Get,
weights::{ConstantMultiplier, Weight, WeightToFee},
};
use gear_core::{
ids::{CodeId, MessageId, ProgramId},
memory::{GearPage, PageBuf, WasmPage},
message::DispatchKind,
reservation::GasReservationMap,
};
use primitive_types::H256;
use sp_arithmetic::traits::{BaseArithmetic, Saturating, Unsigned};
use sp_core::crypto::UncheckedFrom;
use sp_std::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
prelude::*,
};
use storage::ValueStorage;
extern crate alloc;
pub use gas_provider::{
LockId, LockableTree, Provider as GasProvider, ReservableTree, Tree as GasTree,
};
pub trait Origin: Sized {
fn into_origin(self) -> H256;
fn from_origin(val: H256) -> Self;
}
impl Origin for u64 {
fn into_origin(self) -> H256 {
let mut result = H256::zero();
result[0..8].copy_from_slice(&self.to_le_bytes());
result
}
fn from_origin(v: H256) -> Self {
let mut val = [0u8; 8];
val.copy_from_slice(&v[0..8]);
Self::from_le_bytes(val)
}
}
impl Origin for sp_runtime::AccountId32 {
fn into_origin(self) -> H256 {
H256::from(self.as_ref())
}
fn from_origin(v: H256) -> Self {
sp_runtime::AccountId32::unchecked_from(v)
}
}
impl Origin for H256 {
fn into_origin(self) -> H256 {
self
}
fn from_origin(val: H256) -> Self {
val
}
}
impl Origin for MessageId {
fn into_origin(self) -> H256 {
H256(self.into())
}
fn from_origin(val: H256) -> Self {
val.to_fixed_bytes().into()
}
}
impl Origin for ProgramId {
fn into_origin(self) -> H256 {
H256(self.into())
}
fn from_origin(val: H256) -> Self {
val.to_fixed_bytes().into()
}
}
impl Origin for CodeId {
fn into_origin(self) -> H256 {
H256(self.into())
}
fn from_origin(val: H256) -> Self {
val.to_fixed_bytes().into()
}
}
pub trait GasPrice {
type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
type GasToBalanceMultiplier: Get<Self::Balance>;
fn gas_price(gas: u64) -> Self::Balance {
ConstantMultiplier::<Self::Balance, Self::GasToBalanceMultiplier>::weight_to_fee(
&Weight::from_parts(gas, 0),
)
}
}
pub trait QueueRunner {
type Gas;
fn run_queue(initial_gas: Self::Gas) -> Self::Gas;
}
pub trait PaymentProvider<AccountId> {
type Balance;
fn withhold_reserved(
source: H256,
dest: &AccountId,
amount: Self::Balance,
) -> Result<(), DispatchError>;
}
pub trait BlockLimiter {
type BlockGasLimit: Get<Self::Balance>;
type Balance;
type GasAllowance: storage::Limiter<Value = Self::Balance>;
}
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[codec(crate = codec)]
#[scale_info(crate = scale_info)]
pub enum Program<BlockNumber: Copy + Saturating> {
Active(ActiveProgram<BlockNumber>),
Exited(ProgramId),
Terminated(ProgramId),
}
impl<BlockNumber: Copy + Saturating> Program<BlockNumber> {
pub fn is_active(&self) -> bool {
matches!(self, Program::Active(_))
}
pub fn is_exited(&self) -> bool {
matches!(self, Program::Exited(_))
}
pub fn is_terminated(&self) -> bool {
matches!(self, Program::Terminated(_))
}
pub fn is_initialized(&self) -> bool {
matches!(
self,
Program::Active(ActiveProgram {
state: ProgramState::Initialized,
..
})
)
}
pub fn is_uninitialized(&self) -> Option<MessageId> {
if let Program::Active(ActiveProgram {
state: ProgramState::Uninitialized { message_id },
..
}) = self
{
Some(*message_id)
} else {
None
}
}
}
#[derive(Clone, Debug, derive_more::Display)]
#[display(fmt = "Program is not an active one")]
pub struct InactiveProgramError;
impl<BlockNumber: Copy + Saturating> core::convert::TryFrom<Program<BlockNumber>>
for ActiveProgram<BlockNumber>
{
type Error = InactiveProgramError;
fn try_from(prog_with_status: Program<BlockNumber>) -> Result<Self, Self::Error> {
match prog_with_status {
Program::Active(p) => Ok(p),
_ => Err(InactiveProgramError),
}
}
}
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[codec(crate = codec)]
#[scale_info(crate = scale_info)]
pub struct ActiveProgram<BlockNumber: Copy + Saturating> {
pub allocations: BTreeSet<WasmPage>,
pub pages_with_data: BTreeSet<GearPage>,
pub gas_reservation_map: GasReservationMap,
pub code_hash: H256,
pub code_exports: BTreeSet<DispatchKind>,
pub static_pages: WasmPage,
pub state: ProgramState,
pub expiration_block: BlockNumber,
}
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[codec(crate = codec)]
#[scale_info(crate = scale_info)]
pub enum ProgramState {
Uninitialized { message_id: MessageId },
Initialized,
}
#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
#[codec(crate = codec)]
#[scale_info(crate = scale_info)]
pub struct CodeMetadata {
pub author: H256,
#[codec(compact)]
pub block_number: u32,
}
impl CodeMetadata {
pub fn new(author: H256, block_number: u32) -> Self {
CodeMetadata {
author,
block_number,
}
}
}
pub trait ExtractCall<Call> {
fn extract_call(&self) -> Call;
}
impl<Address, Call, Signature, Extra> ExtractCall<Call>
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Call: Dispatchable + Clone,
Extra: SignedExtension,
{
fn extract_call(&self) -> Call {
self.function.clone()
}
}
impl<Address, Call, Extra> ExtractCall<Call> for CheckedExtrinsic<Address, Call, Extra>
where
Call: Dispatchable + Clone,
{
fn extract_call(&self) -> Call {
self.function.clone()
}
}