diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 72691f20..308af213 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -69,7 +69,7 @@ jobs: uses: ./.github/actions/build-dependencies - name: Buld Rust docs run: | - rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c rust-docs + rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c rust-docs -c rust-src RUSTDOCFLAGS="--cfg docsrs" cargo +${{ steps.nightly.outputs.version }} doc --workspace --all-features mv target/doc docs/_site/rust diff --git a/substrate/abi/src/transaction.rs b/substrate/abi/src/transaction.rs index 9e9743fc..cab35409 100644 --- a/substrate/abi/src/transaction.rs +++ b/substrate/abi/src/transaction.rs @@ -268,7 +268,7 @@ mod substrate { >; /// The implicit context to verify transactions with. - fn implicit_context() -> &'static ImplicitContext; + fn implicit_context() -> ImplicitContext; /// If a block is present in the blockchain. fn block_is_present_in_blockchain(&self, hash: &BlockHash) -> bool; @@ -276,8 +276,8 @@ mod substrate { /// /// Returns `None` if the time has yet to be set. fn current_time(&self) -> Option; - /// The next nonce for an account. - fn next_nonce(&self, signer: &SeraiAddress) -> u32; + /// Get, and consume, the next nonce for an account. + fn get_and_consume_next_nonce(&self, signer: &SeraiAddress) -> u32; /// If the signer can pay the SRI fee. fn can_pay_fee( &self, @@ -339,7 +339,7 @@ mod substrate { contextualized_signature: ContextualizedSignature { explicit_context, signature }, } => { if !sp_core::sr25519::Signature::from(*signature).verify( - Transaction::signature_message(calls, Context::implicit_context(), explicit_context) + Transaction::signature_message(calls, &Context::implicit_context(), explicit_context) .as_slice(), &sp_core::sr25519::Public::from(explicit_context.signer), ) { @@ -402,7 +402,7 @@ mod substrate { Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?; } } - match self.1.next_nonce(signer).cmp(nonce) { + match self.1.get_and_consume_next_nonce(signer).cmp(nonce) { core::cmp::Ordering::Less => { Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))? } @@ -454,6 +454,7 @@ mod substrate { self.1.can_pay_fee(signer, *fee)?; // Prioritize transactions by their fees + // TODO: Re-evaluate this { let fee = fee.0; Weight::from_all(fee).checked_div_per_component(&info.call_weight).unwrap_or(0) diff --git a/substrate/primitives/src/address.rs b/substrate/primitives/src/address.rs index 81bf44e1..ee771777 100644 --- a/substrate/primitives/src/address.rs +++ b/substrate/primitives/src/address.rs @@ -27,6 +27,10 @@ const HUMAN_READABLE_PART: bech32::Hrp = bech32::Hrp::parse_unchecked("sri"); #[derive(scale::Encode, scale::Decode)] // This is safe as scale and borsh share an encoding here pub struct SeraiAddress(pub [u8; 32]); +// These share encodings as 32-byte arrays +impl scale::EncodeLike for SeraiAddress {} +impl scale::EncodeLike for &SeraiAddress {} + impl SeraiAddress { /// Generate an address for use by the system. /// diff --git a/substrate/primitives/src/lib.rs b/substrate/primitives/src/lib.rs index 27a5f906..dcf0260f 100644 --- a/substrate/primitives/src/lib.rs +++ b/substrate/primitives/src/lib.rs @@ -48,9 +48,7 @@ pub mod instructions; /// A block's number is its zero-indexed position on the list of blocks which form a blockchain. /// For non-linear structures, this would presumably be the zero-indexed position within some /// topological order. -#[derive( - Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize, -)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)] pub struct BlockNumber(pub u64); impl From for BlockNumber { fn from(number: u64) -> BlockNumber { @@ -66,6 +64,8 @@ impl From for BlockNumber { hash it into a 32-byte hash or truncate it. */ #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)] +#[rustfmt::skip] +#[derive(scale::Encode, scale::Decode)] // This is safe as scale and borsh share an encoding here pub struct BlockHash(pub [u8; 32]); impl From<[u8; 32]> for BlockHash { fn from(hash: [u8; 32]) -> BlockHash { @@ -77,3 +77,7 @@ impl From for BlockHash { BlockHash(hash.into()) } } + +// These share encodings as 32-byte arrays +impl scale::EncodeLike for BlockHash {} +impl scale::EncodeLike for &BlockHash {} diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index 0009c802..13a03bdb 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "serai-runtime" version = "0.1.0" -description = "Serai network node runtime, built over Substrate" +description = "Serai's on-chain logic" license = "AGPL-3.0-only" repository = "https://github.com/serai-dex/serai/tree/develop/substrate/runtime" authors = ["Luke Parker "] @@ -18,61 +18,19 @@ ignored = ["scale", "scale-info"] workspace = true [dependencies] -hashbrown = { version = "0.15", default-features = false, features = ["default-hasher", "inline-more"] } - scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } sp-core = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -sp-std = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -sp-offchain = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } sp-version = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -sp-inherents = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -sp-session = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -sp-consensus-babe = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -sp-consensus-grandpa = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -sp-authority-discovery = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -sp-transaction-pool = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -sp-block-builder = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - sp-runtime = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } sp-api = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } frame-system = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } frame-support = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } frame-executive = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -frame-benchmarking = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false, optional = true } -serai-primitives = { path = "../primitives", default-features = false } -serai-abi = { path = "../abi", default-features = false } - -pallet-timestamp = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -pallet-authorship = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -pallet-transaction-payment = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -coins-pallet = { package = "serai-coins-pallet", path = "../coins/pallet", default-features = false } -dex-pallet = { package = "serai-dex-pallet", path = "../dex/pallet", default-features = false } - -validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets/pallet", default-features = false } -genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../genesis-liquidity/pallet", default-features = false } -emissions-pallet = { package = "serai-emissions-pallet", path = "../emissions/pallet", default-features = false } - -economic-security-pallet = { package = "serai-economic-security-pallet", path = "../economic-security/pallet", default-features = false } - -in-instructions-pallet = { package = "serai-in-instructions-pallet", path = "../in-instructions/pallet", default-features = false } - -signals-pallet = { package = "serai-signals-pallet", path = "../signals/pallet", default-features = false } - -pallet-babe = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -pallet-grandpa = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } - -frame-system-rpc-runtime-api = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false } +serai-abi = { path = "../abi", default-features = false, features = ["substrate"] } [build-dependencies] substrate-wasm-builder = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next" } @@ -83,21 +41,7 @@ std = [ "scale-info/std", "sp-core/std", - "sp-std/std", - - "sp-offchain/std", "sp-version/std", - "sp-inherents/std", - - "sp-session/std", - "sp-consensus-babe/std", - "sp-consensus-grandpa/std", - - "sp-authority-discovery/std", - - "sp-transaction-pool/std", - "sp-block-builder/std", - "sp-runtime/std", "sp-api/std", @@ -105,50 +49,12 @@ std = [ "frame-support/std", "frame-executive/std", - "serai-primitives/std", "serai-abi/std", - - "pallet-timestamp/std", - "pallet-authorship/std", - - "pallet-transaction-payment/std", - - "coins-pallet/std", - "dex-pallet/std", - - "validator-sets-pallet/std", - "genesis-liquidity-pallet/std", - "emissions-pallet/std", - - "economic-security-pallet/std", - - "in-instructions-pallet/std", - - "signals-pallet/std", - - "pallet-babe/std", - "pallet-grandpa/std", - - "frame-system-rpc-runtime-api/std", - "pallet-transaction-payment-rpc-runtime-api/std", ] -fast-epoch = [ - "genesis-liquidity-pallet/fast-epoch", - "emissions-pallet/fast-epoch", -] +fast-epoch = [] # TODO -runtime-benchmarks = [ - "sp-runtime/runtime-benchmarks", - - "frame-system/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - - "pallet-timestamp/runtime-benchmarks", - - "pallet-babe/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", -] +try-runtime = ["sp-runtime/try-runtime", "frame-system/try-runtime", "frame-support/try-runtime", "frame-executive/try-runtime"] +runtime-benchmarks = ["sp-runtime/runtime-benchmarks", "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks"] default = ["std"] diff --git a/substrate/runtime/src/abi.rs b/substrate/runtime/src/abi.rs deleted file mode 100644 index ccf17259..00000000 --- a/substrate/runtime/src/abi.rs +++ /dev/null @@ -1,365 +0,0 @@ -use core::marker::PhantomData; - -use scale::{Encode, Decode}; - -use serai_abi::Call; - -use crate::{ - timestamp, coins, dex, genesis_liquidity, - validator_sets::{self, MembershipProof}, - in_instructions, signals, babe, grandpa, RuntimeCall, -}; - -impl From for RuntimeCall { - fn from(call: Call) -> RuntimeCall { - match call { - Call::Timestamp(serai_abi::timestamp::Call::set { now }) => { - RuntimeCall::Timestamp(timestamp::Call::set { now }) - } - Call::Coins(coins) => match coins { - serai_abi::coins::Call::transfer { to, balance } => { - RuntimeCall::Coins(coins::Call::transfer { to: to.into(), balance }) - } - serai_abi::coins::Call::burn { balance } => { - RuntimeCall::Coins(coins::Call::burn { balance }) - } - serai_abi::coins::Call::burn_with_instruction { instruction } => { - RuntimeCall::Coins(coins::Call::burn_with_instruction { instruction }) - } - }, - Call::LiquidityTokens(lt) => match lt { - serai_abi::liquidity_tokens::Call::transfer { to, balance } => { - RuntimeCall::LiquidityTokens(coins::Call::transfer { to: to.into(), balance }) - } - serai_abi::liquidity_tokens::Call::burn { balance } => { - RuntimeCall::LiquidityTokens(coins::Call::burn { balance }) - } - }, - Call::Dex(dex) => match dex { - serai_abi::dex::Call::add_liquidity { - coin, - coin_desired, - sri_desired, - coin_min, - sri_min, - mint_to, - } => RuntimeCall::Dex(dex::Call::add_liquidity { - coin, - coin_desired, - sri_desired, - coin_min, - sri_min, - mint_to: mint_to.into(), - }), - serai_abi::dex::Call::remove_liquidity { - coin, - lp_token_burn, - coin_min_receive, - sri_min_receive, - withdraw_to, - } => RuntimeCall::Dex(dex::Call::remove_liquidity { - coin, - lp_token_burn, - coin_min_receive, - sri_min_receive, - withdraw_to: withdraw_to.into(), - }), - serai_abi::dex::Call::swap_exact_tokens_for_tokens { - path, - amount_in, - amount_out_min, - send_to, - } => RuntimeCall::Dex(dex::Call::swap_exact_tokens_for_tokens { - path, - amount_in, - amount_out_min, - send_to: send_to.into(), - }), - serai_abi::dex::Call::swap_tokens_for_exact_tokens { - path, - amount_out, - amount_in_max, - send_to, - } => RuntimeCall::Dex(dex::Call::swap_tokens_for_exact_tokens { - path, - amount_out, - amount_in_max, - send_to: send_to.into(), - }), - }, - Call::ValidatorSets(vs) => match vs { - serai_abi::validator_sets::Call::set_keys { - network, - key_pair, - signature_participants, - signature, - } => RuntimeCall::ValidatorSets(validator_sets::Call::set_keys { - network, - key_pair, - signature_participants, - signature, - }), - serai_abi::validator_sets::Call::set_embedded_elliptic_curve_key { - embedded_elliptic_curve, - key, - } => RuntimeCall::ValidatorSets(validator_sets::Call::set_embedded_elliptic_curve_key { - embedded_elliptic_curve, - key, - }), - serai_abi::validator_sets::Call::report_slashes { network, slashes, signature } => { - RuntimeCall::ValidatorSets(validator_sets::Call::report_slashes { - network, - slashes, - signature, - }) - } - serai_abi::validator_sets::Call::allocate { network, amount } => { - RuntimeCall::ValidatorSets(validator_sets::Call::allocate { network, amount }) - } - serai_abi::validator_sets::Call::deallocate { network, amount } => { - RuntimeCall::ValidatorSets(validator_sets::Call::deallocate { network, amount }) - } - serai_abi::validator_sets::Call::claim_deallocation { network, session } => { - RuntimeCall::ValidatorSets(validator_sets::Call::claim_deallocation { network, session }) - } - }, - Call::GenesisLiquidity(gl) => match gl { - serai_abi::genesis_liquidity::Call::remove_coin_liquidity { balance } => { - RuntimeCall::GenesisLiquidity(genesis_liquidity::Call::remove_coin_liquidity { balance }) - } - serai_abi::genesis_liquidity::Call::oraclize_values { values, signature } => { - RuntimeCall::GenesisLiquidity(genesis_liquidity::Call::oraclize_values { - values, - signature, - }) - } - }, - Call::InInstructions(ii) => match ii { - serai_abi::in_instructions::Call::execute_batch { batch } => { - RuntimeCall::InInstructions(in_instructions::Call::execute_batch { batch }) - } - }, - Call::Signals(signals) => match signals { - serai_abi::signals::Call::register_retirement_signal { in_favor_of } => { - RuntimeCall::Signals(signals::Call::register_retirement_signal { in_favor_of }) - } - serai_abi::signals::Call::revoke_retirement_signal { retirement_signal_id } => { - RuntimeCall::Signals(signals::Call::revoke_retirement_signal { retirement_signal_id }) - } - serai_abi::signals::Call::favor { signal_id, for_network } => { - RuntimeCall::Signals(signals::Call::favor { signal_id, for_network }) - } - serai_abi::signals::Call::revoke_favor { signal_id, for_network } => { - RuntimeCall::Signals(signals::Call::revoke_favor { signal_id, for_network }) - } - serai_abi::signals::Call::stand_against { signal_id, for_network } => { - RuntimeCall::Signals(signals::Call::stand_against { signal_id, for_network }) - } - }, - Call::Babe(babe) => match babe { - serai_abi::babe::Call::report_equivocation(report) => { - RuntimeCall::Babe(babe::Call::report_equivocation { - // TODO: Find a better way to go from Proof<[u8; 32]> to Proof - equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice()) - .unwrap(), - key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData), - }) - } - serai_abi::babe::Call::report_equivocation_unsigned(report) => { - RuntimeCall::Babe(babe::Call::report_equivocation_unsigned { - // TODO: Find a better way to go from Proof<[u8; 32]> to Proof - equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice()) - .unwrap(), - key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData), - }) - } - }, - Call::Grandpa(grandpa) => match grandpa { - serai_abi::grandpa::Call::report_equivocation(report) => { - RuntimeCall::Grandpa(grandpa::Call::report_equivocation { - // TODO: Find a better way to go from Proof<[u8; 32]> to Proof - equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice()) - .unwrap(), - key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData), - }) - } - serai_abi::grandpa::Call::report_equivocation_unsigned(report) => { - RuntimeCall::Grandpa(grandpa::Call::report_equivocation_unsigned { - // TODO: Find a better way to go from Proof<[u8; 32]> to Proof - equivocation_proof: <_>::decode(&mut report.equivocation_proof.encode().as_slice()) - .unwrap(), - key_owner_proof: MembershipProof(report.key_owner_proof.into(), PhantomData), - }) - } - }, - } - } -} - -impl TryInto for RuntimeCall { - type Error = (); - - fn try_into(self) -> Result { - Ok(match self { - RuntimeCall::Timestamp(timestamp::Call::set { now }) => { - Call::Timestamp(serai_abi::timestamp::Call::set { now }) - } - RuntimeCall::Coins(call) => Call::Coins(match call { - coins::Call::transfer { to, balance } => { - serai_abi::coins::Call::transfer { to: to.into(), balance } - } - coins::Call::burn { balance } => serai_abi::coins::Call::burn { balance }, - coins::Call::burn_with_instruction { instruction } => { - serai_abi::coins::Call::burn_with_instruction { instruction } - } - }), - RuntimeCall::LiquidityTokens(call) => Call::LiquidityTokens(match call { - coins::Call::transfer { to, balance } => { - serai_abi::liquidity_tokens::Call::transfer { to: to.into(), balance } - } - coins::Call::burn { balance } => serai_abi::liquidity_tokens::Call::burn { balance }, - _ => Err(())?, - }), - RuntimeCall::Dex(call) => Call::Dex(match call { - dex::Call::add_liquidity { - coin, - coin_desired, - sri_desired, - coin_min, - sri_min, - mint_to, - } => serai_abi::dex::Call::add_liquidity { - coin, - coin_desired, - sri_desired, - coin_min, - sri_min, - mint_to: mint_to.into(), - }, - dex::Call::remove_liquidity { - coin, - lp_token_burn, - coin_min_receive, - sri_min_receive, - withdraw_to, - } => serai_abi::dex::Call::remove_liquidity { - coin, - lp_token_burn, - coin_min_receive, - sri_min_receive, - withdraw_to: withdraw_to.into(), - }, - dex::Call::swap_exact_tokens_for_tokens { path, amount_in, amount_out_min, send_to } => { - serai_abi::dex::Call::swap_exact_tokens_for_tokens { - path, - amount_in, - amount_out_min, - send_to: send_to.into(), - } - } - dex::Call::swap_tokens_for_exact_tokens { path, amount_out, amount_in_max, send_to } => { - serai_abi::dex::Call::swap_tokens_for_exact_tokens { - path, - amount_out, - amount_in_max, - send_to: send_to.into(), - } - } - }), - RuntimeCall::GenesisLiquidity(call) => Call::GenesisLiquidity(match call { - genesis_liquidity::Call::remove_coin_liquidity { balance } => { - serai_abi::genesis_liquidity::Call::remove_coin_liquidity { balance } - } - genesis_liquidity::Call::oraclize_values { values, signature } => { - serai_abi::genesis_liquidity::Call::oraclize_values { values, signature } - } - }), - RuntimeCall::ValidatorSets(call) => Call::ValidatorSets(match call { - validator_sets::Call::set_keys { network, key_pair, signature_participants, signature } => { - serai_abi::validator_sets::Call::set_keys { - network, - key_pair, - signature_participants, - signature, - } - } - validator_sets::Call::set_embedded_elliptic_curve_key { embedded_elliptic_curve, key } => { - serai_abi::validator_sets::Call::set_embedded_elliptic_curve_key { - embedded_elliptic_curve, - key, - } - } - validator_sets::Call::report_slashes { network, slashes, signature } => { - serai_abi::validator_sets::Call::report_slashes { network, slashes, signature } - } - validator_sets::Call::allocate { network, amount } => { - serai_abi::validator_sets::Call::allocate { network, amount } - } - validator_sets::Call::deallocate { network, amount } => { - serai_abi::validator_sets::Call::deallocate { network, amount } - } - validator_sets::Call::claim_deallocation { network, session } => { - serai_abi::validator_sets::Call::claim_deallocation { network, session } - } - }), - RuntimeCall::InInstructions(call) => Call::InInstructions(match call { - in_instructions::Call::execute_batch { batch } => { - serai_abi::in_instructions::Call::execute_batch { batch } - } - }), - RuntimeCall::Signals(call) => Call::Signals(match call { - signals::Call::register_retirement_signal { in_favor_of } => { - serai_abi::signals::Call::register_retirement_signal { in_favor_of } - } - signals::Call::revoke_retirement_signal { retirement_signal_id } => { - serai_abi::signals::Call::revoke_retirement_signal { retirement_signal_id } - } - signals::Call::favor { signal_id, for_network } => { - serai_abi::signals::Call::favor { signal_id, for_network } - } - signals::Call::revoke_favor { signal_id, for_network } => { - serai_abi::signals::Call::revoke_favor { signal_id, for_network } - } - signals::Call::stand_against { signal_id, for_network } => { - serai_abi::signals::Call::stand_against { signal_id, for_network } - } - }), - RuntimeCall::Babe(call) => Call::Babe(match call { - babe::Call::report_equivocation { equivocation_proof, key_owner_proof } => { - serai_abi::babe::Call::report_equivocation(serai_abi::babe::ReportEquivocation { - // TODO: Find a better way to go from Proof to Proof<[u8; 32]> - equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(), - key_owner_proof: key_owner_proof.0.into(), - }) - } - babe::Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } => { - serai_abi::babe::Call::report_equivocation_unsigned(serai_abi::babe::ReportEquivocation { - // TODO: Find a better way to go from Proof to Proof<[u8; 32]> - equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(), - key_owner_proof: key_owner_proof.0.into(), - }) - } - _ => Err(())?, - }), - RuntimeCall::Grandpa(call) => Call::Grandpa(match call { - grandpa::Call::report_equivocation { equivocation_proof, key_owner_proof } => { - serai_abi::grandpa::Call::report_equivocation(serai_abi::grandpa::ReportEquivocation { - // TODO: Find a better way to go from Proof to Proof<[u8; 32]> - equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(), - key_owner_proof: key_owner_proof.0.into(), - }) - } - grandpa::Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } => { - serai_abi::grandpa::Call::report_equivocation_unsigned( - serai_abi::grandpa::ReportEquivocation { - // TODO: Find a better way to go from Proof to Proof<[u8; 32]> - equivocation_proof: <_>::decode(&mut equivocation_proof.encode().as_slice()).unwrap(), - key_owner_proof: key_owner_proof.0.into(), - }, - ) - } - _ => Err(())?, - }), - }) - } -} diff --git a/substrate/runtime/src/core_pallet.rs b/substrate/runtime/src/core_pallet.rs new file mode 100644 index 00000000..e1febb30 --- /dev/null +++ b/substrate/runtime/src/core_pallet.rs @@ -0,0 +1,19 @@ +#[frame_support::pallet] +mod core_pallet { + use ::alloc::*; + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; + + #[pallet::storage] + pub type NextNonce = + StorageMap<_, Blake2_128Concat, T::AccountId, T::Nonce, ValueQuery>; + #[pallet::storage] + pub type Blocks = StorageMap<_, Identity, T::Hash, (), OptionQuery>; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} +pub(super) use core_pallet::*; diff --git a/substrate/runtime/src/lib.rs b/substrate/runtime/src/lib.rs index f2f3f91f..542f7eac 100644 --- a/substrate/runtime/src/lib.rs +++ b/substrate/runtime/src/lib.rs @@ -1,11 +1,261 @@ -#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit = "256"] #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + +use ::alloc::{borrow::Cow, vec::Vec}; + +use sp_core::sr25519::Public; +use sp_runtime::{Perbill, Weight, traits::Header as _}; +use sp_version::RuntimeVersion; + +#[rustfmt::skip] +use serai_abi::{ + primitives::address::SeraiAddress, SubstrateHeader as Header, SubstrateBlock, +}; + +mod core_pallet; + +type Block = SubstrateBlock; + +/// 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 { + 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(0, Perbill::from_percent(0)); + // TODO + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::with_sensible_defaults( + Weight::from_parts(0, 0), + Perbill::from_percent(0), + ); +} + +#[frame_support::runtime] +mod runtime { + use super::*; + + #[runtime::runtime] + #[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeError, RuntimeOrigin)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system::Pallet; + + #[runtime::pallet_index(1)] + pub type Core = core_pallet::Pallet; +} + +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 RuntimeTask = (); + type Nonce = u32; + type Hash = ::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 = sp_core::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 = sp_core::ConstU32<{ u32::MAX }>; + // No migrations set + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + // We don't define any block-level hooks at this time + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl core_pallet::Config for Runtime {} + +impl From> for RuntimeOrigin { + fn from(signer: Option) -> Self { + match signer { + None => RuntimeOrigin::none(), + Some(signer) => RuntimeOrigin::signed(signer.into()), + } + } +} + +impl From for RuntimeCall { + fn from(call: serai_abi::Call) -> Self { + match call { + serai_abi::Call::Coins(call) => { + use serai_abi::coins::Call; + match call { + Call::transfer { .. } | Call::burn { .. } | Call::burn_with_instruction { .. } => { + todo!("TODO") + } + } + } + serai_abi::Call::ValidatorSets(call) => { + use serai_abi::validator_sets::Call; + match call { + Call::set_keys { .. } | + Call::report_slashes { .. } | + Call::set_embedded_elliptic_curve_keys { .. } | + Call::allocate { .. } | + Call::deallocate { .. } | + Call::claim_deallocation { .. } => todo!("TODO"), + } + } + serai_abi::Call::Signals(call) => { + use serai_abi::signals::Call; + match call { + Call::register_retirement_signal { .. } | + Call::revoke_retirement_signal { .. } | + Call::favor { .. } | + Call::revoke_favor { .. } | + Call::stand_against { .. } => todo!("TODO"), + } + } + serai_abi::Call::Dex(call) => { + use serai_abi::dex::Call; + match call { + Call::add_liquidity { .. } | + Call::transfer_liquidity { .. } | + Call::remove_liquidity { .. } | + Call::swap_exact { .. } | + Call::swap_for_exact { .. } => todo!("TODO"), + } + } + serai_abi::Call::GenesisLiquidity(call) => { + use serai_abi::genesis_liquidity::Call; + match call { + Call::oraclize_values { .. } | Call::remove_liquidity { .. } => todo!("TODO"), + } + } + serai_abi::Call::InInstructions(call) => { + use serai_abi::in_instructions::Call; + match call { + Call::execute_batch { .. } => todo!("TODO"), + } + } + } + } +} + +type Executive = frame_executive::Executive; + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + fn initialize_block(header: &Header) -> sp_runtime::ExtrinsicInclusionMode { + core_pallet::Blocks::::set(header.parent_hash(), Some(())); + Executive::initialize_block(header) + } + fn execute_block(block: Block) { + Executive::execute_block(block); + } + } +} + +#[derive(Clone, Default, PartialEq, Eq, Debug)] +struct Context; +impl serai_abi::TransactionContext for Context { + // TODO + const SIGNED_WEIGHT: Weight = Weight::zero(); + + type RuntimeCall = RuntimeCall; + + /// The implicit context to verify transactions with. + fn implicit_context() -> serai_abi::ImplicitContext { + serai_abi::ImplicitContext { + genesis: System::block_hash(0).into(), + protocol_id: [0; 32], // TODO via build script + } + } + + /// If a block is present in the blockchain. + fn block_is_present_in_blockchain(&self, hash: &serai_abi::primitives::BlockHash) -> bool { + core_pallet::Blocks::::get(hash).is_some() + } + /// The time embedded into the current block. + fn current_time(&self) -> Option { + todo!("TODO") + } + /// Get, and consume, the next nonce for an account. + fn get_and_consume_next_nonce(&self, signer: &SeraiAddress) -> u32 { + core_pallet::NextNonce::::mutate(signer, |value| { + // Copy the current value for the next nonce + let next_nonce = *value; + // Increment the next nonce in the DB, consuming the current value + *value += 1; + // Return the existing value + next_nonce + }) + } + /// If the signer can pay the SRI fee. + fn can_pay_fee( + &self, + signer: &SeraiAddress, + fee: serai_abi::primitives::balance::Amount, + ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + todo!("TODO") + } + /// Have the transaction pay its SRI fee. + fn pay_fee( + &self, + signer: &SeraiAddress, + fee: serai_abi::primitives::balance::Amount, + ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + todo!("TODO") + } +} + +/* use core::marker::PhantomData; // Re-export all components @@ -73,29 +323,14 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use babe::AuthorityId as BabeId; use grandpa::AuthorityId as GrandpaId; -mod abi; - -/// Nonce of a transaction in the chain, for a given account. -pub type Nonce = u32; - /// A hash of some data used by the chain. pub type Hash = sp_core::H256; pub type SignedExtra = ( system::CheckNonZeroSender, - system::CheckSpecVersion, - system::CheckTxVersion, - system::CheckGenesis, - system::CheckEra, - system::CheckNonce, - system::CheckWeight, - transaction_payment::ChargeTransactionPayment, + system::CheckWeight, TODO ); -pub type Transaction = serai_abi::tx::Transaction; -pub type Block = generic::Block; -pub type BlockId = generic::BlockId; - pub mod opaque { use super::*; @@ -107,22 +342,6 @@ pub mod opaque { } } -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("serai"), - impl_name: create_runtime_str!("core"), - spec_version: 1, - impl_version: 1, - apis: RUNTIME_API_VERSIONS, - transaction_version: 1, - state_version: 1, -}; - -#[cfg(feature = "std")] -pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } -} - pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration = sp_consensus_babe::BabeEpochConfiguration { @@ -133,7 +352,6 @@ pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration = const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { - pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; pub const SS58Prefix: u8 = 42; // TODO: Remove for Bech32m @@ -148,44 +366,6 @@ parameter_types! { ); } -pub struct CallFilter; -impl Contains for CallFilter { - fn contains(call: &RuntimeCall) -> bool { - // If the call is defined in our ABI, it's allowed - let call: Result = call.clone().try_into(); - call.is_ok() - } -} - -impl system::Config for Runtime { - type BaseCallFilter = CallFilter; - type BlockWeights = BlockWeights; - type BlockLength = BlockLength; - type AccountId = PublicKey; - type RuntimeCall = RuntimeCall; - type Lookup = AccountLookup; - type Hash = Hash; - type Hashing = BlakeTwo256; - type Nonce = Nonce; - type Block = Block; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = RocksDbWeight; - type Version = Version; - type PalletInfo = PalletInfo; - - type OnNewAccount = (); - type OnKilledAccount = (); - type OnSetCode = (); - - type AccountData = (); - type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; // TODO: Remove for Bech32m - - type MaxConsumers = support::traits::ConstU32<16>; -} - impl timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Babe; @@ -319,14 +499,6 @@ impl grandpa::Config for Runtime { grandpa::EquivocationReportSystem; } -pub type Executive = frame_executive::Executive< - Runtime, - Block, - system::ChainContext, - Runtime, - AllPalletsWithSystem, ->; - construct_runtime!( pub enum Runtime { System: system exclude_parts { Call }, @@ -627,3 +799,4 @@ sp_api::impl_runtime_apis! { } } } +*/