mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 04:09:23 +00:00
Round out the runtime
Ensures the block's size limit is respected. Defines a policy for weights. While I'm unsure I want to commit to this forever, I do want to acknowledge it's valid and well-defined. Cleans up the `serai-runtime` crate a bit with further modules in the `wasm` folder.
This commit is contained in:
@@ -63,6 +63,11 @@ pub struct HeaderV1 {
|
||||
pub consensus_commitment: [u8; 32],
|
||||
}
|
||||
|
||||
impl HeaderV1 {
|
||||
/// The size of a serialized V1 header.
|
||||
pub const SIZE: usize = 8 + 32 + 8 + 32 + 32 + 32;
|
||||
}
|
||||
|
||||
/// A header for a block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Header {
|
||||
@@ -71,6 +76,9 @@ pub enum Header {
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// The size of a serialized header.
|
||||
pub const SIZE: usize = 1 + HeaderV1::SIZE;
|
||||
|
||||
/// Get the hash of the header.
|
||||
pub fn number(&self) -> u64 {
|
||||
match self {
|
||||
@@ -109,8 +117,8 @@ impl Header {
|
||||
|
||||
/// A block.
|
||||
///
|
||||
/// This does not guarantee consistency. The header's `transactions_root` may not match the
|
||||
/// contained transactions.
|
||||
/// This does not guarantee consistency nor validity. The header's `transactions_root` may not
|
||||
/// match the contained transactions, among other ill effects.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Block {
|
||||
/// The block's header.
|
||||
@@ -119,6 +127,13 @@ pub struct Block {
|
||||
pub transactions: Vec<Transaction>,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
/// The size limit for a block.
|
||||
///
|
||||
/// This is not enforced upon deserialization. Be careful accordingly.
|
||||
pub const SIZE_LIMIT: usize = 1024 * 1024;
|
||||
}
|
||||
|
||||
#[cfg(feature = "substrate")]
|
||||
mod substrate {
|
||||
use core::fmt::Debug;
|
||||
@@ -133,7 +148,7 @@ mod substrate {
|
||||
|
||||
use super::*;
|
||||
|
||||
// Add `serde` implementations which treat self as a `Vec<u8>`
|
||||
// Add `serde` implementations which treat `self` as a `Vec<u8>`
|
||||
impl sp_core::serde::Serialize for Transaction {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
||||
@@ -279,12 +279,13 @@ mod substrate {
|
||||
/// The implicit context to verify transactions with.
|
||||
fn implicit_context() -> ImplicitContext;
|
||||
|
||||
/// The size of the current block.
|
||||
fn current_block_size(&self) -> usize;
|
||||
|
||||
/// If a block is present in the blockchain.
|
||||
fn block_is_present_in_blockchain(&self, hash: &BlockHash) -> bool;
|
||||
/// The time embedded into the current block.
|
||||
///
|
||||
/// Returns `None` if the time has yet to be set.
|
||||
fn current_time(&self) -> Option<u64>;
|
||||
fn current_time(&self) -> u64;
|
||||
/// Get the next nonce for an account.
|
||||
fn next_nonce(&self, signer: &SeraiAddress) -> u32;
|
||||
/// If the signer can pay the SRI fee.
|
||||
@@ -295,7 +296,7 @@ mod substrate {
|
||||
) -> Result<(), TransactionValidityError>;
|
||||
|
||||
/// Begin execution of a transaction.
|
||||
fn start_transaction(&self);
|
||||
fn start_transaction(&self, len: usize);
|
||||
/// Consume the next nonce for an account.
|
||||
///
|
||||
/// This MUST NOT be called if the next nonce is `u32::MAX`. The caller MAY panic in that case.
|
||||
@@ -390,9 +391,14 @@ mod substrate {
|
||||
impl<Context: TransactionContext> TransactionWithContext<Context> {
|
||||
fn validate_except_fee<V: ValidateUnsigned<Call = Context::RuntimeCall>>(
|
||||
&self,
|
||||
len: usize,
|
||||
source: TransactionSource,
|
||||
mempool_priority_if_signed: u64,
|
||||
) -> TransactionValidity {
|
||||
if self.1.current_block_size().saturating_add(len) > crate::Block::SIZE_LIMIT {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::ExhaustsResources))?;
|
||||
}
|
||||
|
||||
match &self.0 {
|
||||
Transaction::Unsigned { call } => {
|
||||
let ValidTransaction { priority: _, requires, provides, longevity: _, propagate: _ } =
|
||||
@@ -417,13 +423,8 @@ mod substrate {
|
||||
Err(TransactionValidityError::Unknown(UnknownTransaction::CannotLookup))?;
|
||||
}
|
||||
if let Some(include_by) = *include_by {
|
||||
if let Some(current_time) = self.1.current_time() {
|
||||
if current_time >= u64::from(include_by) {
|
||||
// Since this transaction has a time bound which has passed, error
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?;
|
||||
}
|
||||
} else {
|
||||
// Since this transaction has a time bound, yet we don't know the time, error
|
||||
if self.1.current_time() >= u64::from(include_by) {
|
||||
// Since this transaction has a time bound which has passed, error
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?;
|
||||
}
|
||||
}
|
||||
@@ -471,7 +472,7 @@ mod substrate {
|
||||
&self,
|
||||
source: TransactionSource,
|
||||
info: &DispatchInfo,
|
||||
_len: usize,
|
||||
len: usize,
|
||||
) -> TransactionValidity {
|
||||
let mempool_priority_if_signed = match &self.0 {
|
||||
Transaction::Unsigned { .. } => {
|
||||
@@ -493,19 +494,19 @@ mod substrate {
|
||||
}
|
||||
}
|
||||
};
|
||||
self.validate_except_fee::<V>(source, mempool_priority_if_signed)
|
||||
self.validate_except_fee::<V>(len, source, mempool_priority_if_signed)
|
||||
}
|
||||
|
||||
fn apply<V: ValidateUnsigned<Call = Context::RuntimeCall>>(
|
||||
self,
|
||||
_info: &DispatchInfo,
|
||||
_len: usize,
|
||||
len: usize,
|
||||
) -> sp_runtime::ApplyExtrinsicResultWithInfo<PostDispatchInfo> {
|
||||
// We use 0 for the mempool priority, as this is no longer in the mempool so it's irrelevant
|
||||
self.validate_except_fee::<V>(TransactionSource::InBlock, 0)?;
|
||||
self.validate_except_fee::<V>(len, TransactionSource::InBlock, 0)?;
|
||||
|
||||
// Start the transaction
|
||||
self.1.start_transaction();
|
||||
self.1.start_transaction(len);
|
||||
|
||||
let transaction_hash = self.0.hash();
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ impl frame_system::Config for Test {
|
||||
type AccountId = sp_core::sr25519::Public;
|
||||
type Lookup = frame_support::sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
type BlockLength = serai_core_pallet::Limits;
|
||||
type BlockWeights = serai_core_pallet::Limits;
|
||||
}
|
||||
|
||||
#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||
|
||||
@@ -10,7 +10,7 @@ pub type CoinsEvent = serai_abi::coins::Event;
|
||||
#[test]
|
||||
fn mint() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
Core::start_transaction(0);
|
||||
|
||||
// minting u64::MAX should work
|
||||
let coin = Coin::Serai;
|
||||
@@ -51,7 +51,7 @@ fn mint() {
|
||||
#[test]
|
||||
fn burn_with_instruction() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
Core::start_transaction(0);
|
||||
|
||||
// mint some coin
|
||||
let coin = Coin::External(ExternalCoin::Bitcoin);
|
||||
@@ -106,7 +106,7 @@ fn burn_with_instruction() {
|
||||
#[test]
|
||||
fn transfer() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
Core::start_transaction(0);
|
||||
|
||||
// mint some coin
|
||||
let coin = Coin::External(ExternalCoin::Bitcoin);
|
||||
|
||||
@@ -8,6 +8,9 @@ extern crate alloc;
|
||||
|
||||
use frame_support::traits::{PreInherents, PostTransactions};
|
||||
|
||||
mod limits;
|
||||
pub use limits::Limits;
|
||||
|
||||
mod iumt;
|
||||
pub use iumt::*;
|
||||
|
||||
@@ -83,7 +86,8 @@ pub mod pallet {
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config:
|
||||
frame_system::Config<Hash: Into<[u8; 32]>> + pallet_timestamp::Config<Moment = u64>
|
||||
frame_system::Config<Hash: Into<[u8; 32]>, BlockLength = Limits, BlockWeights = Limits>
|
||||
+ pallet_timestamp::Config<Moment = u64>
|
||||
{
|
||||
}
|
||||
|
||||
@@ -120,7 +124,7 @@ pub mod pallet {
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
|
||||
Self::start_transaction();
|
||||
Self::start_transaction(0);
|
||||
<_>::build(config);
|
||||
Self::end_transaction([0; 32]);
|
||||
|
||||
@@ -130,7 +134,15 @@ pub mod pallet {
|
||||
/// The code to run when beginning execution of a transaction.
|
||||
///
|
||||
/// The caller MUST ensure two transactions aren't simultaneously started.
|
||||
pub fn start_transaction() {
|
||||
pub fn start_transaction(len: usize) {
|
||||
{
|
||||
let existing_len = frame_system::AllExtrinsicsLen::<T>::get().unwrap_or(0);
|
||||
let new_len = existing_len.saturating_add(u32::try_from(len).unwrap_or(u32::MAX));
|
||||
// We panic here as this should've been caught earlier during validation
|
||||
assert!(new_len <= u32::try_from(serai_abi::Block::SIZE_LIMIT).unwrap());
|
||||
frame_system::AllExtrinsicsLen::<T>::set(Some(new_len));
|
||||
}
|
||||
|
||||
TransactionEventsMerkle::<T>::new_expecting_none();
|
||||
Self::deposit_event(Event::BeginTransaction);
|
||||
}
|
||||
@@ -192,7 +204,21 @@ impl<T: Config> PreInherents for StartOfBlock<T> {
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
|
||||
Pallet::<T>::start_transaction();
|
||||
/*
|
||||
We assign the implicit transaction with the block the length of the block itself: its
|
||||
header's length and the length of the length-prefix for the list of transactions.
|
||||
|
||||
The length-prefix will be a little-endian `u32`, as `Block` will be borsh-serialized
|
||||
(https://borsh.io).
|
||||
|
||||
The length of each actual transaction is expected to be accurate as the SCALE implementation
|
||||
defers to the `borsh` serialization.
|
||||
*/
|
||||
assert!(
|
||||
frame_system::AllExtrinsicsLen::<T>::get().is_none(),
|
||||
"AllExtrinsicsLen wasn't killed at the end of the last block"
|
||||
);
|
||||
Pallet::<T>::start_transaction(serai_abi::Header::SIZE + 4);
|
||||
|
||||
// Handle the `SeraiPreExecutionDigest`
|
||||
/*
|
||||
@@ -220,7 +246,7 @@ impl<T: Config> PreInherents for StartOfBlock<T> {
|
||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> PostTransactions for EndOfBlock<T> {
|
||||
fn post_transactions() {
|
||||
Pallet::<T>::start_transaction();
|
||||
Pallet::<T>::start_transaction(0);
|
||||
|
||||
// Other modules' `PostTransactions`
|
||||
|
||||
@@ -229,6 +255,8 @@ impl<T: Config> PostTransactions for EndOfBlock<T> {
|
||||
end_of_block_transaction_hash[.. 16].copy_from_slice(&[0xff; 16]);
|
||||
Pallet::<T>::end_transaction(end_of_block_transaction_hash);
|
||||
|
||||
frame_system::AllExtrinsicsLen::<T>::kill();
|
||||
|
||||
use serai_abi::SeraiExecutionDigest;
|
||||
frame_system::Pallet::<T>::deposit_log(
|
||||
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
||||
|
||||
34
substrate/core/src/limits.rs
Normal file
34
substrate/core/src/limits.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use sp_core::Get;
|
||||
use frame_support::weights::Weight;
|
||||
use frame_system::limits::{BlockLength, BlockWeights};
|
||||
|
||||
/// The limits for the Serai protocol.
|
||||
pub struct Limits;
|
||||
impl Get<BlockLength> for Limits {
|
||||
fn get() -> BlockLength {
|
||||
/*
|
||||
We do not reserve an allocation for mandatory/operational transactions, assuming they'll be
|
||||
prioritized in the mempool. This does technically give block producers an inventive to
|
||||
misbehave by on-purposely favoring paying non-operational transactions over operational
|
||||
transactions, but ensures the entire block is available to the transactions actually present
|
||||
in the mempool.
|
||||
*/
|
||||
BlockLength::max(u32::try_from(serai_abi::Block::SIZE_LIMIT).unwrap())
|
||||
}
|
||||
}
|
||||
impl Get<BlockWeights> for Limits {
|
||||
fn get() -> BlockWeights {
|
||||
/*
|
||||
While Serai does limit the size of a block, every transaction is expected to operate in
|
||||
complexity constant to the current state size, regardless of what the state is. Accordingly,
|
||||
the most efficient set of transactions (basic transfers?) is expected to be within an order
|
||||
of magnitude of the most expensive transactions (multi-pool swaps?).
|
||||
|
||||
Instead of engaging with the complexity within the consensus protocol of metering both
|
||||
bandwidth and computation, we do not define limits for weights. We do, however, still use the
|
||||
weight system in order to determine fee rates and ensure prioritization to
|
||||
computationally-cheaper transactions. That solely serves as mempool policy however.
|
||||
*/
|
||||
BlockWeights::simple_max(Weight::MAX)
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ impl frame_system::Config for Test {
|
||||
type AccountId = sp_core::sr25519::Public;
|
||||
type Lookup = frame_support::sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
type BlockLength = serai_core_pallet::Limits;
|
||||
type BlockWeights = serai_core_pallet::Limits;
|
||||
}
|
||||
|
||||
#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||
|
||||
127
substrate/runtime/src/wasm/map.rs
Normal file
127
substrate/runtime/src/wasm/map.rs
Normal file
@@ -0,0 +1,127 @@
|
||||
use super::*;
|
||||
|
||||
impl From<Option<SeraiAddress>> for RuntimeOrigin {
|
||||
fn from(signer: Option<SeraiAddress>) -> Self {
|
||||
match signer {
|
||||
None => RuntimeOrigin::none(),
|
||||
Some(signer) => RuntimeOrigin::signed(signer.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serai_abi::Call> for RuntimeCall {
|
||||
fn from(call: serai_abi::Call) -> Self {
|
||||
match call {
|
||||
serai_abi::Call::Coins(call) => {
|
||||
use serai_abi::coins::Call;
|
||||
use serai_coins_pallet::Call as Scall;
|
||||
RuntimeCall::Coins(match call {
|
||||
Call::transfer { to, coins } => Scall::transfer { to: to.into(), coins },
|
||||
Call::burn { coins } => Scall::burn { coins },
|
||||
Call::burn_with_instruction { instruction } => {
|
||||
Scall::burn_with_instruction { instruction }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::ValidatorSets(call) => {
|
||||
use serai_abi::validator_sets::Call;
|
||||
use serai_validator_sets_pallet::Call as Scall;
|
||||
RuntimeCall::ValidatorSets(match call {
|
||||
Call::set_keys { network, key_pair, signature_participants, signature } => {
|
||||
Scall::set_keys { network, key_pair, signature_participants, signature }
|
||||
}
|
||||
Call::report_slashes { network, slashes, signature } => {
|
||||
Scall::report_slashes { network, slashes, signature }
|
||||
}
|
||||
Call::set_embedded_elliptic_curve_keys { keys } => {
|
||||
Scall::set_embedded_elliptic_curve_keys { keys }
|
||||
}
|
||||
Call::allocate { network, amount } => Scall::allocate { network, amount },
|
||||
Call::deallocate { network, amount } => Scall::deallocate { network, amount },
|
||||
Call::claim_deallocation { deallocation } => Scall::claim_deallocation {
|
||||
network: deallocation.network,
|
||||
session: deallocation.session,
|
||||
},
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Signals(call) => {
|
||||
use serai_abi::signals::Call;
|
||||
use serai_signals_pallet::Call as Scall;
|
||||
RuntimeCall::Signals(match call {
|
||||
Call::register_retirement_signal { in_favor_of } => {
|
||||
Scall::register_retirement_signal { in_favor_of }
|
||||
}
|
||||
Call::revoke_retirement_signal { was_in_favor_of } => {
|
||||
Scall::revoke_retirement_signal { retirement_signal: was_in_favor_of }
|
||||
}
|
||||
Call::favor { signal, with_network } => Scall::favor { signal, with_network },
|
||||
Call::revoke_favor { signal, with_network } => {
|
||||
Scall::revoke_favor { signal, with_network }
|
||||
}
|
||||
Call::stand_against { signal, with_network } => {
|
||||
Scall::stand_against { signal, with_network }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Dex(call) => {
|
||||
use serai_abi::dex::Call;
|
||||
RuntimeCall::Dex(match call {
|
||||
Call::add_liquidity {
|
||||
external_coin,
|
||||
sri_intended,
|
||||
external_coin_intended,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
} => serai_dex_pallet::Call::add_liquidity {
|
||||
external_coin,
|
||||
sri_intended,
|
||||
external_coin_intended,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
},
|
||||
Call::transfer_liquidity { to, liquidity_tokens } => {
|
||||
serai_dex_pallet::Call::transfer_liquidity { to, liquidity_tokens }
|
||||
}
|
||||
Call::remove_liquidity { liquidity_tokens, sri_minimum, external_coin_minimum } => {
|
||||
serai_dex_pallet::Call::remove_liquidity {
|
||||
liquidity_tokens,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
}
|
||||
}
|
||||
Call::swap { coins_to_swap, minimum_to_receive } => {
|
||||
serai_dex_pallet::Call::swap { coins_to_swap, minimum_to_receive }
|
||||
}
|
||||
Call::swap_for { coins_to_receive, maximum_to_swap } => {
|
||||
serai_dex_pallet::Call::swap_for { coins_to_receive, maximum_to_swap }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::GenesisLiquidity(call) => {
|
||||
use serai_abi::genesis_liquidity::Call;
|
||||
RuntimeCall::GenesisLiquidity(match call {
|
||||
Call::oraclize_values { values, signature } => {
|
||||
serai_genesis_liquidity_pallet::Call::oraclize_values { values, signature }
|
||||
}
|
||||
Call::transfer_genesis_liquidity { to, genesis_liquidity } => {
|
||||
serai_genesis_liquidity_pallet::Call::transfer_genesis_liquidity {
|
||||
to,
|
||||
genesis_liquidity,
|
||||
}
|
||||
}
|
||||
Call::remove_genesis_liquidity { genesis_liquidity } => {
|
||||
serai_genesis_liquidity_pallet::Call::remove_genesis_liquidity { genesis_liquidity }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::InInstructions(call) => {
|
||||
use serai_abi::in_instructions::Call;
|
||||
RuntimeCall::InInstructions(match call {
|
||||
Call::execute_batch { batch } => {
|
||||
serai_in_instructions_pallet::Call::execute_batch { batch }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::marker::PhantomData;
|
||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||
|
||||
use sp_core::{ConstU32, ConstU64, sr25519::Public};
|
||||
use sp_core::{Get, ConstU32, ConstU64, sr25519::Public};
|
||||
use sp_runtime::{
|
||||
Perbill, Weight,
|
||||
traits::{Header as _, Block as _},
|
||||
@@ -21,51 +21,10 @@ use serai_abi::{
|
||||
|
||||
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
||||
|
||||
/// The lookup for a SeraiAddress -> Public.
|
||||
pub struct Lookup;
|
||||
impl sp_runtime::traits::StaticLookup for Lookup {
|
||||
type Source = SeraiAddress;
|
||||
type Target = Public;
|
||||
fn lookup(source: SeraiAddress) -> Result<Public, sp_runtime::traits::LookupError> {
|
||||
Ok(source.into())
|
||||
}
|
||||
fn unlookup(source: Public) -> SeraiAddress {
|
||||
source.into()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove
|
||||
#[sp_version::runtime_version]
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: Cow::Borrowed("serai"),
|
||||
impl_name: Cow::Borrowed("core"),
|
||||
authoring_version: 0,
|
||||
spec_version: 0,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 0,
|
||||
system_version: 0,
|
||||
};
|
||||
|
||||
frame_support::parameter_types! {
|
||||
pub const Version: RuntimeVersion = VERSION;
|
||||
|
||||
// TODO
|
||||
pub BlockLength: frame_system::limits::BlockLength =
|
||||
frame_system::limits::BlockLength::max_with_normal_ratio(
|
||||
100 * 1024,
|
||||
Perbill::from_percent(75),
|
||||
);
|
||||
// TODO
|
||||
pub BlockWeights: frame_system::limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::with_sensible_defaults(
|
||||
Weight::from_parts(
|
||||
2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
|
||||
u64::MAX,
|
||||
),
|
||||
Perbill::from_percent(75),
|
||||
);
|
||||
}
|
||||
/// Maps `serai_abi` types into the types expected within the Substrate runtime
|
||||
mod map;
|
||||
/// The configuration for `frame_system`.
|
||||
mod system;
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
@@ -113,45 +72,6 @@ mod runtime {
|
||||
pub type Grandpa = pallet_grandpa::Pallet<Runtime>;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = BlockLength;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type Nonce = u32;
|
||||
type Hash = <Self::Block as sp_runtime::traits::Block>::Hash;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = sp_core::sr25519::Public;
|
||||
type Lookup = Lookup;
|
||||
type Block = Block;
|
||||
// Don't track old block hashes within the System pallet
|
||||
// We use not a number -> hash index, but a hash -> () index, in our own pallet
|
||||
type BlockHashCount = ConstU64<1>;
|
||||
type DbWeight = frame_support::weights::constants::RocksDbWeight;
|
||||
type Version = Version;
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = ();
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
// We use the default weights as we never expose/call any of these methods
|
||||
type SystemWeightInfo = ();
|
||||
// We also don't use the provided extensions framework
|
||||
type ExtensionsWeightInfo = ();
|
||||
// We don't invoke any hooks on-set-code as we don't perform upgrades via the blockchain yet via
|
||||
// nodes, ensuring everyone who upgrades consents to the rules they upgrade to
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = ConstU32<{ u32::MAX }>;
|
||||
// No migrations set
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
|
||||
type PreInherents = serai_core_pallet::StartOfBlock<Runtime>;
|
||||
type PostInherents = ();
|
||||
type PostTransactions = serai_core_pallet::EndOfBlock<Runtime>;
|
||||
}
|
||||
|
||||
impl serai_core_pallet::Config for Runtime {}
|
||||
|
||||
impl serai_coins_pallet::Config<CoinsInstance> for Runtime {
|
||||
@@ -237,137 +157,6 @@ impl pallet_grandpa::Config for Runtime {
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
|
||||
impl From<Option<SeraiAddress>> for RuntimeOrigin {
|
||||
fn from(signer: Option<SeraiAddress>) -> Self {
|
||||
match signer {
|
||||
None => RuntimeOrigin::none(),
|
||||
Some(signer) => RuntimeOrigin::signed(signer.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serai_abi::Call> for RuntimeCall {
|
||||
fn from(call: serai_abi::Call) -> Self {
|
||||
match call {
|
||||
serai_abi::Call::Coins(call) => {
|
||||
use serai_abi::coins::Call;
|
||||
use serai_coins_pallet::Call as Scall;
|
||||
RuntimeCall::Coins(match call {
|
||||
Call::transfer { to, coins } => Scall::transfer { to: to.into(), coins },
|
||||
Call::burn { coins } => Scall::burn { coins },
|
||||
Call::burn_with_instruction { instruction } => {
|
||||
Scall::burn_with_instruction { instruction }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::ValidatorSets(call) => {
|
||||
use serai_abi::validator_sets::Call;
|
||||
use serai_validator_sets_pallet::Call as Scall;
|
||||
RuntimeCall::ValidatorSets(match call {
|
||||
Call::set_keys { network, key_pair, signature_participants, signature } => {
|
||||
Scall::set_keys { network, key_pair, signature_participants, signature }
|
||||
}
|
||||
Call::report_slashes { network, slashes, signature } => {
|
||||
Scall::report_slashes { network, slashes, signature }
|
||||
}
|
||||
Call::set_embedded_elliptic_curve_keys { keys } => {
|
||||
Scall::set_embedded_elliptic_curve_keys { keys }
|
||||
}
|
||||
Call::allocate { network, amount } => Scall::allocate { network, amount },
|
||||
Call::deallocate { network, amount } => Scall::deallocate { network, amount },
|
||||
Call::claim_deallocation { deallocation } => Scall::claim_deallocation {
|
||||
network: deallocation.network,
|
||||
session: deallocation.session,
|
||||
},
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Signals(call) => {
|
||||
use serai_abi::signals::Call;
|
||||
use serai_signals_pallet::Call as Scall;
|
||||
RuntimeCall::Signals(match call {
|
||||
Call::register_retirement_signal { in_favor_of } => {
|
||||
Scall::register_retirement_signal { in_favor_of }
|
||||
}
|
||||
Call::revoke_retirement_signal { was_in_favor_of } => {
|
||||
Scall::revoke_retirement_signal { retirement_signal: was_in_favor_of }
|
||||
}
|
||||
Call::favor { signal, with_network } => Scall::favor { signal, with_network },
|
||||
Call::revoke_favor { signal, with_network } => {
|
||||
Scall::revoke_favor { signal, with_network }
|
||||
}
|
||||
Call::stand_against { signal, with_network } => {
|
||||
Scall::stand_against { signal, with_network }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Dex(call) => {
|
||||
use serai_abi::dex::Call;
|
||||
match call {
|
||||
Call::add_liquidity {
|
||||
external_coin,
|
||||
sri_intended,
|
||||
external_coin_intended,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
} => RuntimeCall::Dex(serai_dex_pallet::Call::add_liquidity {
|
||||
external_coin,
|
||||
sri_intended,
|
||||
external_coin_intended,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
}),
|
||||
Call::transfer_liquidity { to, liquidity_tokens } => {
|
||||
RuntimeCall::Dex(serai_dex_pallet::Call::transfer_liquidity { to, liquidity_tokens })
|
||||
}
|
||||
Call::remove_liquidity { liquidity_tokens, sri_minimum, external_coin_minimum } => {
|
||||
RuntimeCall::Dex(serai_dex_pallet::Call::remove_liquidity {
|
||||
liquidity_tokens,
|
||||
sri_minimum,
|
||||
external_coin_minimum,
|
||||
})
|
||||
}
|
||||
Call::swap { coins_to_swap, minimum_to_receive } => {
|
||||
RuntimeCall::Dex(serai_dex_pallet::Call::swap { coins_to_swap, minimum_to_receive })
|
||||
}
|
||||
Call::swap_for { coins_to_receive, maximum_to_swap } => {
|
||||
RuntimeCall::Dex(serai_dex_pallet::Call::swap_for { coins_to_receive, maximum_to_swap })
|
||||
}
|
||||
}
|
||||
}
|
||||
serai_abi::Call::GenesisLiquidity(call) => {
|
||||
use serai_abi::genesis_liquidity::Call;
|
||||
match call {
|
||||
Call::oraclize_values { values, signature } => {
|
||||
RuntimeCall::GenesisLiquidity(serai_genesis_liquidity_pallet::Call::oraclize_values {
|
||||
values,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
Call::transfer_genesis_liquidity { to, genesis_liquidity } => {
|
||||
RuntimeCall::GenesisLiquidity(
|
||||
serai_genesis_liquidity_pallet::Call::transfer_genesis_liquidity {
|
||||
to,
|
||||
genesis_liquidity,
|
||||
},
|
||||
)
|
||||
}
|
||||
Call::remove_genesis_liquidity { genesis_liquidity } => RuntimeCall::GenesisLiquidity(
|
||||
serai_genesis_liquidity_pallet::Call::remove_genesis_liquidity { genesis_liquidity },
|
||||
),
|
||||
}
|
||||
}
|
||||
serai_abi::Call::InInstructions(call) => {
|
||||
use serai_abi::in_instructions::Call;
|
||||
match call {
|
||||
Call::execute_batch { batch } => {
|
||||
RuntimeCall::InInstructions(serai_in_instructions_pallet::Call::execute_batch { batch })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Executive = frame_executive::Executive<Runtime, Block, Context, Runtime, AllPalletsWithSystem>;
|
||||
|
||||
const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
|
||||
@@ -411,7 +200,7 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
impl sp_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
VERSION
|
||||
<Runtime as frame_system::Config>::Version::get()
|
||||
}
|
||||
fn initialize_block(header: &Header) -> sp_runtime::ExtrinsicInclusionMode {
|
||||
Executive::initialize_block(header)
|
||||
@@ -667,13 +456,19 @@ impl serai_abi::TransactionContext for Context {
|
||||
}
|
||||
}
|
||||
|
||||
/// The size of the current block.
|
||||
fn current_block_size(&self) -> usize {
|
||||
let current_block_size = frame_system::AllExtrinsicsLen::<Runtime>::get().unwrap_or(0);
|
||||
usize::try_from(current_block_size).unwrap_or(usize::MAX)
|
||||
}
|
||||
|
||||
/// If a block is present in the blockchain.
|
||||
fn block_is_present_in_blockchain(&self, hash: &serai_abi::primitives::BlockHash) -> bool {
|
||||
serai_core_pallet::Pallet::<Runtime>::block_exists(hash)
|
||||
}
|
||||
/// The time embedded into the current block.
|
||||
fn current_time(&self) -> Option<u64> {
|
||||
todo!("TODO")
|
||||
fn current_time(&self) -> u64 {
|
||||
pallet_timestamp::Pallet::<Runtime>::get()
|
||||
}
|
||||
/// Get the next nonce for an account.
|
||||
fn next_nonce(&self, signer: &SeraiAddress) -> u32 {
|
||||
@@ -695,8 +490,8 @@ impl serai_abi::TransactionContext for Context {
|
||||
}
|
||||
}
|
||||
|
||||
fn start_transaction(&self) {
|
||||
Core::start_transaction()
|
||||
fn start_transaction(&self, len: usize) {
|
||||
Core::start_transaction(len)
|
||||
}
|
||||
fn consume_next_nonce(&self, signer: &SeraiAddress) {
|
||||
serai_core_pallet::Pallet::<Runtime>::consume_next_nonce(signer)
|
||||
@@ -726,26 +521,7 @@ impl serai_abi::TransactionContext for Context {
|
||||
/* TODO
|
||||
use validator_sets::MembershipProof;
|
||||
|
||||
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
||||
|
||||
parameter_types! {
|
||||
pub const Version: RuntimeVersion = VERSION;
|
||||
|
||||
pub const SS58Prefix: u8 = 42; // TODO: Remove for Bech32m
|
||||
|
||||
// 1 MB block size limit
|
||||
pub BlockLength: system::limits::BlockLength =
|
||||
system::limits::BlockLength::max_with_normal_ratio(BLOCK_SIZE, NORMAL_DISPATCH_RATIO);
|
||||
pub BlockWeights: system::limits::BlockWeights =
|
||||
system::limits::BlockWeights::with_sensible_defaults(
|
||||
Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
|
||||
NORMAL_DISPATCH_RATIO,
|
||||
);
|
||||
}
|
||||
|
||||
impl timestamp::Config for Runtime {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = Babe;
|
||||
type MinimumPeriod = ConstU64<{ (TARGET_BLOCK_TIME * 1000) / 2 }>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
@@ -782,14 +558,6 @@ impl signals::Config for Runtime {
|
||||
type RetirementLockInDuration = ConstU32<{ (2 * 7 * 24 * 60 * 60) / (TARGET_BLOCK_TIME as u32) }>;
|
||||
}
|
||||
|
||||
impl in_instructions::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
|
||||
impl genesis_liquidity::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
|
||||
impl emissions::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
@@ -818,54 +586,4 @@ impl pallet_authorship::Config for Runtime {
|
||||
|
||||
/// Longevity of an offence report.
|
||||
pub type ReportLongevity = <Runtime as pallet_babe::Config>::EpochDuration;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
#[macro_use]
|
||||
extern crate frame_benchmarking;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benches {
|
||||
define_benchmarks!(
|
||||
[frame_benchmarking, BaselineBench::<Runtime>]
|
||||
|
||||
[system, SystemBench::<Runtime>]
|
||||
|
||||
[balances, Balances]
|
||||
|
||||
[babe, Babe]
|
||||
[grandpa, Grandpa]
|
||||
);
|
||||
}
|
||||
|
||||
sp_api::impl_runtime_apis! {
|
||||
impl validator_sets::ValidatorSetsApi<Block> for Runtime {
|
||||
fn external_network_key(network: ExternalNetworkId) -> Option<Vec<u8>> {
|
||||
ValidatorSets::external_network_key(network)
|
||||
}
|
||||
}
|
||||
|
||||
impl dex::DexApi<Block> for Runtime {
|
||||
fn quote_price_exact_tokens_for_tokens(
|
||||
coin1: Coin,
|
||||
coin2: Coin,
|
||||
amount: SubstrateAmount,
|
||||
include_fee: bool
|
||||
) -> Option<SubstrateAmount> {
|
||||
Dex::quote_price_exact_tokens_for_tokens(coin1, coin2, amount, include_fee)
|
||||
}
|
||||
|
||||
fn quote_price_tokens_for_exact_tokens(
|
||||
coin1: Coin,
|
||||
coin2: Coin,
|
||||
amount: SubstrateAmount,
|
||||
include_fee: bool
|
||||
) -> Option<SubstrateAmount> {
|
||||
Dex::quote_price_tokens_for_exact_tokens(coin1, coin2, amount, include_fee)
|
||||
}
|
||||
|
||||
fn get_reserves(coin1: Coin, coin2: Coin) -> Option<(SubstrateAmount, SubstrateAmount)> {
|
||||
Dex::get_reserves(&coin1, &coin2).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
95
substrate/runtime/src/wasm/system.rs
Normal file
95
substrate/runtime/src/wasm/system.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use super::*;
|
||||
|
||||
/// The lookup for a SeraiAddress -> Public.
|
||||
pub struct Lookup;
|
||||
impl sp_runtime::traits::StaticLookup for Lookup {
|
||||
type Source = SeraiAddress;
|
||||
type Target = Public;
|
||||
fn lookup(source: SeraiAddress) -> Result<Public, sp_runtime::traits::LookupError> {
|
||||
Ok(source.into())
|
||||
}
|
||||
fn unlookup(source: Public) -> SeraiAddress {
|
||||
source.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// The runtime version.
|
||||
pub struct Version;
|
||||
// TODO: Are we reasonably able to prune `RuntimeVersion` from Substrate?
|
||||
impl Get<RuntimeVersion> for Version {
|
||||
fn get() -> RuntimeVersion {
|
||||
#[sp_version::runtime_version]
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: Cow::Borrowed("serai"),
|
||||
impl_name: Cow::Borrowed("core"),
|
||||
authoring_version: 0,
|
||||
spec_version: 0,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 0,
|
||||
system_version: 0,
|
||||
};
|
||||
VERSION
|
||||
}
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type PalletInfo = PalletInfo;
|
||||
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type Hash = <Self::Block as sp_runtime::traits::Block>::Hash;
|
||||
|
||||
type Block = Block;
|
||||
type AccountId = sp_core::sr25519::Public;
|
||||
type Lookup = Lookup;
|
||||
type Nonce = u32;
|
||||
|
||||
type PreInherents = serai_core_pallet::StartOfBlock<Runtime>;
|
||||
type PostInherents = ();
|
||||
type PostTransactions = serai_core_pallet::EndOfBlock<Runtime>;
|
||||
|
||||
/*
|
||||
We do not globally filter the types of calls which may be performed. Instead, our ABI only
|
||||
exposes the calls we want exposed, and each call individually errors if it's called when it
|
||||
shouldn't be.
|
||||
*/
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
|
||||
/*
|
||||
We do not have `frame_system` track historical block hashes by their block number. Instead,
|
||||
`serai_core_pallet` populates a hash set (map of `[u8; 32] -> ()`) of all historical block's
|
||||
hashes within itself.
|
||||
|
||||
The usage of `1` here is solely as `frame_system` requires it be at least `1`.
|
||||
*/
|
||||
type BlockHashCount = ConstU64<1>;
|
||||
|
||||
type Version = Version;
|
||||
type BlockLength = serai_core_pallet::Limits;
|
||||
type BlockWeights = serai_core_pallet::Limits;
|
||||
// We assume `serai-node` will be run using the RocksDB backend
|
||||
type DbWeight = frame_support::weights::constants::RocksDbWeight;
|
||||
/*
|
||||
Serai does not expose `frame_system::Call` nor does it use transaction extensions. We
|
||||
accordingly have no consequence to using the default weights for these accordingly.
|
||||
*/
|
||||
type SystemWeightInfo = ();
|
||||
type ExtensionsWeightInfo = ();
|
||||
|
||||
// We also don't use `frame_system`'s account system at all, leaving us to bottom these out.
|
||||
type AccountData = ();
|
||||
type MaxConsumers = ConstU32<{ u32::MAX }>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
|
||||
// Serai does perform any 'on-chain upgrades' to ensure upgrades are opted into by the entity
|
||||
// running this node and accordingly consented to
|
||||
type OnSetCode = ();
|
||||
|
||||
// We do not have any migrations declared
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
}
|
||||
Reference in New Issue
Block a user