From c03a33d16898b0eecd37a2b053f45ca0c1ad70e8 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Thu, 11 Apr 2024 23:10:43 -0400 Subject: [PATCH] `parachainify!` macro (#199) * Introduce `parachainify!` macro. * Introduce `ParachainConstraintChecker` trait. * Persist block number in storage under new dedicated key. * Remove generic block parameter from Executive. It is now just Executive. * Create and use some type aliases like Header and Block in core. * Reduce definitions in parachain runtime, instead re-using more stuff from the original template. --- Cargo.lock | 5 +- Cargo.toml | 2 +- node/src/command.rs | 2 +- node/src/rpc.rs | 2 +- node/src/service.rs | 4 +- parachain-node/src/dev_service.rs | 4 +- parachain-node/src/rpc.rs | 2 +- parachain-node/src/service.rs | 11 +- tuxedo-core/src/executive.rs | 102 +++++++-------- tuxedo-core/src/genesis.rs | 5 +- tuxedo-core/src/types.rs | 16 ++- tuxedo-core/src/verifier/htlc.rs | 16 +-- tuxedo-parachain-core/Cargo.toml | 4 +- .../Cargo.toml | 4 +- .../src/lib.rs | 94 +++++++++----- tuxedo-parachain-core/src/collation_api.rs | 9 +- tuxedo-parachain-core/src/lib.rs | 27 ++-- tuxedo-parachain-core/src/validate_block.rs | 103 +++++---------- tuxedo-parachain-runtime/Cargo.toml | 10 +- tuxedo-parachain-runtime/src/genesis.rs | 6 +- tuxedo-parachain-runtime/src/lib.rs | 121 ++---------------- tuxedo-template-runtime/src/genesis.rs | 4 +- tuxedo-template-runtime/src/lib.rs | 34 +---- wallet/src/rpc.rs | 3 +- wallet/src/sync.rs | 6 +- wardrobe/parachain/src/lib.rs | 3 +- wardrobe/parachain/src/tests.rs | 4 +- 27 files changed, 232 insertions(+), 371 deletions(-) rename tuxedo-parachain-core/{register_validate_block => parachainify}/Cargo.toml (51%) rename tuxedo-parachain-core/{register_validate_block => parachainify}/src/lib.rs (55%) diff --git a/Cargo.lock b/Cargo.lock index 852714433..0b16093fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14016,7 +14016,7 @@ dependencies = [ "sp-trie", "trie-db", "tuxedo-core", - "tuxedo-register-validate-block", + "tuxedo-parachainify", ] [[package]] @@ -14035,7 +14035,6 @@ dependencies = [ "sp-application-crypto", "sp-block-builder", "sp-consensus-aura", - "sp-consensus-grandpa", "sp-core", "sp-debug-derive", "sp-inherents", @@ -14053,7 +14052,7 @@ dependencies = [ ] [[package]] -name = "tuxedo-register-validate-block" +name = "tuxedo-parachainify" version = "0.1.0" dependencies = [ "proc-macro-crate 1.3.1", diff --git a/Cargo.toml b/Cargo.toml index 89830d067..7a3b042da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "tuxedo-core", "tuxedo-core/aggregator", "tuxedo-core/no_bound", - "tuxedo-parachain-core/register_validate_block", + "tuxedo-parachain-core/parachainify", "tuxedo-parachain-core", "tuxedo-parachain-runtime", "wallet", diff --git a/node/src/command.rs b/node/src/command.rs index ae494605f..8ea42dd63 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -3,9 +3,9 @@ use crate::{ cli::{Cli, Subcommand}, service, }; -use node_template_runtime::opaque::Block as OpaqueBlock; use sc_cli::SubstrateCli; use sc_service::PartialComponents; +use tuxedo_core::types::OpaqueBlock; impl SubstrateCli for Cli { fn impl_name() -> String { diff --git a/node/src/rpc.rs b/node/src/rpc.rs index efce2278d..b8642396d 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -8,11 +8,11 @@ use std::sync::Arc; use jsonrpsee::RpcModule; -use node_template_runtime::opaque::Block; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use tuxedo_core::types::OpaqueBlock as Block; pub use sc_rpc_api::DenyUnsafe; diff --git a/node/src/service.rs b/node/src/service.rs index d7c892792..d18194aca 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use crate::rpc; -use node_template_runtime::{self, opaque::Block, RuntimeApi}; +use node_template_runtime::{self, RuntimeApi}; use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; @@ -11,7 +11,7 @@ use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use std::{sync::Arc, time::Duration}; -use tuxedo_core::genesis::TuxedoGenesisBlockBuilder; +use tuxedo_core::{genesis::TuxedoGenesisBlockBuilder, types::OpaqueBlock as Block}; // Our native executor instance. pub struct ExecutorDispatch; diff --git a/parachain-node/src/dev_service.rs b/parachain-node/src/dev_service.rs index 8243dc64f..2a1d22057 100644 --- a/parachain-node/src/dev_service.rs +++ b/parachain-node/src/dev_service.rs @@ -2,14 +2,14 @@ //! but without a backing relay chain. This allows developers to quickly and easily spin up parachain //! nodes using the --dev flag, for example. It can also be used in integration tests. -use parachain_template_runtime::{self, opaque::Block, RuntimeApi}; +use parachain_template_runtime::{self, RuntimeApi}; use sc_client_api::BlockBackend; use sc_consensus_manual_seal::consensus::aura::AuraConsensusDataProvider; pub use sc_executor::NativeElseWasmExecutor; use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use std::{sync::Arc, time::Duration}; -use tuxedo_core::genesis::TuxedoGenesisBlockBuilder; +use tuxedo_core::{genesis::TuxedoGenesisBlockBuilder, types::OpaqueBlock as Block}; use cumulus_primitives_parachain_inherent::MockValidationDataInherentDataProvider; diff --git a/parachain-node/src/rpc.rs b/parachain-node/src/rpc.rs index 62c932dfb..d3f54e184 100644 --- a/parachain-node/src/rpc.rs +++ b/parachain-node/src/rpc.rs @@ -8,12 +8,12 @@ use std::sync::Arc; use jsonrpsee::RpcModule; -use parachain_template_runtime::opaque::Block; pub use sc_rpc::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use tuxedo_core::types::OpaqueBlock as Block; /// A type representing all RPC extensions. pub type RpcExtension = jsonrpsee::RpcModule<()>; diff --git a/parachain-node/src/service.rs b/parachain-node/src/service.rs index c059e131b..7f2d300f0 100644 --- a/parachain-node/src/service.rs +++ b/parachain-node/src/service.rs @@ -1,14 +1,9 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. -// std -use std::{sync::Arc, time::Duration}; - use cumulus_client_cli::CollatorOptions; -// Local Runtime Types -use parachain_template_runtime::{ - opaque::{Block, Hash}, - RuntimeApi, -}; +use parachain_template_runtime::RuntimeApi; +use std::{sync::Arc, time::Duration}; +use tuxedo_core::types::{OpaqueBlock as Block, OpaqueHash as Hash}; // Cumulus Imports use cumulus_client_collator::service::CollatorService; diff --git a/tuxedo-core/src/executive.rs b/tuxedo-core/src/executive.rs index 5b88930f0..969b92feb 100644 --- a/tuxedo-core/src/executive.rs +++ b/tuxedo-core/src/executive.rs @@ -11,7 +11,10 @@ use crate::{ dynamic_typing::DynamicallyTypedData, ensure, inherents::PARENT_INHERENT_IDENTIFIER, - types::{DispatchResult, OutputRef, RedemptionStrategy, Transaction, UtxoError}, + types::{ + Block, BlockNumber, DispatchResult, Header, OutputRef, RedemptionStrategy, Transaction, + UtxoError, + }, utxo_set::TransparentUtxoSet, verifier::Verifier, EXTRINSIC_KEY, HEADER_KEY, HEIGHT_KEY, LOG_TARGET, @@ -22,7 +25,7 @@ use sp_api::{BlockT, HashT, HeaderT, TransactionValidity}; use sp_core::H256; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ - traits::BlakeTwo256, + traits::{BlakeTwo256, Extrinsic}, transaction_validity::{ InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidityError, ValidTransaction, @@ -34,14 +37,14 @@ use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; /// The executive. Each runtime is encouraged to make a type alias called `Executive` that fills /// in the proper generic types. -pub struct Executive(PhantomData<(B, V, C)>); +pub struct Executive(PhantomData<(V, C)>); -impl Executive +impl Executive where - B: BlockT>, - B::Header: HeaderT, // Tuxedo always uses u32 for block number. V: Verifier, C: ConstraintChecker, + Block: BlockT, Hash = sp_core::H256>, + Transaction: Extrinsic, { /// Does pool-style validation of a tuxedo transaction. /// Does not commit anything to storage. @@ -235,19 +238,16 @@ where } /// A helper function that allows tuxedo runtimes to read the current block height - pub fn block_height() -> <::Header as HeaderT>::Number - where - B::Header: HeaderT, - { + pub fn block_height() -> BlockNumber { sp_io::storage::get(HEIGHT_KEY) - .and_then(|d| <::Header as HeaderT>::Number::decode(&mut &*d).ok()) - .expect("A header is stored at the beginning of block one and never cleared.") + .and_then(|d| BlockNumber::decode(&mut &*d).ok()) + .expect("A height is stored at the beginning of block one and never cleared.") } // These next three methods are for the block authoring workflow. // Open the block, apply zero or more extrinsics, close the block - pub fn open_block(header: &::Header) { + pub fn open_block(header: &Header) { debug!( target: LOG_TARGET, "Entering initialize_block. header: {:?}", header @@ -262,7 +262,7 @@ where sp_io::storage::set(HEIGHT_KEY, &header.number().encode()); } - pub fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + pub fn apply_extrinsic(extrinsic: Transaction) -> ApplyExtrinsicResult { debug!( target: LOG_TARGET, "Entering apply_extrinsic: {:?}", extrinsic @@ -283,9 +283,9 @@ where Ok(Ok(())) } - pub fn close_block() -> ::Header { + pub fn close_block() -> Header { let mut header = sp_io::storage::get(HEADER_KEY) - .and_then(|d| ::Header::decode(&mut &*d).ok()) + .and_then(|d| Header::decode(&mut &*d).ok()) .expect("We initialized with header, it never got mutated, qed"); // the header itself contains the state root, so it cannot be inside the state (circular @@ -295,16 +295,13 @@ where let extrinsics = sp_io::storage::get(EXTRINSIC_KEY) .and_then(|d| >>::decode(&mut &*d).ok()) .unwrap_or_default(); - let extrinsics_root = <::Header as HeaderT>::Hashing::ordered_trie_root( - extrinsics, - StateVersion::V0, - ); + let extrinsics_root = +
::Hashing::ordered_trie_root(extrinsics, StateVersion::V0); sp_io::storage::clear(EXTRINSIC_KEY); header.set_extrinsics_root(extrinsics_root); let raw_state_root = &sp_io::storage::root(StateVersion::V1)[..]; - let state_root = - <::Header as HeaderT>::Hash::decode(&mut &raw_state_root[..]).unwrap(); + let state_root =
::Hash::decode(&mut &raw_state_root[..]).unwrap(); header.set_state_root(state_root); debug!(target: LOG_TARGET, "finalizing block {:?}", header); @@ -313,7 +310,7 @@ where // This one is for the Core api. It is used to import blocks authored by foreign nodes. - pub fn execute_block(block: B) { + pub fn execute_block(block: Block) { debug!( target: LOG_TARGET, "Entering execute_block. block: {:?}", block @@ -324,6 +321,10 @@ where // be cleared before the end of the block sp_io::storage::set(HEADER_KEY, &block.header().encode()); + // Also store the height persistently so it is available when + // performing pool validations and other off-chain runtime calls. + sp_io::storage::set(HEIGHT_KEY, &block.header().number().encode()); + // Tuxedo requires that inherents are at the beginning (and soon end) of the // block and not scattered throughout. We use this flag to enforce that. let mut finished_with_opening_inherents = false; @@ -354,37 +355,21 @@ where // Check state root let raw_state_root = &sp_io::storage::root(StateVersion::V1)[..]; - let state_root = - <::Header as HeaderT>::Hash::decode(&mut &raw_state_root[..]).unwrap(); + let state_root =
::Hash::decode(&mut &raw_state_root[..]).unwrap(); assert_eq!( *block.header().state_root(), state_root, "state root mismatch" ); - // Print state for quick debugging - // let mut key = vec![]; - // while let Some(next) = sp_io::storage::next_key(&key) { - // let val = sp_io::storage::get(&next).unwrap().to_vec(); - // log::trace!( - // target: LOG_TARGET, - // "{} <=> {}", - // HexDisplay::from(&next), - // HexDisplay::from(&val) - // ); - // key = next; - // } - // Check extrinsics root. let extrinsics = block .extrinsics() .iter() .map(|x| x.encode()) .collect::>(); - let extrinsics_root = <::Header as HeaderT>::Hashing::ordered_trie_root( - extrinsics, - StateVersion::V0, - ); + let extrinsics_root = +
::Hashing::ordered_trie_root(extrinsics, StateVersion::V0); assert_eq!( *block.header().extrinsics_root(), extrinsics_root, @@ -396,8 +381,8 @@ where pub fn validate_transaction( source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, + tx: Transaction, + block_hash: as BlockT>::Hash, ) -> TransactionValidity { debug!( target: LOG_TARGET, @@ -433,14 +418,14 @@ where } // The next two are for the standard beginning-of-block inherent extrinsics. - pub fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + pub fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec> { debug!( target: LOG_TARGET, "Entering `inherent_extrinsics`." ); // Extract the complete parent block from the inherent data - let parent: B = data + let parent: Block = data .get_data(&PARENT_INHERENT_IDENTIFIER) .expect("Parent block inherent data should be able to decode.") .expect("Parent block should be present among authoring inherent data."); @@ -450,7 +435,7 @@ where // We also annotate each transaction with its original hash for purposes of constructing output refs later. // This is necessary because the transaction hash changes as we unwrap layers of aggregation, // and we need an original universal transaction id. - let previous_blocks_inherents: Vec<(::Extrinsic, H256)> = parent + let previous_blocks_inherents: Vec<(Transaction, H256)> = parent .extrinsics() .iter() .cloned() @@ -470,7 +455,10 @@ where C::create_inherents(&data, previous_blocks_inherents) } - pub fn check_inherents(block: B, data: InherentData) -> sp_inherents::CheckInherentsResult { + pub fn check_inherents( + block: Block, + data: InherentData, + ) -> sp_inherents::CheckInherentsResult { debug!( target: LOG_TARGET, "Entering `check_inherents`" @@ -514,7 +502,7 @@ mod tests { type TestTransaction = Transaction; pub type TestHeader = sp_runtime::generic::Header; pub type TestBlock = sp_runtime::generic::Block; - pub type TestExecutive = Executive; + pub type TestExecutive = Executive; /// Construct a mock OutputRef from a transaction number and index in that transaction. /// @@ -1098,7 +1086,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", @@ -1120,7 +1108,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "d609af1c51521f5891054014cf667619067a93f4bca518b398f5a39aeb270cca", @@ -1143,7 +1131,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", @@ -1187,7 +1175,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: H256::zero(), digest: Default::default(), @@ -1207,7 +1195,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "799fc6d36f68fc83ae3408de607006e02836181e91701aa3a8021960b1f3507c", @@ -1229,7 +1217,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "bf3e98799022bee8f0a55659af5f498717736ae012d2aff6274cdb7c2b0d78e9", @@ -1257,7 +1245,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "df64890515cd8ef5a8e736248394f7c72a1df197bd400a4e31affcaf6e051984", @@ -1285,7 +1273,7 @@ mod tests { parent_hash: H256::zero(), number: 6, state_root: array_bytes::hex_n_into_unchecked( - "858174d563f845dbb4959ea64816bd8409e48cc7e65db8aa455bc98d61d24071", + "cc2d78f5977b6e9e16f4417f60cbd7edaad0c39a6a7cd21281e847da7dd210b9", ), extrinsics_root: array_bytes::hex_n_into_unchecked( "0x36601deae36de127b974e8498e118e348a50aa4aa94bc5713e29c56e0d37e44f", diff --git a/tuxedo-core/src/genesis.rs b/tuxedo-core/src/genesis.rs index ead021a83..54e4653d9 100644 --- a/tuxedo-core/src/genesis.rs +++ b/tuxedo-core/src/genesis.rs @@ -3,7 +3,7 @@ use crate::{ ensure, types::{Output, OutputRef, Transaction}, - ConstraintChecker, Verifier, EXTRINSIC_KEY, LOG_TARGET, + ConstraintChecker, Verifier, EXTRINSIC_KEY, HEIGHT_KEY, LOG_TARGET, }; use parity_scale_codec::{Decode, Encode}; use sc_chain_spec::BuildGenesisBlock; @@ -144,6 +144,9 @@ where self.wasm_binary.clone(), ); + // Initialize the stored block number to 0 + storage.top.insert(HEIGHT_KEY.to_vec(), 0u32.encode()); + // The transactions are stored under a special key. storage .top diff --git a/tuxedo-core/src/types.rs b/tuxedo-core/src/types.rs index 7a81ee930..85073f80a 100644 --- a/tuxedo-core/src/types.rs +++ b/tuxedo-core/src/types.rs @@ -5,9 +5,23 @@ use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_core::H256; -use sp_runtime::traits::Extrinsic; +use sp_runtime::traits::{BlakeTwo256, Extrinsic}; use sp_std::vec::Vec; +// All Tuxedo chains use the same BlakeTwo256 hash. +pub type Hash = BlakeTwo256; +/// Opaque block hash type. +pub type OpaqueHash = ::Output; +/// All Tuxedo chains use the same u32 BlockNumber. +pub type BlockNumber = u32; +/// Because all tuxedo chains use the same Blocknumber and Hash types, +/// they also use the same concrete header type. +pub type Header = sp_runtime::generic::Header; +/// An alias for a Tuxedo block with all the common parts filled in. +pub type Block = sp_runtime::generic::Block>; +/// Opaque block type. It has a Standard Tuxedo header, and opaque transactions. +pub type OpaqueBlock = sp_runtime::generic::Block; + /// A reference to a output that is expected to exist in the state. #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub struct OutputRef { diff --git a/tuxedo-core/src/verifier/htlc.rs b/tuxedo-core/src/verifier/htlc.rs index 9e70eacb0..57f66f996 100644 --- a/tuxedo-core/src/verifier/htlc.rs +++ b/tuxedo-core/src/verifier/htlc.rs @@ -223,7 +223,7 @@ mod test { signature: recipient_sig, }; - assert!(htlc.verify(&simplified_tx, 0, &redeemer)); + assert!(htlc.verify(simplified_tx, 0, &redeemer)); } #[test] @@ -249,7 +249,7 @@ mod test { signature: recipient_sig, }; - assert!(!htlc.verify(&simplified_tx, 0, &redeemer)); + assert!(!htlc.verify(simplified_tx, 0, &redeemer)); } #[test] @@ -272,7 +272,7 @@ mod test { signature: bad_sig(), }; - assert!(!htlc.verify(&simplified_tx, 0, &redeemer)); + assert!(!htlc.verify(simplified_tx, 0, &redeemer)); } #[test] @@ -296,7 +296,7 @@ mod test { signature: refunder_sig, }; - assert!(!htlc.verify(&simplified_tx, 0, &redeemer)); + assert!(!htlc.verify(simplified_tx, 0, &redeemer)); } #[test] @@ -319,7 +319,7 @@ mod test { signature: refunder_sig, }; - assert!(htlc.verify(&simplified_tx, 2 * THRESHOLD, &redeemer)); + assert!(htlc.verify(simplified_tx, 2 * THRESHOLD, &redeemer)); } #[test] @@ -342,7 +342,7 @@ mod test { signature: refunder_sig, }; - assert!(!htlc.verify(&simplified_tx, 0, &redeemer)); + assert!(!htlc.verify(simplified_tx, 0, &redeemer)); } #[test] @@ -364,7 +364,7 @@ mod test { signature: bad_sig(), }; - assert!(!htlc.verify(&simplified_tx, 2 * THRESHOLD, &redeemer)); + assert!(!htlc.verify(simplified_tx, 2 * THRESHOLD, &redeemer)); } #[test] @@ -387,6 +387,6 @@ mod test { signature: recipient_sig, }; - assert!(!htlc.verify(&simplified_tx, 2 * THRESHOLD, &redeemer)); + assert!(!htlc.verify(simplified_tx, 2 * THRESHOLD, &redeemer)); } } diff --git a/tuxedo-parachain-core/Cargo.toml b/tuxedo-parachain-core/Cargo.toml index d59940d40..85e696d06 100644 --- a/tuxedo-parachain-core/Cargo.toml +++ b/tuxedo-parachain-core/Cargo.toml @@ -16,7 +16,7 @@ serde = { features = [ "derive" ], workspace = true } # Local tuxedo-core = { default-features = false, path = "../tuxedo-core" } -tuxedo-register-validate-block = { default_features = false, path = "register_validate_block" } +tuxedo-parachainify = { default_features = false, path = "parachainify" } # Substrate sp-api = { default_features = false, workspace = true } @@ -67,5 +67,5 @@ std = [ "polkadot-parachain-primitives/std", "trie-db/std", "tuxedo-core/std", - "tuxedo-register-validate-block/std", + "tuxedo-parachainify/std", ] diff --git a/tuxedo-parachain-core/register_validate_block/Cargo.toml b/tuxedo-parachain-core/parachainify/Cargo.toml similarity index 51% rename from tuxedo-parachain-core/register_validate_block/Cargo.toml rename to tuxedo-parachain-core/parachainify/Cargo.toml index aba2b56b7..a138299c6 100644 --- a/tuxedo-parachain-core/register_validate_block/Cargo.toml +++ b/tuxedo-parachain-core/parachainify/Cargo.toml @@ -1,7 +1,7 @@ [package] -description = "Proc macro to register Polkadot's validate_block entrypoint in your Tuxedo Runtime. Inspired by cumulus-pallet-parachain-system-proc-macro" +description = "Proc macro to make a Tuxedo tuntime Parachain Compatible. Inspired by cumulus-pallet-parachain-system-proc-macro" edition = "2021" -name = "tuxedo-register-validate-block" +name = "tuxedo-parachainify" version = "0.1.0" [dependencies] diff --git a/tuxedo-parachain-core/register_validate_block/src/lib.rs b/tuxedo-parachain-core/parachainify/src/lib.rs similarity index 55% rename from tuxedo-parachain-core/register_validate_block/src/lib.rs rename to tuxedo-parachain-core/parachainify/src/lib.rs index 4820cf4bc..d2b2753ab 100644 --- a/tuxedo-parachain-core/register_validate_block/src/lib.rs +++ b/tuxedo-parachain-core/parachainify/src/lib.rs @@ -1,14 +1,14 @@ //! This macro is copied from cumulus-pallet-parachain-system-proc-macro crate //! and modified slightly to fit Tuxedo's needs. -use proc_macro2::Span; +use proc_macro2::{Literal, Span}; use proc_macro_crate::{crate_name, FoundCrate}; use syn::{ parse::{Parse, ParseStream}, Error, Ident, Token, }; -/// Provides an identifier that is a safe way to refer to the crate tuxedo_core within the macro +/// Provides an identifier that is a safe way to refer to the crate tuxedo_parachain_core within the macro fn crate_() -> Result { match crate_name("tuxedo-parachain-core") { Ok(FoundCrate::Itself) => Ok(syn::Ident::new("tuxedo_parachain_core", Span::call_site())), @@ -18,27 +18,27 @@ fn crate_() -> Result { } struct RegisterValidateBlockInput { - pub block: Ident, - _comma1: Token![,], pub verifier: Ident, + _comma1: Token![,], + pub inner_constraint_checker: Ident, _comma2: Token![,], - pub constraint_checker: Ident, + pub para_id: Literal, } impl Parse for RegisterValidateBlockInput { fn parse(input: ParseStream) -> syn::Result { let parsed = Self { - block: input.parse()?, - _comma1: input.parse()?, verifier: input.parse()?, + _comma1: input.parse()?, + inner_constraint_checker: input.parse()?, _comma2: input.parse()?, - constraint_checker: input.parse()?, + para_id: input.parse()?, }; if !input.is_empty() { return Err(Error::new( input.span(), - "Expected exactly three parameters: Block, Verifier, ConstraintChecker.", + "Expected exactly three parameters: Verifier, InnerConstraintChecker, ParaId.", )); } @@ -47,7 +47,7 @@ impl Parse for RegisterValidateBlockInput { } #[proc_macro] -pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn parachainify(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // Extract the paths to the parts from the runtime developer's input // I will likely need to revise or simplify the fields that are passed in. // I hope to only use the exposed runtime APIs here, not some custom trait impls. (if possible) @@ -56,9 +56,9 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To Err(e) => return e.into_compile_error().into(), }; - let block = input.block.clone(); let verifier = input.verifier.clone(); - let constraint_checker = input.constraint_checker.clone(); + let inner_constraint_checker = input.inner_constraint_checker.clone(); + let para_id = input.para_id.clone(); // A way to refer to the tuxedo_parachain_core crate from within the macro. let crate_ = match crate_() { @@ -66,22 +66,9 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To Err(e) => return e.into_compile_error().into(), }; - //TODO We need to check inherents. At least the timestamp one, and maybe also the parachain one? - // https://github.com/Off-Narrative-Labs/Tuxedo/issues/144 - // But I think the parachain one is handled already. - // To start the hack, we will just not check them at all. Fewer places to panic XD - // let check_inherents = match check_inherents { - // Some(_check_inherents) => { - // quote::quote! { #_check_inherents } - // }, - // None => { - // quote::quote! { - // #crate_::DummyCheckInherents<<#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock> - // } - // }, - // }; - - if cfg!(not(feature = "std")) { + // Implementation of Polkadot's validate_block function. Inspired by Basti's frame version: + // https://github.com/paritytech/polkadot-sdk/blob/0becc45b/cumulus/pallets/parachain-system/proc-macro/src/lib.rs#L93-L153 + let validate_block_func = if cfg!(not(feature = "std")) { quote::quote! { #[doc(hidden)] mod parachain_validate_block { @@ -93,8 +80,7 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To // It is basically a wrapper around the validate block implementation // that handles extracting params and returning results via shared memory. - // Setp 1. Extract the arguments from shared memory - + // Step 1. Extract the arguments from shared memory // We convert the `arguments` into a boxed slice and then into `Bytes`. let args = #crate_::sp_std::boxed::Box::from_raw( #crate_::sp_std::slice::from_raw_parts_mut( @@ -111,9 +97,8 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To // Step 2: Call the actual validate_block implementation let res = #crate_::validate_block::validate_block::< - #block, #verifier, - #constraint_checker, + ParachainConstraintChecker, >(params); // Step 3: Write the return value back into the shared memory @@ -126,6 +111,51 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To } else { // If we are building to std, we don't include this validate_block entry point at all quote::quote!() + }; + + // Write the piece config and the `ParachainConstraintChecker` enum. + let parachain_constraint_checker_enum = quote::quote! { + #[derive(PartialEq, Eq, Clone)] + pub struct RuntimeParachainConfig; + impl parachain_piece::ParachainPieceConfig for RuntimeParachainConfig { + const PARA_ID: u32 = #para_id; + + type SetRelayParentNumberStorage = tuxedo_parachain_core::RelayParentNumberStorage; + } + + /// The Outer / Aggregate Constraint Checker for the Parachain runtime. + /// + /// It is comprized of two individual checkers: + /// First, the constraint checker from the normal Tuxedo Template Runtime. + /// Second, the parachain inherent piece + /// + /// That first constituent checker, the normal tuxedo template runtime, is itself an aggregate + /// constraint checker aggregated from individual pieces such as money, amoeba, and others. + #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] + #[tuxedo_constraint_checker] + pub enum ParachainConstraintChecker { + /// All other calls are delegated to the normal Tuxedo Template Runtime. + Inner(#inner_constraint_checker), + + /// Set some parachain related information via an inherent extrinsic. + ParachainInfo(InherentAdapter>), + } + + // We provide a way for the relay chain validators to extract the parachain inherent data from + // a raw transaction. + impl #crate_::ParachainConstraintChecker for ParachainConstraintChecker { + + fn is_parachain(&self) -> bool { + matches!(self, Self::ParachainInfo(_)) + } + } + }; + + // The final output is the `ParachainConstraintChecker` plus the `validate_block` function. + quote::quote! { + #validate_block_func + + #parachain_constraint_checker_enum } .into() } diff --git a/tuxedo-parachain-core/src/collation_api.rs b/tuxedo-parachain-core/src/collation_api.rs index 330c569ca..b2a21a100 100644 --- a/tuxedo-parachain-core/src/collation_api.rs +++ b/tuxedo-parachain-core/src/collation_api.rs @@ -4,19 +4,18 @@ use cumulus_primitives_core::{relay_chain::HeadData, CollationInfo}; use parity_scale_codec::Encode; -use sp_api::BlockT; use sp_std::vec::Vec; -use tuxedo_core::Executive; +use tuxedo_core::{types::Header, Executive}; use crate::{GetRelayParentNumberStorage, RelayParentNumberStorage}; /// An extension trait that allows us to implement more methods on tuxedo-core's executive. -pub trait ParachainExecutiveExtension
{ +pub trait ParachainExecutiveExtension { fn collect_collation_info(header: &Header) -> cumulus_primitives_core::CollationInfo; } -impl ParachainExecutiveExtension for Executive { - fn collect_collation_info(header: &B::Header) -> cumulus_primitives_core::CollationInfo { +impl ParachainExecutiveExtension for Executive { + fn collect_collation_info(header: &Header) -> cumulus_primitives_core::CollationInfo { // The implementation here is simple. Most of the fields are related to xcm and parachain runtime upgrades, // neither or which are supported in the PoC, so they are left blank. diff --git a/tuxedo-parachain-core/src/lib.rs b/tuxedo-parachain-core/src/lib.rs index 47b267f90..439fa5758 100644 --- a/tuxedo-parachain-core/src/lib.rs +++ b/tuxedo-parachain-core/src/lib.rs @@ -7,10 +7,10 @@ //! are quite heavy to compile, and sovereign chains are able to completely avoid it. //! //! It's primary jobs are to -//! * Manage transiet storage details for the parachain inherent, specifically the relay +//! * Manage transient storage details for the parachain inherent, specifically the relay //! parent block number. //! * Provide collation information to the client side collator service. -//! * Implement the `validate_block` funtion required by relay chain validators. +//! * Implement the `validate_block` function required by relay chain validators. //! This task is achieved through the `register_validate_block!` macro. //! //! This code is inspired by, cumulus pallet parachain system @@ -58,6 +58,7 @@ use cumulus_primitives_parachain_inherent::ParachainInherentData; use tuxedo_core::{ dynamic_typing::UtxoData, support_macros::{CloneNoBound, DebugNoBound}, + ConstraintChecker, }; /// A transient storage key that will hold the block number of the relay chain parent @@ -123,22 +124,23 @@ pub struct MemoryOptimizedValidationParams { pub relay_parent_storage_root: cumulus_primitives_core::relay_chain::Hash, } -/// Register the `validate_block` function that is used by parachains to validate blocks on a -/// validator. +/// Prepares a Tuxedo runtime to be parachain compatible by doing two main tasks. /// -/// Does *nothing* when `std` feature is enabled. +/// 1. Wraps the provided constraint checker in another layer of aggregation including the parachain +/// inherent piece +/// 2. Registers the `validate_block` function that is used by parachains to validate blocks on a +/// validator when building to wasm. This is skipped when building to std. /// -/// Expects as parameters the Block type, the OuterVerifier, and the OuterConstraintChecker. -pub use tuxedo_register_validate_block::register_validate_block; +/// Expects as parameters a Verifier, a non-yet-parachain-ready ConstraintChecker, and a ParaId. +pub use tuxedo_parachainify::parachainify; // Having to do this wrapping is one more reason to abandon this UtxoData trait, // and go for a more strongly typed aggregate type approach. // Tracking issue: https://github.com/Off-Narrative-Labs/Tuxedo/issues/153 /// A wrapper type around Cumulus's ParachainInherentData type that can be stored. #[derive(Encode, Decode, DebugNoBound, CloneNoBound, scale_info::TypeInfo)] - /// A wrapper type around Cumulus's ParachainInherentData type. -/// This type is convertable Into and From the inner type. +/// This type is convertible Into and From the inner type. /// This is necessary so that we can implement the `UtxoData` trait. pub struct ParachainInherentDataUtxo(ParachainInherentData); @@ -157,3 +159,10 @@ impl From for ParachainInherentDataUtxo { Self(value) } } + +/// A way for the relay chain validators to determine whether a particular parachain +/// extrinsic is the parachain inherent and whether the parachain inherent data can +/// be extracted from it. +pub trait ParachainConstraintChecker: ConstraintChecker { + fn is_parachain(&self) -> bool; +} diff --git a/tuxedo-parachain-core/src/validate_block.rs b/tuxedo-parachain-core/src/validate_block.rs index 5bb1388fa..197e3ce10 100644 --- a/tuxedo-parachain-core/src/validate_block.rs +++ b/tuxedo-parachain-core/src/validate_block.rs @@ -2,7 +2,7 @@ use super::{ trie_cache, GetRelayParentNumberStorage, MemoryOptimizedValidationParams, - ParachainInherentDataUtxo, RelayParentNumberStorage, + ParachainConstraintChecker, ParachainInherentDataUtxo, RelayParentNumberStorage, }; use cumulus_primitives_core::{ relay_chain::Hash as RHash, ParachainBlockData, PersistedValidationData, @@ -11,10 +11,12 @@ use cumulus_primitives_parachain_inherent::ParachainInherentData; use polkadot_parachain_primitives::primitives::{ HeadData, RelayChainBlockNumber, ValidationResult, }; -use tuxedo_core::{types::Transaction, ConstraintChecker, Executive, Verifier}; +use tuxedo_core::{ + types::{Block, Header, Transaction}, + ConstraintChecker, Executive, Verifier, +}; use parity_scale_codec::Encode; -use scale_info::TypeInfo; use sp_core::storage::{ChildInfo, StateVersion}; use sp_externalities::{set_and_run_with_externalities, Externalities}; use sp_io::KillStorageResult; @@ -61,7 +63,7 @@ fn with_externalities R, R>(f: F) -> R { /// ensuring that the final storage root matches the storage root in the header of the block. In the /// end we return back the [`ValidationResult`] with all the required information for the validator. #[doc(hidden)] -pub fn validate_block( +pub fn validate_block( MemoryOptimizedValidationParams { block_data, parent_head, @@ -70,32 +72,46 @@ pub fn validate_block( }: MemoryOptimizedValidationParams, ) -> ValidationResult where - B: BlockT>, - B::Header: HeaderT, // Tuxedo always uses u32 for block number. + // Kind of feels like I'm repeating all the requirements that + // should have been taken care of by the type aliases. + V: Verifier, + C: ParachainConstraintChecker, + Block: BlockT, Hash = sp_core::H256>, Transaction: Extrinsic, - V: TypeInfo + Verifier + 'static, - C: TypeInfo + ConstraintChecker + 'static, // + Into>, { sp_runtime::runtime_logger::RuntimeLogger::init(); log::info!(target: "tuxvb", "🕵️🕵️🕵️🕵️Entering validate_block implementation"); // Step 1: Decode block data - let block_data = parity_scale_codec::decode_from_bytes::>(block_data) - .expect("Invalid parachain block data"); + let block_data = + parity_scale_codec::decode_from_bytes::>>(block_data) + .expect("Invalid parachain block data"); // Step 2: Security Checks log::info!(target: "tuxvb", "🕵️🕵️🕵️🕵️ Step 2"); - let parent_header = parity_scale_codec::decode_from_bytes::(parent_head.clone()) + let parent_header = parity_scale_codec::decode_from_bytes::
(parent_head.clone()) .expect("Invalid parent head"); let (header, extrinsics, storage_proof) = block_data.deconstruct(); - let block = B::new(header, extrinsics); + let block = Block::::new(header, extrinsics); assert!( parent_header.hash() == *block.header().parent_hash(), "Invalid parent hash" ); - let inherent_data = extract_parachain_inherent_data(&block); + let inherent_data: ParachainInherentData = block + .extrinsics() + .iter() + .take_while(|e| !e.is_signed().unwrap_or(true)) + .find(|e| e.checker.is_parachain()) + .expect("There should be at least one beginning-of-block inherent extrinsic which is the parachain inherent.") + .outputs + .get(0) + .expect("Parachain inherent should have exactly one output.") + .payload + .extract::() + .expect("All valid parachain info transactions have this typed output. This is verified by the constraint checker.") + .into(); validate_validation_data( &inherent_data.validation_data, @@ -192,15 +208,15 @@ where // } // }); - run_with_externalities::(&backend, || { + run_with_externalities::, _, _>(&backend, || { log::info!(target: "tuxvb", "🕵️🕵️🕵️🕵️ In the run_with_externalities closure"); let head_data = HeadData(block.header().encode()); - Executive::::execute_block(block); + Executive::::execute_block(block); log::info!(target: "tuxvb", "🕵️🕵️🕵️🕵️ returned from execute block"); - // TODO Once we support XCM, we will need to gather some messaging state stuff here + // In order to support XCM, we will need to gather some messaging state stuff here // Seems like we could call the existing collect_collation_info api to get this information here // instead of FRAME's approach of tightly coupling to pallet parachain system. // That would mean less duplicated code as well as a more flexible validate block macro. @@ -219,61 +235,6 @@ where }) } -/// Extract the [`ParachainInherentData`] from a parachain block. -/// The data has to be extracted from the extrinsics themselves. -/// I want the runtime to expose a method to do this, and I also want it to -/// be nice and flexible by searching for the right transactions. -/// For now I have a hacky implementation that assumes the parachain inherent is last -fn extract_parachain_inherent_data(block: &B) -> ParachainInherentData -where - B: BlockT>, - // Consider an alternative way to express the bounds here: - // Transaction: Extrinsic - V: TypeInfo + Verifier + 'static, - C: TypeInfo + ConstraintChecker + 'static, -{ - // The commented stuff is Basti's algo. - // It is nicer than my hack because it searches the transactions, - // But it is still not good enough because it lived right here in this file as - // opposed to with the runtime. - // FIXME https://github.com/Off-Narrative-Labs/Tuxedo/issues/146 - - // One idea from github.com/Off-Narrative-Labs/Tuxedo/pull/130#discussion_r1408250978 - // is to find the inehrent based o nthe dynamic type of the output. - // This is a reason to keep dynamic typing which is discussed in - // https://github.com/Off-Narrative-Labs/Tuxedo/issues/153 - - // block - // .extrinsics() - // .iter() - // // Inherents are at the front of the block and are unsigned. - // // - // // If `is_signed` is returning `None`, we keep it safe and assume that it is "signed". - // // We are searching for unsigned transactions anyway. - // .take_while(|e| !e.is_signed().unwrap_or(true)) - // .filter_map(|e| e.call().is_sub_type()) - // .find_map(|c| match c { - // crate::Call::set_validation_data { data: validation_data } => Some(validation_data), - // _ => None, - // }) - // .expect("Could not find `set_validation_data` inherent") - - block - .extrinsics() - .iter() - .take_while(|&e| !e.is_signed().unwrap_or(true)) - .collect::>() - .last() - .expect("There should be at least one inherent extrinsic which is the parachain inherent.") - .outputs - .get(0) - .expect("Parachain inherent should be first and should have exactly one output.") - .payload - .extract::() - .expect("Should decode to proper type based on the position in the block.") - .into() -} - /// Validate the given [`PersistedValidationData`] against the [`MemoryOptimizedValidationParams`]. fn validate_validation_data( validation_data: &PersistedValidationData, diff --git a/tuxedo-parachain-runtime/Cargo.toml b/tuxedo-parachain-runtime/Cargo.toml index fa5c6bb78..d6cd14c6b 100644 --- a/tuxedo-parachain-runtime/Cargo.toml +++ b/tuxedo-parachain-runtime/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/Off-Narative-Labs/Tuxedo" version = "1.0.0-dev" [dependencies] +hex-literal = { workspace = true } log = { workspace = true } parity-scale-codec = { features = [ "derive" ], workspace = true } parity-util-mem = { optional = true, workspace = true } @@ -14,7 +15,9 @@ scale-info = { features = [ "derive", "serde" ], workspace = true } serde = { features = [ "derive" ], workspace = true } sp-api = { default_features = false, workspace = true } +sp-application-crypto = { default_features = false, workspace = true } sp-block-builder = { default_features = false, workspace = true } +sp-consensus-aura = { default_features = false, workspace = true } sp-core = { features = [ "serde" ], default_features = false, workspace = true } sp-debug-derive = { features = [ "force-debug" ], default_features = false, workspace = true } sp-inherents = { default_features = false, workspace = true } @@ -30,12 +33,6 @@ sp-version = { default_features = false, workspace = true } # The inner runtime inner-runtime = { default-features = false, package = "tuxedo-template-runtime", path = "../tuxedo-template-runtime" } -# These were added for Aura / Grandpa API support -hex-literal = { workspace = true } -sp-application-crypto = { default_features = false, workspace = true } -sp-consensus-aura = { default_features = false, workspace = true } -sp-consensus-grandpa = { default_features = false, workspace = true } - # Parachain related ones cumulus-primitives-core = { default-features = false, workspace = true } parachain-piece = { default-features = false, path = "../wardrobe/parachain" } @@ -64,7 +61,6 @@ std = [ "sp-storage/std", "sp-consensus-aura/std", "sp-application-crypto/std", - "sp-consensus-grandpa/std", "inner-runtime/std", "cumulus-primitives-core/std", "parachain-piece/std", diff --git a/tuxedo-parachain-runtime/src/genesis.rs b/tuxedo-parachain-runtime/src/genesis.rs index ad350920b..537c054e5 100644 --- a/tuxedo-parachain-runtime/src/genesis.rs +++ b/tuxedo-parachain-runtime/src/genesis.rs @@ -1,6 +1,6 @@ //! Helper module to build a genesis configuration for the template runtime. -use super::{OuterConstraintChecker, OuterVerifier, WASM_BINARY}; +use super::{OuterVerifier, ParachainConstraintChecker, WASM_BINARY}; use hex_literal::hex; use inner_runtime::{money::Coin, OuterConstraintChecker as InnerConstraintChecker}; use tuxedo_parachain_core::tuxedo_core::{ @@ -10,7 +10,7 @@ use tuxedo_parachain_core::tuxedo_core::{ }; /// Helper type for the ChainSpec. -pub type RuntimeGenesisConfig = TuxedoGenesisConfig; +pub type RuntimeGenesisConfig = TuxedoGenesisConfig; const SHAWN_PUB_KEY_BYTES: [u8; 32] = hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); @@ -39,7 +39,7 @@ pub fn development_genesis_config() -> RuntimeGenesisConfig { // The inherents are computed using the appropriate method, and placed before the user transactions. // Ideally this will get better upstream eventually. - let mut genesis_transactions = OuterConstraintChecker::genesis_transactions(); + let mut genesis_transactions = ParachainConstraintChecker::genesis_transactions(); genesis_transactions.extend(user_genesis_transactions); RuntimeGenesisConfig::new( diff --git a/tuxedo-parachain-runtime/src/lib.rs b/tuxedo-parachain-runtime/src/lib.rs index c778f9c11..eb5053bc3 100644 --- a/tuxedo-parachain-runtime/src/lib.rs +++ b/tuxedo-parachain-runtime/src/lib.rs @@ -12,35 +12,26 @@ pub mod genesis; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; -use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_consensus_grandpa::AuthorityId as GrandpaId; - use sp_api::impl_runtime_apis; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::OpaqueMetadata; use sp_inherents::InherentData; use sp_runtime::{ create_runtime_str, - traits::{BlakeTwo256, Block as BlockT}, + traits::Block as BlockT, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; use sp_std::prelude::*; - #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; - -use tuxedo_core::{ - tuxedo_constraint_checker, types::Transaction as TuxedoTransaction, InherentAdapter, -}; +use tuxedo_core::{tuxedo_constraint_checker, types::Block as TuxedoBlock, InherentAdapter}; use tuxedo_parachain_core::tuxedo_core; -// We use the same aggregate verifier from the inner_runtime. -// The verifier does not contain anything parachain specific. -use inner_runtime::OuterVerifier; - -// Reuse all the same opaque types from the inner runtime. -pub use inner_runtime::opaque; +// We use the same aggregate verifier and opaque types from the inner_runtime. +// They do not contain anything parachain specific. +pub use inner_runtime::{opaque, OuterConstraintChecker as InnerConstraintChecker, OuterVerifier}; /// This runtime version. #[sp_version::runtime_version] @@ -64,46 +55,14 @@ pub fn native_version() -> NativeVersion { } } -pub type Transaction = TuxedoTransaction; -pub type BlockNumber = u32; -pub type Header = sp_runtime::generic::Header; -pub type Block = sp_runtime::generic::Block; -pub type Executive = tuxedo_core::Executive; -pub type Output = tuxedo_core::types::Output; - /// The Aura slot duration. When things are working well, this will also be the block time. const BLOCK_TIME: u64 = 3000; -impl parachain_piece::ParachainPieceConfig for Runtime { - // Use the para ID 2_000 which is the first available in the rococo-local runtime. - // This is the default value, so this could be omitted, but explicit is better. - const PARA_ID: u32 = 2_000; - - type SetRelayParentNumberStorage = tuxedo_parachain_core::RelayParentNumberStorage; -} - -/// The Outer / Aggregate Constraint Checker for the Parachain runtime. -/// -/// It is comprized of two individual chekers: -/// First, the parachain inherent piece -/// Second, the constraint checker from the normal Tuxedo Template Runtime. -/// -/// That second checker, the normal tuxedo template runtime, is itself an aggregate -/// constraint checker aggregated from idividual pieces such as money, amoeba, and others. -/// Therefore, this crate shows: -/// Generally, how to perform recursive aggregation of constraint checkers. -/// Specifically, how to elegantly transform a sovereign runtime into a parachain runtime by wrapping. -#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[tuxedo_constraint_checker(OuterVerifier)] -pub enum OuterConstraintChecker { - /// All other calls are delegated to the normal Tuxedo Template Runtime. - Inner(inner_runtime::OuterConstraintChecker), +// This creates an enum `ParachainConstraintChecker` that implements `ParachainConstraintChecker` +tuxedo_parachain_core::parachainify!(OuterVerifier, InnerConstraintChecker, 2000); - // TODO This one is last for now so that I can write a hacky algorithm to scrape - // the inherent data and assume it is last. - /// Set some parachain related information via an inherent extrinsic. - ParachainInfo(InherentAdapter>), -} +pub type Block = TuxedoBlock; +pub type Executive = tuxedo_core::Executive; /// The main struct in this module. #[derive(Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] @@ -137,36 +96,6 @@ impl Runtime { .map(|hex| AuraId::from_slice(hex.as_ref()).expect("Valid Aura authority hex was provided")) .collect() } - - ///Grandpa Authority IDs - All equally weighted - fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { - use hex_literal::hex; - use sp_application_crypto::ByteArray; - - [ - // Alice - hex!("88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee"), - // Bob - // hex!("d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69"), - // Charlie - // hex!("439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234f"), - // Dave - // hex!("5e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d9"), - // Eve - // hex!("1dfe3e22cc0d45c70779c1095f7489a8ef3cf52d62fbd8c2fa38c9f1723502b5"), - // Ferdie - // hex!("568cb4a574c6d178feb39c27dfc8b3f789e5f5423e19c71633c748b9acf086b5"), - ] - .iter() - .map(|hex| { - ( - GrandpaId::from_slice(hex.as_ref()) - .expect("Valid Grandpa authority hex was provided"), - 1, - ) - }) - .collect() - } } impl_runtime_apis! { @@ -254,33 +183,6 @@ impl_runtime_apis! { } } - impl sp_consensus_grandpa::GrandpaApi for Runtime { - fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { - Self::grandpa_authorities() - } - - fn current_set_id() -> sp_consensus_grandpa::SetId { - 0u64 - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_consensus_grandpa::EquivocationProof< - ::Hash, - sp_runtime::traits::NumberFor, - >, - _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _set_id: sp_consensus_grandpa::SetId, - _authority_id: sp_consensus_grandpa::AuthorityId, - ) -> Option { - None - } - } - impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { use tuxedo_parachain_core::ParachainExecutiveExtension; @@ -288,6 +190,3 @@ impl_runtime_apis! { } } } - -// Register the `validate_block` function that Polkadot validators will call to verify this parachain block. -tuxedo_parachain_core::register_validate_block!(Block, OuterVerifier, OuterConstraintChecker); diff --git a/tuxedo-template-runtime/src/genesis.rs b/tuxedo-template-runtime/src/genesis.rs index 7baf8cb92..4f54749c1 100644 --- a/tuxedo-template-runtime/src/genesis.rs +++ b/tuxedo-template-runtime/src/genesis.rs @@ -134,7 +134,7 @@ mod tests { .unwrap() .clone(); - assert_eq!(tx.outputs.get(0), Some(&genesis_utxo)); + assert_eq!(tx.outputs.first(), Some(&genesis_utxo)); let tx_hash = BlakeTwo256::hash_of(&tx.encode()); let output_ref = OutputRef { @@ -179,7 +179,7 @@ mod tests { .unwrap() .clone(); - assert_eq!(tx.outputs.get(0), Some(&genesis_multi_sig_utxo)); + assert_eq!(tx.outputs.first(), Some(&genesis_multi_sig_utxo)); let tx_hash = BlakeTwo256::hash_of(&tx.encode()); let output_ref = OutputRef { diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index 70494bb1d..61ff3e9ff 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -23,7 +23,7 @@ use sp_core::OpaqueMetadata; use sp_inherents::InherentData; use sp_runtime::{ create_runtime_str, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT}, + traits::Block as BlockT, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, BoundToRuntimeAppPublic, }; @@ -54,11 +54,6 @@ pub use timestamp; pub mod opaque { use super::*; - /// Opaque block type. - pub type Block = sp_runtime::generic::Block; - /// Opaque block hash type. - pub type Hash = ::Output; - // This part is necessary for generating session keys in the runtime impl_opaque_keys! { pub struct SessionKeys { @@ -104,10 +99,8 @@ pub fn native_version() -> NativeVersion { } pub type Transaction = TuxedoTransaction; -pub type BlockNumber = u32; -pub type Header = sp_runtime::generic::Header; -pub type Block = sp_runtime::generic::Block; -pub type Executive = tuxedo_core::Executive; +pub type Block = tuxedo_core::types::Block; +pub type Executive = tuxedo_core::Executive; pub type Output = tuxedo_core::types::Output; /// The Aura slot duration. When things are working well, this will also be the block time. @@ -168,27 +161,6 @@ pub enum OuterConstraintChecker { RuntimeUpgrade(runtime_upgrade::RuntimeUpgrade), } -#[derive( - Serialize, Deserialize, Encode, Decode, Debug, Default, PartialEq, Eq, Clone, TypeInfo, -)] -/// A Dummy constraint checker that does nothing. It is only present to make the -/// Parachain and non-parahcain OuterConstraintCheckers scale compatible -pub struct DummyParachainInfo; - -impl tuxedo_core::SimpleConstraintChecker for DummyParachainInfo { - type Error = (); - - fn check( - &self, - _input_data: &[tuxedo_core::dynamic_typing::DynamicallyTypedData], - _evicted_input_data: &[tuxedo_core::dynamic_typing::DynamicallyTypedData], - _peeks: &[tuxedo_core::dynamic_typing::DynamicallyTypedData], - _output_data: &[tuxedo_core::dynamic_typing::DynamicallyTypedData], - ) -> Result { - panic!("Transactions should not be sent to the dummy parachain info piece.") - } -} - /// The main struct in this module. #[derive(Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] pub struct Runtime; diff --git a/wallet/src/rpc.rs b/wallet/src/rpc.rs index 1824b4a29..4691623ee 100644 --- a/wallet/src/rpc.rs +++ b/wallet/src/rpc.rs @@ -5,10 +5,9 @@ use crate::strip_0x_prefix; use anyhow::anyhow; use jsonrpsee::{core::client::ClientT, http_client::HttpClient, rpc_params}; use parity_scale_codec::{Decode, Encode}; -use runtime::opaque::Block as OpaqueBlock; use sp_core::H256; use tuxedo_core::{ - types::{Output, OutputRef}, + types::{OpaqueBlock, Output, OutputRef}, Verifier, }; diff --git a/wallet/src/sync.rs b/wallet/src/sync.rs index c5fb995c6..a0a89945f 100644 --- a/wallet/src/sync.rs +++ b/wallet/src/sync.rs @@ -25,14 +25,12 @@ use sp_runtime::{ use tuxedo_core::{ dynamic_typing::UtxoData, types::Transaction, - types::{Input, OutputRef}, + types::{Input, OpaqueBlock, OutputRef}, ConstraintChecker, }; use jsonrpsee::http_client::HttpClient; -use runtime::{ - money::Coin, opaque::Block as OpaqueBlock, timestamp::Timestamp, Block, OuterVerifier, -}; +use runtime::{money::Coin, timestamp::Timestamp, Block, OuterVerifier}; /// The identifier for the blocks tree in the db. const BLOCKS: &str = "blocks"; diff --git a/wardrobe/parachain/src/lib.rs b/wardrobe/parachain/src/lib.rs index 3b6f5d6e6..b04ab8192 100644 --- a/wardrobe/parachain/src/lib.rs +++ b/wardrobe/parachain/src/lib.rs @@ -21,7 +21,8 @@ use core::marker::PhantomData; -use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER}; +pub use cumulus_primitives_parachain_inherent::ParachainInherentData; +use cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; diff --git a/wardrobe/parachain/src/tests.rs b/wardrobe/parachain/src/tests.rs index a9cbadfa7..2522c8327 100644 --- a/wardrobe/parachain/src/tests.rs +++ b/wardrobe/parachain/src/tests.rs @@ -95,13 +95,11 @@ fn update_parachain_info_with_otherwise_valid_old_info_as_normal_input() { #[test] fn update_parachain_info_extra_outputs() { let old: DynamicallyTypedData = new_data_from_relay_parent_number(3).into(); - let inputs = vec![old]; let new1: DynamicallyTypedData = new_data_from_relay_parent_number(4).into(); let new2: DynamicallyTypedData = Bogus.into(); - let outputs = vec![new1.into(), new2.into()]; assert_eq!( - SetParachainInfo::(Default::default()).check(&inputs, &[], &[], &outputs), + SetParachainInfo::(Default::default()).check(&[old], &[], &[], &[new1, new2]), Err(ExtraOutputs) ); }