// This file is part of Substrate.
// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd.
// 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 .
//! The Data Availability runtime. This can be compiled with `#[no_std]`, ready for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512.
#![recursion_limit = "512"]
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
pub(crate) const LOG_TARGET: &str = "da-runtime";
pub mod apis;
pub mod constants;
#[cfg(test)]
mod header_extension_builder_data_tests;
pub mod impls;
#[cfg(test)]
mod impls_tests;
pub mod kate;
mod primitives;
pub mod transaction_filter;
mod version;
mod weights;
pub use avail_core::currency::{Balance, AVAIL, CENTS, MILLICENTS};
pub use avail_core::{header::Header as DaHeader, AppId};
use constants::time::*;
pub use frame_support::{
construct_runtime, debug,
dispatch::DispatchClass,
pallet_prelude::Get,
parameter_types,
traits::{
ConstU32, ContainsLengthBound, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything,
ExtrinsicCall, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, SortedMembers,
},
weights::{
constants::{
BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND,
},
ConstantMultiplier, IdentityFee, Weight,
},
PalletId, StorageValue,
};
pub use impls::BlockHashCount;
pub use pallet_balances::Call as BalancesCall;
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_session::historical as pallet_session_historical;
#[cfg(feature = "std")]
pub use pallet_staking::StakerStatus;
pub use primitives::*;
use sp_core::OpaqueMetadata;
pub use sp_runtime::{Perbill, Percent, Permill, RuntimeDebug};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
pub use version::VERSION;
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
#[cfg(feature = "std")]
pub fn wasm_binary_unwrap() -> &'static [u8] {
WASM_BINARY.expect(
"Development wasm binary is not available. This means the client is built with \
`SKIP_WASM_BUILD` flag and it is only usable for production chains. Please rebuild with \
the flag disabled.",
)
}
pub mod voter_bags;
/// The version information used to identify this runtime when compiled natively.
#[cfg(any(feature = "std", test))]
pub fn native_version() -> NativeVersion {
NativeVersion {
runtime_version: VERSION,
can_author_with: Default::default(),
}
}
// Create the runtime by composing the FRAME pallets that were previously configured.
construct_runtime!(
pub struct Runtime
{
System: frame_system = 0,
Utility: pallet_utility = 1,
Babe: pallet_babe = 2,
Timestamp: pallet_timestamp = 3,
Authorship: pallet_authorship = 4,
Indices: pallet_indices = 5,
Balances: pallet_balances = 6,
TransactionPayment: pallet_transaction_payment = 7,
ElectionProviderMultiPhase: pallet_election_provider_multi_phase = 9,
Staking: pallet_staking = 10,
Session: pallet_session = 11,
// Democracy: pallet_democracy = 12,
// Council: pallet_collective:: = 13,
TechnicalCommittee: pallet_collective:: = 14,
// Elections: pallet_elections_phragmen = 15,
// TechnicalMembership: pallet_membership:: = 16,
Grandpa: pallet_grandpa = 17,
Treasury: pallet_treasury = 18,
Sudo: pallet_sudo = 19,
ImOnline: pallet_im_online = 20,
AuthorityDiscovery: pallet_authority_discovery = 21,
Offences: pallet_offences = 22,
Historical: pallet_session_historical = 23,
Scheduler: pallet_scheduler = 24,
Mmr: pallet_mmr = 27,
// BagsList: pallet_bags_list = 28,
// DA module
DataAvailability: da_control = 29,
// Old: Nomad - don't use id 30,31,32
// More from upgrade to v0.9.33
Preimage: pallet_preimage = 33,
Multisig: pallet_multisig = 34,
VoterList: pallet_bags_list:: = 35,
NominationPools: pallet_nomination_pools = 36,
Identity: pallet_identity = 37,
Mandate: pallet_mandate = 38,
Vector: pallet_vector = 39,
Proxy: pallet_proxy = 40,
TxPause: pallet_tx_pause = 41,
TreasuryCommittee: pallet_collective:: = 42,
}
);
/// MMR helper types.
pub(crate) mod mmr {
pub use pallet_mmr::primitives::*;
use super::Runtime;
pub type Leaf = <::LeafData as LeafDataProvider>::LeafData;
pub type Hash = ::Output;
pub type Hashing = ::Hashing;
}
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")]
mod benches {
define_benchmarks!(
[frame_benchmarking, BaselineBench::]
[pallet_utility, crate::Utility]
[pallet_babe, crate::Babe]
[pallet_timestamp, crate::Timestamp]
[pallet_indices, crate::Indices]
[pallet_balances, crate::Balances]
[pallet_election_provider_multi_phase, crate::ElectionProviderMultiPhase]
[pallet_staking, crate::Staking]
[pallet_collective, crate::TechnicalCommittee]
[pallet_grandpa, crate::Grandpa]
[pallet_treasury, crate::Treasury]
[pallet_im_online, crate::ImOnline]
[pallet_scheduler, crate::Scheduler]
[pallet_mmr, crate::Mmr]
[frame_system, SystemBench::]
[da_control, crate::DataAvailability]
[pallet_identity, crate::Identity]
[pallet_mandate, crate::Mandate]
[pallet_vector, crate::Vector]
[pallet_proxy, crate::Proxy]
[pallet_tx_pause, crate::TxPause]
[pallet_collective, crate::TreasuryCommittee]
);
}
#[cfg(test)]
mod tests {
use codec::Encode;
use core::mem::size_of;
use std::collections::HashSet;
use frame_election_provider_support::NposSolution;
use frame_support::{
dispatch::{DispatchInfo, GetDispatchInfo},
traits::WhitelistedStorageKeys,
};
use frame_system::offchain::CreateSignedTransaction;
use hex_literal::hex;
use sp_core::hexdisplay::HexDisplay;
use sp_keyring::AccountKeyring::Bob;
use sp_runtime::{
traits::SignedExtension, transaction_validity::InvalidTransaction, MultiAddress, UpperOf,
};
use test_case::test_case;
use super::*;
#[test]
fn runtime_block_length_ratios_are_configured() {
let block_length = impls::RuntimeBlockLength::get();
assert_eq!(
*block_length.max.get(DispatchClass::Normal),
85 * 5 * 1024 * 1024 / 100
);
assert_eq!(
*block_length.max.get(DispatchClass::Operational),
90 * 5 * 1024 * 1024 / 100
);
assert_eq!(
*block_length.max.get(DispatchClass::Mandatory),
5 * 1024 * 1024
);
}
#[test]
fn oversized_authorized_upgrade_is_rejected_by_length_validation() {
sp_io::TestExternalities::default().execute_with(|| {
let operational_limit = *impls::RuntimeBlockLength::get()
.max
.get(DispatchClass::Operational) as usize;
let call = RuntimeCall::System(frame_system::Call::apply_authorized_upgrade {
code: vec![0; operational_limit],
});
let info = call.get_dispatch_info();
let encoded_len = UncheckedExtrinsic::new_unsigned(call.clone())
.encode()
.len();
let check_weight = frame_system::CheckWeight::::new();
assert_eq!(info.class, DispatchClass::Operational);
assert!(encoded_len > operational_limit);
assert_eq!(
check_weight.validate(&AccountId::new([0; 32]), &call, &info, encoded_len,),
Err(InvalidTransaction::ExhaustsResources.into())
);
assert_eq!(
frame_system::CheckWeight::::validate_unsigned(&call, &info, encoded_len),
Err(InvalidTransaction::ExhaustsResources.into())
);
let small_call = RuntimeCall::System(frame_system::Call::apply_authorized_upgrade {
code: vec![0; 1],
});
let small_info = small_call.get_dispatch_info();
let small_len = UncheckedExtrinsic::new_unsigned(small_call.clone())
.encode()
.len();
assert!(check_weight
.validate(
&AccountId::new([0; 32]),
&small_call,
&small_info,
small_len,
)
.is_ok());
});
}
#[test]
fn operational_limit_leaves_room_for_vector_post_inherent() {
sp_io::TestExternalities::default().execute_with(|| {
let block_length = impls::RuntimeBlockLength::get();
let operational_limit =
*block_length.max.get(DispatchClass::Operational) as usize;
let mandatory_limit = *block_length.max.get(DispatchClass::Mandatory) as usize;
let post_inherent = as avail_base::ProvidePostInherent>::create_inherent(
&Default::default(),
)
.expect("Vector always provides its post-inherent");
let post_inherent = UncheckedExtrinsic::new_unsigned(post_inherent.into());
let post_info = post_inherent.get_dispatch_info();
let post_len = post_inherent.encode().len();
let operational_info = DispatchInfo {
class: DispatchClass::Operational,
..Default::default()
};
assert_eq!(post_info.class, DispatchClass::Mandatory);
assert!(post_len <= mandatory_limit - operational_limit);
assert!(
frame_system::CheckWeight::::do_pre_dispatch(
&operational_info,
operational_limit,
)
.is_ok()
);
assert!(
frame_system::CheckWeight::::do_pre_dispatch(&post_info, post_len).is_ok()
);
assert_eq!(
System::all_extrinsics_len() as usize,
operational_limit + post_len
);
});
}
/// This test was used to detect any missing support of `TryState` needed for `try-runtime`
/// feature.
#[cfg(feature = "try-runtime")]
#[allow(dead_code)]
fn check_try_runtime_support_on_pallets() -> Result<(), &'static str> {
use crate::impls::{TechnicalCollective, TreasuryCollective};
use frame_support::traits::{TryState, TryStateSelect::All};
use sp_runtime::traits::Zero;
let block = Zero::zero();
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(
block, All,
)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(
block, All,
)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(
block, All,
)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState<
BlockNumber,
>>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
as TryState>::try_state(block, All)?;
Ok(())
}
#[test]
fn check_whitelist() {
let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys()
.iter()
.map(|e| HexDisplay::from(&e.key).to_string())
.collect();
// Block Number
assert!(
whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
);
// Total Issuance
assert!(
whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
);
// Execution Phase
assert!(
whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
);
// Event Count
assert!(
whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
);
// System Events
assert!(
whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
);
// System BlockWeight
assert!(
whitelist.contains("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96")
);
}
#[test]
fn validate_transaction_submitter_bounds() {
fn is_submit_signed_transaction()
where
T: CreateSignedTransaction,
{
}
is_submit_signed_transaction::();
}
#[test]
fn perbill_as_onchain_accuracy() {
type OnChainAccuracy =
<::Solution as NposSolution>::Accuracy;
let maximum_chain_accuracy: Vec> = (0
..constants::staking::MaxNominations::get())
.map(|_| >::from(OnChainAccuracy::one().deconstruct()))
.collect();
let _: UpperOf = maximum_chain_accuracy
.iter()
.fold(0, |acc, x| acc.checked_add(*x).unwrap());
}
const RUNTIME_CALL_SIZE: usize = size_of::();
const DA_CALL_SIZE: usize = size_of::>();
const SYSTEM_CALL_SIZE: usize = size_of::>();
#[test_case(RUNTIME_CALL_SIZE => 208)]
#[test_case(DA_CALL_SIZE => 64)]
#[test_case(SYSTEM_CALL_SIZE => 40)]
fn call_size(size: usize) -> usize {
const MAX_CALL_SIZE: usize = 208;
assert!(
size <= MAX_CALL_SIZE,
"size of RuntimeCall {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the
size of RuntimeCall.
If the limit is too strong, maybe consider increase the limit to 300.",
size,
);
size
}
const TRANSFER_RAW : &[u8]= &hex!("b4040600008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4813000064a7b3b6e00d");
/// Creates a transfer tx of 1 AVAIL to Bob.
fn transfer_expected() -> RuntimeCall {
RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death {
dest: MultiAddress::Id(Bob.to_account_id()),
value: AVAIL,
})
}
const SET_TIMESTAMP_RAW: &[u8] = &hex!("280403000ba302ac318301");
// `set_timestamp` extrinsic from block 13852 on DevNet.
fn set_timestamp_expected() -> RuntimeCall {
RuntimeCall::Timestamp(pallet_timestamp::Call::set {
now: 1_662_985_700_003,
})
}
#[test_case( &TRANSFER_RAW => transfer_expected(); "Transfer 1 AVAIL to Bob")]
#[test_case( &SET_TIMESTAMP_RAW => set_timestamp_expected(); "set_timestamp_block_242")]
fn decode_app_unchecked_extrinsics(mut raw_ext: &[u8]) -> RuntimeCall {
use codec::Decode;
let app_ext = UncheckedExtrinsic::decode(&mut raw_ext).expect("Valid raw extrinsic .qed");
app_ext.function
}
}