Skip to main content

substrate_runtime/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::disallowed_macros)]
3
4// Make the WASM binary available.
5#[cfg(feature = "std")]
6include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
7
8extern crate alloc;
9
10use crate::sp_runtime::ConsensusEngineId;
11use alloc::{vec, vec::Vec};
12use currency::*;
13use frame_support::weights::{
14    Weight,
15    constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_REF_TIME_PER_SECOND},
16};
17use frame_system::limits::BlockWeights;
18use pallet_revive::{
19    AccountId32Mapper,
20    evm::{
21        fees::{BlockRatioFee, Info as FeeInfo},
22        runtime::EthExtra,
23    },
24};
25use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
26use polkadot_sdk::{
27    parachains_common::{
28        AccountId, AssetHubPolkadotAuraId as AuraId, BlockNumber, Hash as CommonHash, Header,
29        Nonce, Signature,
30    },
31    polkadot_runtime_common::SlowAdjustingFeeUpdate,
32    polkadot_sdk_frame::{
33        deps::sp_genesis_builder,
34        runtime::{apis, prelude::*},
35        traits::FindAuthor,
36    },
37    sp_consensus_aura::{self, SlotDuration, runtime_decl_for_aura_api::AuraApiV1},
38    sp_runtime::traits::Block as BlockT,
39    *,
40};
41
42pub use polkadot_sdk::parachains_common::Balance;
43use sp_weights::ConstantMultiplier;
44
45pub mod constants {
46    /// DOT precision (1e12) to ETH precision (1e18) ratio.
47    pub const NATIVE_TO_ETH_RATIO: u32 = 1_000_000;
48}
49
50pub mod currency {
51    use super::Balance;
52    pub const DOLLARS: Balance = 1_000_000_000_000;
53    pub const CENTS: Balance = DOLLARS / 100;
54    pub const MILLICENTS: Balance = CENTS / 1_000;
55}
56
57/// The runtime version.
58#[runtime_version]
59pub const VERSION: RuntimeVersion = RuntimeVersion {
60    spec_name: alloc::borrow::Cow::Borrowed("revive-dev-runtime"),
61    impl_name: alloc::borrow::Cow::Borrowed("revive-dev-runtime"),
62    authoring_version: 1,
63    spec_version: 0,
64    impl_version: 1,
65    apis: RUNTIME_API_VERSIONS,
66    transaction_version: 1,
67    system_version: 1,
68};
69
70/// The version information used to identify this runtime when compiled natively.
71#[cfg(feature = "std")]
72pub fn native_version() -> NativeVersion {
73    NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
74}
75
76/// The address format for describing accounts.
77pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
78/// Block type as expected by this runtime.
79pub type Block = sp_runtime::generic::Block<Header, UncheckedExtrinsic>;
80/// Hash type used by the runtime.
81pub type Hash = <Runtime as frame_system::Config>::Hash;
82/// The transaction extensions that are added to the runtime.
83type TxExtension = (
84    // Checks that the sender is not the zero address.
85    frame_system::CheckNonZeroSender<Runtime>,
86    // Checks that the runtime version is correct.
87    frame_system::CheckSpecVersion<Runtime>,
88    // Checks that the transaction version is correct.
89    frame_system::CheckTxVersion<Runtime>,
90    // Checks that the genesis hash is correct.
91    frame_system::CheckGenesis<Runtime>,
92    // Checks that the era is valid.
93    frame_system::CheckEra<Runtime>,
94    // Checks that the nonce is valid.
95    frame_system::CheckNonce<Runtime>,
96    // Checks that the weight is valid.
97    frame_system::CheckWeight<Runtime>,
98    // Ensures that the sender has enough funds to pay for the transaction
99    // and deducts the fee from the sender's account.
100    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
101    // Needs to be done after all extensions that rely on a signed origin.
102    pallet_revive::evm::tx_extension::SetOrigin<Runtime>,
103    // Reclaim the unused weight from the block using post dispatch information.
104    // It must be last in the pipeline in order to catch the refund in previous transaction
105    // extensions
106    frame_system::WeightReclaim<Runtime>,
107);
108
109/// Default extensions applied to Ethereum transactions.
110#[derive(Clone, PartialEq, Eq, Debug)]
111pub struct EthExtraImpl;
112
113impl EthExtra for EthExtraImpl {
114    type Config = Runtime;
115    type Extension = TxExtension;
116
117    fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension {
118        (
119            frame_system::CheckNonZeroSender::<Runtime>::new(),
120            frame_system::CheckSpecVersion::<Runtime>::new(),
121            frame_system::CheckTxVersion::<Runtime>::new(),
122            frame_system::CheckGenesis::<Runtime>::new(),
123            frame_system::CheckMortality::from(sp_runtime::generic::Era::Immortal),
124            frame_system::CheckNonce::<Runtime>::from(nonce),
125            frame_system::CheckWeight::<Runtime>::new(),
126            pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
127            pallet_revive::evm::tx_extension::SetOrigin::<Runtime>::new_from_eth_transaction(),
128            frame_system::WeightReclaim::<Runtime>::new(),
129        )
130    }
131}
132
133pub type UncheckedExtrinsic =
134    pallet_revive::evm::runtime::UncheckedExtrinsic<Address, Signature, EthExtraImpl>;
135
136type Executive = frame_executive::Executive<
137    Runtime,
138    Block,
139    frame_system::ChainContext<Runtime>,
140    Runtime,
141    AllPalletsWithSystem,
142>;
143
144#[frame_construct_runtime]
145// Composes the runtime by adding all the used pallets and deriving necessary types.
146mod runtime {
147    /// The main runtime type.
148    #[runtime::runtime]
149    #[runtime::derive(
150        RuntimeCall,
151        RuntimeEvent,
152        RuntimeError,
153        RuntimeOrigin,
154        RuntimeFreezeReason,
155        RuntimeHoldReason,
156        RuntimeSlashReason,
157        RuntimeLockId,
158        RuntimeTask,
159        RuntimeViewFunction
160    )]
161    pub struct Runtime;
162
163    /// Mandatory system pallet that should always be included in a FRAME runtime.
164    #[runtime::pallet_index(0)]
165    pub type System = frame_system::Pallet<Runtime>;
166
167    /// Provides a way for consensus systems to set and check the onchain time.
168    #[runtime::pallet_index(1)]
169    pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
170
171    /// Provides the ability to keep track of balances.
172    #[runtime::pallet_index(2)]
173    pub type Balances = pallet_balances::Pallet<Runtime>;
174
175    /// Provides the ability to charge for extrinsic execution.
176    #[runtime::pallet_index(3)]
177    pub type TransactionPayment = pallet_transaction_payment::Pallet<Runtime>;
178
179    /// Provides the ability to execute Smart Contracts.
180    #[runtime::pallet_index(4)]
181    pub type Revive = pallet_revive::Pallet<Runtime>;
182
183    /// Provides the ability to determine AURA authorities for block building.
184    #[runtime::pallet_index(5)]
185    pub type Aura = pallet_aura::Pallet<Runtime>;
186}
187
188impl pallet_aura::Config for Runtime {
189    type AuthorityId = AuraId;
190    type DisabledValidators = ();
191    type MaxAuthorities = ConstU32<1>;
192    type AllowMultipleBlocksPerSlot = ConstBool<true>;
193    // Not relevant in general since the node digest
194    // will refer to slot 0 always.
195    type SlotDuration = ConstU64<6000>;
196}
197
198/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers.
199/// This is used to limit the maximal weight of a single extrinsic.
200const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
201/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
202/// by  Operational  extrinsics.
203const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
204/// We allow for 2 seconds of compute with a 6 second average block time, with maximum proof size.
205const MAXIMUM_BLOCK_WEIGHT: Weight =
206    Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
207
208parameter_types! {
209    pub const Version: RuntimeVersion = VERSION;
210    pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
211        .base_block(BlockExecutionWeight::get())
212        .for_class(DispatchClass::all(), |weights| {
213            weights.base_extrinsic = ExtrinsicBaseWeight::get();
214        })
215        .for_class(DispatchClass::Normal, |weights| {
216            weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
217        })
218        .for_class(DispatchClass::Operational, |weights| {
219            weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
220            // Operational transactions have some extra reserved space, so that they
221            // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
222            weights.reserved = Some(
223                MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
224            );
225        })
226        .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
227        .build_or_panic();
228}
229
230/// Implements the types required for the system pallet.
231#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
232impl frame_system::Config for Runtime {
233    type Block = Block;
234    type Version = Version;
235    type AccountId = AccountId;
236    type Hash = CommonHash;
237    type Nonce = Nonce;
238    type AccountData = pallet_balances::AccountData<<Runtime as pallet_balances::Config>::Balance>;
239}
240
241parameter_types! {
242    // As it is on Westend
243    pub const ExistentialDeposit: Balance = MILLICENTS;
244}
245
246// Implements the types required for the balances pallet.
247#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
248impl pallet_balances::Config for Runtime {
249    type AccountStore = System;
250    type Balance = Balance;
251    type ExistentialDeposit = ExistentialDeposit;
252}
253
254// Implements the types required for the timestamp pallet.
255#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
256impl pallet_timestamp::Config for Runtime {}
257
258parameter_types! {
259    // That's how asset-hub-westend sets this.
260    pub const TransactionByteFee: Balance = MILLICENTS;
261}
262
263// That's how asset-hub-westend sets this.
264pub type WeightToFee = BlockRatioFee<
265    // p
266    CENTS,
267    // q
268    { 100 * ExtrinsicBaseWeight::get().ref_time() as u128 },
269    Runtime,
270    Balance,
271>;
272
273// Implements the types required for the transaction payment pallet.
274#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)]
275impl pallet_transaction_payment::Config for Runtime {
276    type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter<Balances, ()>;
277    type WeightToFee = WeightToFee;
278    type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
279    // That's how asset-hub-westend sets this.
280    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
281}
282
283parameter_types! {
284    pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30);
285    pub storage ChainId: u64 = 420_420_420;
286}
287
288pub struct BlockAuthor;
289impl FindAuthor<AccountId> for BlockAuthor {
290    fn find_author<'a, I>(_digests: I) -> Option<AccountId>
291    where
292        I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
293    {
294        let authorities = Runtime::authorities();
295        authorities.first().map(|inner| inner.clone().into_inner().into())
296    }
297}
298
299#[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)]
300impl pallet_revive::Config for Runtime {
301    type AddressMapper = AccountId32Mapper<Self>;
302    type ChainId = ChainId;
303    type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
304    type Currency = Balances;
305    // TODO: make necessary changes so that we can use `pallet-aura`'s
306    // `FindAuthor` implementation. Main thing it requires is mocking
307    // the inherent data on the node side, effort already part of
308    // `forking` feature.
309    type FindAuthor = BlockAuthor;
310    type Balance = Balance;
311    type NativeToEthRatio = ConstU32<{ constants::NATIVE_TO_ETH_RATIO }>;
312    type UploadOrigin = EnsureSigned<Self::AccountId>;
313    type InstantiateOrigin = EnsureSigned<Self::AccountId>;
314    type Time = Timestamp;
315    type GasScale = ConstU32<1>;
316    type FeeInfo = FeeInfo<Address, Signature, EthExtraImpl>;
317    type DebugEnabled = ConstBool<true>;
318}
319
320pallet_revive::impl_runtime_apis_plus_revive_traits!(
321    Runtime,
322    Revive,
323    Executive,
324    EthExtraImpl,
325
326    impl apis::Core<Block> for Runtime {
327        fn version() -> RuntimeVersion {
328            VERSION
329        }
330
331        fn execute_block(block: <Block as BlockT>::LazyBlock) {
332            Executive::execute_block(block)
333        }
334
335        fn initialize_block(header: &Header) -> ExtrinsicInclusionMode {
336            Executive::initialize_block(header)
337        }
338    }
339
340    impl apis::Metadata<Block> for Runtime {
341        fn metadata() -> OpaqueMetadata {
342            OpaqueMetadata::new(Runtime::metadata().into())
343        }
344
345        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
346            Runtime::metadata_at_version(version)
347        }
348
349        fn metadata_versions() -> Vec<u32> {
350            Runtime::metadata_versions()
351        }
352    }
353
354    impl apis::BlockBuilder<Block> for Runtime {
355        fn apply_extrinsic(extrinsic: ExtrinsicFor<Runtime>) -> ApplyExtrinsicResult {
356            Executive::apply_extrinsic(extrinsic)
357        }
358
359        fn finalize_block() -> HeaderFor<Runtime> {
360            Executive::finalize_block()
361        }
362
363        fn inherent_extrinsics(data: InherentData) -> Vec<ExtrinsicFor<Runtime>> {
364            data.create_extrinsics()
365        }
366
367        fn check_inherents(
368            block: <Block as BlockT>::LazyBlock,
369            data: InherentData,
370        ) -> CheckInherentsResult {
371            data.check_extrinsics(&block)
372        }
373    }
374
375    impl apis::TaggedTransactionQueue<Block> for Runtime {
376        fn validate_transaction(
377            source: TransactionSource,
378            tx: ExtrinsicFor<Runtime>,
379            block_hash: <Runtime as frame_system::Config>::Hash,
380        ) -> TransactionValidity {
381            Executive::validate_transaction(source, tx, block_hash)
382        }
383    }
384
385    impl apis::OffchainWorkerApi<Block> for Runtime {
386        fn offchain_worker(header: &HeaderFor<Runtime>) {
387            Executive::offchain_worker(header)
388        }
389    }
390
391    impl apis::SessionKeys<Block> for Runtime {
392        fn generate_session_keys(_owner: Vec<u8>, _seed: Option<Vec<u8>>) -> apis::OpaqueGeneratedSessionKeys {
393            Default::default()
394        }
395
396        fn decode_session_keys(
397            _encoded: Vec<u8>,
398        ) -> Option<Vec<(Vec<u8>, apis::KeyTypeId)>> {
399            Default::default()
400        }
401    }
402
403    impl apis::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
404        fn account_nonce(account: AccountId) -> Nonce {
405            System::account_nonce(account)
406        }
407    }
408
409    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
410        Block,
411        Balance,
412    > for Runtime {
413        fn query_info(uxt: ExtrinsicFor<Runtime>, len: u32) -> RuntimeDispatchInfo<Balance> {
414            TransactionPayment::query_info(uxt, len)
415        }
416        fn query_fee_details(uxt: ExtrinsicFor<Runtime>, len: u32) -> FeeDetails<Balance> {
417            TransactionPayment::query_fee_details(uxt, len)
418        }
419        fn query_weight_to_fee(weight: Weight) -> Balance {
420            TransactionPayment::weight_to_fee(weight)
421        }
422        fn query_length_to_fee(length: u32) -> Balance {
423            TransactionPayment::length_to_fee(length)
424        }
425    }
426
427    impl apis::GenesisBuilder<Block> for Runtime {
428        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
429            build_state::<RuntimeGenesisConfig>(config)
430        }
431
432        fn get_preset(id: &Option<PresetId>) -> Option<Vec<u8>> {
433            get_preset::<RuntimeGenesisConfig>(id, |_| None)
434        }
435
436        fn preset_names() -> Vec<PresetId> {
437            vec![]
438        }
439    }
440
441    impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
442        fn slot_duration() -> SlotDuration {
443            // This is not relevant when considering a manual-seal
444            // driven node. The slot duration is used by Aura to determine
445            // the authority, but anvil-polkadot will provide a single slot
446            // always, not taking into consideration computing based on this
447            // runtime API.
448            SlotDuration::from_millis(6000)
449        }
450
451        fn authorities() -> Vec<AuraId> {
452            pallet_aura::Authorities::<Runtime>::get().into_inner()
453        }
454    }
455
456);