From 02a463fbd20369f24fe8f0f3bb53cd896d2779cd Mon Sep 17 00:00:00 2001 From: muraca Date: Tue, 7 Nov 2023 12:15:50 +0100 Subject: [PATCH 1/5] beautify `TuxedoGenesisConfig` Signed-off-by: muraca --- tuxedo-template-runtime/src/lib.rs | 56 +++++++----------------------- wardrobe/kitties/src/lib.rs | 39 ++++++++++++++++++++- wardrobe/money/src/lib.rs | 18 +++++++++- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index 044e4700b..a7c92e8a1 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -9,7 +9,6 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use kitties::FreeKittyConstraintChecker; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -110,9 +109,8 @@ pub struct TuxedoGenesisConfig(pub Vec); impl Default for TuxedoGenesisConfig { fn default() -> Self { use hex_literal::hex; - use kitties::{KittyDNA, KittyData, Parent}; - use money::{Coin, MoneyConstraintChecker}; - use sp_api::HashT; + use kitties::{KittyData, Parent}; + use money::Coin; const SHAWN_PUB_KEY_BYTES: [u8; 32] = hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); @@ -121,44 +119,14 @@ impl Default for TuxedoGenesisConfig { let signatories = vec![SHAWN_PUB_KEY_BYTES.into(), ANDREW_PUB_KEY_BYTES.into()]; let genesis_transactions = vec![ - // Money Transaction - Transaction { - inputs: vec![], - peeks: vec![], - outputs: vec![ - (Coin::<0>(100), SigCheck::new(SHAWN_PUB_KEY_BYTES)).into(), - (Coin::<0>(100), ThresholdMultiSignature::new(1, signatories)).into(), - ], - checker: MoneyConstraintChecker::Mint.into(), - }, - // Kitty Transaction - Transaction { - inputs: vec![], - peeks: vec![], - outputs: vec![ - ( - KittyData { - parent: Parent::Mom(Default::default()), - dna: KittyDNA(BlakeTwo256::hash_of(b"mother")), - ..Default::default() - }, - UpForGrabs, - ) - .into(), - ( - KittyData { - parent: Parent::Dad(Default::default()), - dna: KittyDNA(BlakeTwo256::hash_of(b"father")), - ..Default::default() - }, - UpForGrabs, - ) - .into(), - ], - checker: FreeKittyConstraintChecker.into(), - }, - // TODO: Initial Transactions for Existence + // Money Transactions + Coin::<0>::mint(100, SigCheck::new(SHAWN_PUB_KEY_BYTES)), + Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), + // Kitty Transactions + KittyData::mint(Parent::mom(), b"mother", UpForGrabs), + KittyData::mint(Parent::dad(), b"father", UpForGrabs), ]; + // TODO: Initial Transactions for Existence TuxedoGenesisConfig(genesis_transactions) } @@ -523,14 +491,14 @@ mod tests { }, }; - let tx = TuxedoGenesisConfig::default().0.get(0).unwrap().clone(); + let tx = TuxedoGenesisConfig::default().0.get(1).unwrap().clone(); - assert_eq!(tx.outputs.get(1), Some(&genesis_multi_sig_utxo)); + assert_eq!(tx.outputs.get(0), Some(&genesis_multi_sig_utxo)); let tx_hash = BlakeTwo256::hash_of(&tx.encode()); let output_ref = OutputRef { tx_hash, - index: 1_u32, + index: 0_u32, }; let encoded_utxo = diff --git a/wardrobe/kitties/src/lib.rs b/wardrobe/kitties/src/lib.rs index 9091c8f4c..49d7d4162 100644 --- a/wardrobe/kitties/src/lib.rs +++ b/wardrobe/kitties/src/lib.rs @@ -28,7 +28,9 @@ use sp_runtime::{ use sp_std::prelude::*; use tuxedo_core::{ dynamic_typing::{DynamicallyTypedData, UtxoData}, - ensure, SimpleConstraintChecker, + ensure, + types::Transaction, + SimpleConstraintChecker, Verifier, }; #[cfg(test)] @@ -111,6 +113,16 @@ pub enum Parent { Dad(DadKittyStatus), } +impl Parent { + pub fn dad() -> Self { + Parent::Dad(DadKittyStatus::RearinToGo) + } + + pub fn mom() -> Self { + Parent::Mom(MomKittyStatus::RearinToGo) + } +} + impl Default for Parent { fn default() -> Self { Parent::Mom(MomKittyStatus::RearinToGo) @@ -155,6 +167,31 @@ pub struct KittyData { pub num_breedings: u128, } +impl KittyData { + /// Create a mint transaction for a single Kitty. + pub fn mint(parent: Parent, dna_preimage: &[u8], v: V) -> Transaction + where + V: Verifier, + OV: Verifier + From, + OC: tuxedo_core::ConstraintChecker + From, + { + Transaction { + inputs: vec![], + peeks: vec![], + outputs: vec![( + KittyData { + parent, + dna: KittyDNA(BlakeTwo256::hash(dna_preimage)), + ..Default::default() + }, + v, + ) + .into()], + checker: FreeKittyConstraintChecker.into(), + } + } +} + impl Default for KittyData { fn default() -> Self { Self { diff --git a/wardrobe/money/src/lib.rs b/wardrobe/money/src/lib.rs index e3b714818..b012cc847 100644 --- a/wardrobe/money/src/lib.rs +++ b/wardrobe/money/src/lib.rs @@ -11,7 +11,8 @@ use tuxedo_core::{ dynamic_typing::{DynamicallyTypedData, UtxoData}, ensure, traits::Cash, - SimpleConstraintChecker, + types::Transaction, + SimpleConstraintChecker, Verifier, }; #[cfg(test)] @@ -75,6 +76,21 @@ impl Coin { pub fn new(amt: u128) -> Self { Coin(amt) } + + /// Create a mint transaction for a single Coin. + pub fn mint(amt: u128, v: V) -> Transaction + where + V: Verifier, + OV: Verifier + From, + OC: tuxedo_core::ConstraintChecker + From>, + { + Transaction { + inputs: vec![], + peeks: vec![], + outputs: vec![(Self::new(amt), v).into()], + checker: MoneyConstraintChecker::Mint.into(), + } + } } impl UtxoData for Coin { From 7088c0d8cd9d95c7f53dac1b036d2eac094868b6 Mon Sep 17 00:00:00 2001 From: muraca Date: Thu, 9 Nov 2023 17:47:46 +0100 Subject: [PATCH 2/5] move `TuxedoGenesisConfig` to `tuxedo-core::genesis` and remove `TuxedoGenesisConfig::default` implementation Signed-off-by: muraca --- Cargo.lock | 1 + node/Cargo.toml | 1 + node/src/chain_spec.rs | 50 +++++++++++++-- tuxedo-core/src/genesis.rs | 99 ++++++++++++++++++++++-------- tuxedo-template-runtime/src/lib.rs | 60 +----------------- 5 files changed, 123 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb0016809..ca36691bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4189,6 +4189,7 @@ name = "node-template" version = "4.0.0-dev" dependencies = [ "clap", + "hex-literal", "jsonrpsee", "sc-basic-authorship", "sc-cli", diff --git a/node/Cargo.toml b/node/Cargo.toml index 1d3b22412..2dd0eb514 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -12,6 +12,7 @@ targets = [ "x86_64-unknown-linux-gnu" ] [dependencies] clap = { features = [ "derive" ], workspace = true } +hex-literal = { workspace = true } sc-cli = { workspace = true } sc-client-api = { workspace = true } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index b2bdcd115..a738fb514 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -1,11 +1,22 @@ -use node_template_runtime::TuxedoGenesisConfig; +use hex_literal::hex; +use node_template_runtime::{ + kitties::{KittyData, Parent}, + money::Coin, + OuterConstraintChecker, OuterConstraintCheckerInherentHooks, OuterVerifier, WASM_BINARY, +}; use sc_service::ChainType; +use tuxedo_core::{ + genesis::TuxedoGenesisConfig, + inherents::InherentInternal, + verifier::{SigCheck, ThresholdMultiSignature, UpForGrabs}, +}; // The URL for the telemetry server. // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. -pub type ChainSpec = sc_service::GenericChainSpec; +pub type ChainSpec = + sc_service::GenericChainSpec>; // /// Generate a crypto pair from seed. // pub fn get_from_seed(seed: &str) -> ::Public { @@ -29,6 +40,35 @@ pub type ChainSpec = sc_service::GenericChainSpec; // (get_from_seed::(s), get_from_seed::(s)) // } +const SHAWN_PUB_KEY_BYTES: [u8; 32] = + hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); +const ANDREW_PUB_KEY_BYTES: [u8; 32] = + hex!("baa81e58b1b4d053c2e86d93045765036f9d265c7dfe8b9693bbc2c0f048d93a"); + +fn development_genesis_config() -> TuxedoGenesisConfig { + let signatories = vec![SHAWN_PUB_KEY_BYTES.into(), ANDREW_PUB_KEY_BYTES.into()]; + + // The inherents are computed using the appropriate method, and placed before the extrinsics. + let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); + + genesis_transactions.extend([ + // Money Transactions + Coin::<0>::mint(100, SigCheck::new(SHAWN_PUB_KEY_BYTES)), + Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), + // Kitty Transactions + KittyData::mint(Parent::mom(), b"mother", UpForGrabs), + KittyData::mint(Parent::dad(), b"father", UpForGrabs), + // TODO: Initial Transactions for Existence + ]); + + TuxedoGenesisConfig::new( + WASM_BINARY + .expect("Runtime WASM binary must exist.") + .to_vec(), + genesis_transactions, + ) +} + pub fn development_config() -> Result { Ok(ChainSpec::from_genesis( // Name @@ -36,7 +76,8 @@ pub fn development_config() -> Result { // ID "dev", ChainType::Development, - TuxedoGenesisConfig::default, + // TuxedoGenesisConfig + development_genesis_config, // Bootnodes vec![], // Telemetry @@ -58,7 +99,8 @@ pub fn local_testnet_config() -> Result { // ID "local_testnet", ChainType::Local, - TuxedoGenesisConfig::default, + // TuxedoGenesisConfig + development_genesis_config, // Bootnodes vec![], // Telemetry diff --git a/tuxedo-core/src/genesis.rs b/tuxedo-core/src/genesis.rs index e4117397f..9a8c0d372 100644 --- a/tuxedo-core/src/genesis.rs +++ b/tuxedo-core/src/genesis.rs @@ -2,14 +2,14 @@ use crate::{ ensure, - types::{OutputRef, Transaction}, - EXTRINSIC_KEY, + types::{Output, OutputRef, Transaction}, + ConstraintChecker, Verifier, EXTRINSIC_KEY, }; use parity_scale_codec::{Decode, Encode}; use sc_chain_spec::BuildGenesisBlock; use sc_client_api::backend::{Backend, BlockImportOperation}; use sc_executor::RuntimeVersionOf; -use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; use sp_core::{storage::Storage, traits::CodeExecutor}; use sp_runtime::{ traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, @@ -97,31 +97,78 @@ impl<'a, Block: BlockT, B: Backend, E: RuntimeVersionOf + CodeExecutor> } } -/// Assimilate the storage into the genesis block. -/// This is done by inserting the genesis extrinsics into the genesis block, along with their outputs. -/// Make sure to pass the transactions in order: the inherents should be first, then the extrinsics. -pub fn assimilate_storage( - storage: &mut Storage, +#[derive(Serialize, Deserialize)] +/// The `TuxedoGenesisConfig` struct is used to configure the genesis state of the runtime. +/// It expects the wasm binary and a list of transactions to be included in the genesis block, and stored along with their outputs. +/// They must not contain any inputs or peeks. These transactions will not be validated by the corresponding ConstraintChecker or Verifier. +/// Make sure to pass the inherents before the extrinsics. +pub struct TuxedoGenesisConfig { + wasm_binary: Vec, genesis_transactions: Vec>, -) -> Result<(), String> { - storage - .top - .insert(EXTRINSIC_KEY.to_vec(), genesis_transactions.encode()); - - for tx in genesis_transactions { - ensure!( - tx.inputs.is_empty() && tx.peeks.is_empty(), - "Genesis transactions must not have any inputs or peeks." - ); - let tx_hash = BlakeTwo256::hash_of(&tx.encode()); - for (index, utxo) in tx.outputs.iter().enumerate() { - let output_ref = OutputRef { - tx_hash, - index: index as u32, - }; - storage.top.insert(output_ref.encode(), utxo.encode()); +} + +impl TuxedoGenesisConfig { + /// Create a new `TuxedoGenesisConfig` from a WASM binary and a list of transactions. + /// Make sure to pass the transactions in order: the inherents should be first, then the extrinsics. + pub fn new(wasm_binary: Vec, genesis_transactions: Vec>) -> Self { + Self { + wasm_binary, + genesis_transactions, } } +} + +impl BuildStorage for TuxedoGenesisConfig +where + V: Verifier, + C: ConstraintChecker, + Transaction: Encode, + Output: Encode, +{ + /// Assimilate the storage into the genesis block. + /// This is done by inserting the genesis extrinsics into the genesis block, along with their outputs. + fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { + // The wasm binary is stored under a special key. + storage.top.insert( + sp_storage::well_known_keys::CODE.into(), + self.wasm_binary.clone(), + ); - Ok(()) + // The transactions are stored under a special key. + storage + .top + .insert(EXTRINSIC_KEY.to_vec(), self.genesis_transactions.encode()); + + let mut finished_with_opening_inherents = false; + + for tx in self.genesis_transactions.iter() { + // Enforce that inherents are in the right place + let current_tx_is_inherent = tx.checker.is_inherent(); + if current_tx_is_inherent && finished_with_opening_inherents { + return Err( + "Tried to execute opening inherent after switching to non-inherents.".into(), + ); + } + if !current_tx_is_inherent && !finished_with_opening_inherents { + // This is the first non-inherent, so we update our flag and continue. + finished_with_opening_inherents = true; + } + // Enforce that transactions do not have any inputs or peeks. + ensure!( + tx.inputs.is_empty() && tx.peeks.is_empty(), + "Genesis transactions must not have any inputs or peeks." + ); + // Insert the outputs into the storage. + let tx_hash = BlakeTwo256::hash_of(&tx.encode()); + for (index, utxo) in tx.outputs.iter().enumerate() { + let output_ref = OutputRef { + tx_hash, + index: index as u32, + }; + storage.top.insert(output_ref.encode(), utxo.encode()); + } + } + + Ok(()) + } } diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index a7c92e8a1..622ea7eca 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -11,10 +11,12 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); 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_core::OpaqueMetadata; use sp_inherents::InherentData; use sp_runtime::{ create_runtime_str, impl_opaque_keys, @@ -24,16 +26,10 @@ use sp_runtime::{ }; use sp_std::prelude::*; -use sp_core::OpaqueMetadata; -#[cfg(any(feature = "std", test))] -use sp_runtime::{BuildStorage, Storage}; - #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use serde::{Deserialize, Serialize}; - use tuxedo_core::{ tuxedo_constraint_checker, tuxedo_verifier, types::Transaction as TuxedoTransaction, @@ -100,58 +96,6 @@ pub fn native_version() -> NativeVersion { } } -#[derive(Serialize, Deserialize)] -/// The `TuxedoGenesisConfig` struct is used to configure the genesis state of the runtime. -/// The only parameter is a list of transactions to be included in the genesis block, and stored along with their outputs. -/// They must not contain any inputs or peeks. These transactions will not be validated by the corresponding ConstraintChecker or Verifier. -pub struct TuxedoGenesisConfig(pub Vec); - -impl Default for TuxedoGenesisConfig { - fn default() -> Self { - use hex_literal::hex; - use kitties::{KittyData, Parent}; - use money::Coin; - - const SHAWN_PUB_KEY_BYTES: [u8; 32] = - hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); - const ANDREW_PUB_KEY_BYTES: [u8; 32] = - hex!("baa81e58b1b4d053c2e86d93045765036f9d265c7dfe8b9693bbc2c0f048d93a"); - let signatories = vec![SHAWN_PUB_KEY_BYTES.into(), ANDREW_PUB_KEY_BYTES.into()]; - - let genesis_transactions = vec![ - // Money Transactions - Coin::<0>::mint(100, SigCheck::new(SHAWN_PUB_KEY_BYTES)), - Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), - // Kitty Transactions - KittyData::mint(Parent::mom(), b"mother", UpForGrabs), - KittyData::mint(Parent::dad(), b"father", UpForGrabs), - ]; - // TODO: Initial Transactions for Existence - - TuxedoGenesisConfig(genesis_transactions) - } -} - -#[cfg(feature = "std")] -impl BuildStorage for TuxedoGenesisConfig { - fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { - use tuxedo_core::inherents::InherentInternal; - - // The wasm binary is stored under a special key. - storage.top.insert( - sp_storage::well_known_keys::CODE.into(), - WASM_BINARY.unwrap().to_vec(), - ); - - // The inherents transactions are computed using the appropriate method, - // and placed in the block before the normal transactions. - let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); - genesis_transactions.extend(self.0.clone()); - - tuxedo_core::genesis::assimilate_storage(storage, genesis_transactions) - } -} - pub type Transaction = TuxedoTransaction; pub type BlockNumber = u32; pub type Header = sp_runtime::generic::Header; From 064335bc7444797544501df483185deacd749930 Mon Sep 17 00:00:00 2001 From: muraca Date: Thu, 9 Nov 2023 19:11:22 +0100 Subject: [PATCH 3/5] `RuntimeGenesisConfig` type, fixed tests Signed-off-by: muraca --- node/src/chain_spec.rs | 6 +-- tuxedo-core/src/genesis.rs | 4 ++ tuxedo-template-runtime/src/lib.rs | 60 ++++++++++++++++++++++++++---- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index a738fb514..0b5ec4d2e 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -2,7 +2,8 @@ use hex_literal::hex; use node_template_runtime::{ kitties::{KittyData, Parent}, money::Coin, - OuterConstraintChecker, OuterConstraintCheckerInherentHooks, OuterVerifier, WASM_BINARY, + OuterConstraintChecker, OuterConstraintCheckerInherentHooks, OuterVerifier, + RuntimeGenesisConfig, WASM_BINARY, }; use sc_service::ChainType; use tuxedo_core::{ @@ -15,8 +16,7 @@ use tuxedo_core::{ // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. -pub type ChainSpec = - sc_service::GenericChainSpec>; +pub type ChainSpec = sc_service::GenericChainSpec; // /// Generate a crypto pair from seed. // pub fn get_from_seed(seed: &str) -> ::Public { diff --git a/tuxedo-core/src/genesis.rs b/tuxedo-core/src/genesis.rs index 9a8c0d372..486c3ee75 100644 --- a/tuxedo-core/src/genesis.rs +++ b/tuxedo-core/src/genesis.rs @@ -116,6 +116,10 @@ impl TuxedoGenesisConfig { genesis_transactions, } } + + pub fn get_transaction(&self, i: usize) -> Option<&Transaction> { + self.genesis_transactions.get(i) + } } impl BuildStorage for TuxedoGenesisConfig diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index 622ea7eca..e239d3e4c 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -102,6 +102,9 @@ 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; +#[cfg(feature = "std")] +pub type RuntimeGenesisConfig = + tuxedo_core::genesis::TuxedoGenesisConfig; impl sp_runtime::traits::GetNodeBlockType for Runtime { type NodeBlock = opaque::Block; @@ -349,13 +352,17 @@ impl_runtime_apis! { #[cfg(test)] mod tests { use super::*; + use kitties::{KittyData, Parent}; + use money::Coin; use parity_scale_codec::Encode; use sp_api::HashT; use sp_core::testing::SR25519; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; + use sp_runtime::BuildStorage; use std::sync::Arc; use tuxedo_core::{ dynamic_typing::{DynamicallyTypedData, UtxoData}, + inherents::InherentInternal, types::OutputRef, }; @@ -365,20 +372,49 @@ mod tests { const ANDREW_PHRASE: &str = "monkey happy total rib lumber scrap guide photo country online rose diet"; - fn new_test_ext() -> sp_io::TestExternalities { + fn default_runtime_genesis_config() -> RuntimeGenesisConfig { let keystore = MemoryKeystore::new(); - let t = TuxedoGenesisConfig::default() + let shawn_pub_key_bytes = keystore + .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) + .unwrap() + .0; + + let andrew_pub_key_bytes = keystore + .sr25519_generate_new(SR25519, Some(ANDREW_PHRASE)) + .unwrap() + .0; + + let signatories = vec![shawn_pub_key_bytes.into(), andrew_pub_key_bytes.into()]; + + let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); + genesis_transactions.extend([ + // Money Transactions + Coin::<0>::mint(100, SigCheck::new(shawn_pub_key_bytes)), + Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), + ]); + + RuntimeGenesisConfig::new( + WASM_BINARY + .expect("Runtime WASM binary must exist.") + .to_vec(), + genesis_transactions, + ) + } + + fn new_test_ext() -> sp_io::TestExternalities { + let keystore = MemoryKeystore::new(); + let storage = default_runtime_genesis_config() .build_storage() .expect("System builds valid default genesis config"); - let mut ext = sp_io::TestExternalities::from(t); + let mut ext = sp_io::TestExternalities::from(storage); ext.register_extension(KeystoreExt(Arc::new(keystore))); ext } #[test] - fn utxo_money_test_genesis() { + fn genesis_utxo_money() { new_test_ext().execute_with(|| { let keystore = MemoryKeystore::new(); let shawn_pub_key = keystore @@ -396,7 +432,12 @@ mod tests { }, }; - let tx = TuxedoGenesisConfig::default().0.get(0).unwrap().clone(); + let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); + + let tx = default_runtime_genesis_config() + .get_transaction(0 + inherents_len) + .unwrap() + .clone(); assert_eq!(tx.outputs.get(0), Some(&genesis_utxo)); @@ -414,7 +455,7 @@ mod tests { } #[test] - fn utxo_money_multi_sig_genesis_test() { + fn genesis_utxo_money_multi_sig() { new_test_ext().execute_with(|| { let keystore = MemoryKeystore::new(); let shawn_pub_key = keystore @@ -435,7 +476,12 @@ mod tests { }, }; - let tx = TuxedoGenesisConfig::default().0.get(1).unwrap().clone(); + let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); + + let tx = default_runtime_genesis_config() + .get_transaction(1 + inherents_len) + .unwrap() + .clone(); assert_eq!(tx.outputs.get(0), Some(&genesis_multi_sig_utxo)); From 52b0b49e0930e10e71b3cdddf0f519cb854babe1 Mon Sep 17 00:00:00 2001 From: muraca Date: Thu, 9 Nov 2023 19:14:08 +0100 Subject: [PATCH 4/5] :) Signed-off-by: muraca --- tuxedo-template-runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index e239d3e4c..0f4032bb9 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -352,7 +352,7 @@ impl_runtime_apis! { #[cfg(test)] mod tests { use super::*; - use kitties::{KittyData, Parent}; + use money::Coin; use parity_scale_codec::Encode; use sp_api::HashT; @@ -435,7 +435,7 @@ mod tests { let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); let tx = default_runtime_genesis_config() - .get_transaction(0 + inherents_len) + .get_transaction(inherents_len) .unwrap() .clone(); From f80aac4ff47c10bb756e7ef8b012ce9158948e21 Mon Sep 17 00:00:00 2001 From: muraca Date: Sat, 11 Nov 2023 16:01:48 +0100 Subject: [PATCH 5/5] runtime mod genesis Signed-off-by: muraca --- Cargo.lock | 1 - node/Cargo.toml | 1 - node/src/chain_spec.rs | 42 +----- tuxedo-template-runtime/src/genesis.rs | 195 +++++++++++++++++++++++++ tuxedo-template-runtime/src/lib.rs | 156 +------------------- 5 files changed, 199 insertions(+), 196 deletions(-) create mode 100644 tuxedo-template-runtime/src/genesis.rs diff --git a/Cargo.lock b/Cargo.lock index ca36691bc..cb0016809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4189,7 +4189,6 @@ name = "node-template" version = "4.0.0-dev" dependencies = [ "clap", - "hex-literal", "jsonrpsee", "sc-basic-authorship", "sc-cli", diff --git a/node/Cargo.toml b/node/Cargo.toml index 2dd0eb514..1d3b22412 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -12,7 +12,6 @@ targets = [ "x86_64-unknown-linux-gnu" ] [dependencies] clap = { features = [ "derive" ], workspace = true } -hex-literal = { workspace = true } sc-cli = { workspace = true } sc-client-api = { workspace = true } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 0b5ec4d2e..750f8b9ad 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -1,16 +1,5 @@ -use hex_literal::hex; -use node_template_runtime::{ - kitties::{KittyData, Parent}, - money::Coin, - OuterConstraintChecker, OuterConstraintCheckerInherentHooks, OuterVerifier, - RuntimeGenesisConfig, WASM_BINARY, -}; +use node_template_runtime::genesis::*; use sc_service::ChainType; -use tuxedo_core::{ - genesis::TuxedoGenesisConfig, - inherents::InherentInternal, - verifier::{SigCheck, ThresholdMultiSignature, UpForGrabs}, -}; // The URL for the telemetry server. // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -40,35 +29,6 @@ pub type ChainSpec = sc_service::GenericChainSpec; // (get_from_seed::(s), get_from_seed::(s)) // } -const SHAWN_PUB_KEY_BYTES: [u8; 32] = - hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); -const ANDREW_PUB_KEY_BYTES: [u8; 32] = - hex!("baa81e58b1b4d053c2e86d93045765036f9d265c7dfe8b9693bbc2c0f048d93a"); - -fn development_genesis_config() -> TuxedoGenesisConfig { - let signatories = vec![SHAWN_PUB_KEY_BYTES.into(), ANDREW_PUB_KEY_BYTES.into()]; - - // The inherents are computed using the appropriate method, and placed before the extrinsics. - let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); - - genesis_transactions.extend([ - // Money Transactions - Coin::<0>::mint(100, SigCheck::new(SHAWN_PUB_KEY_BYTES)), - Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), - // Kitty Transactions - KittyData::mint(Parent::mom(), b"mother", UpForGrabs), - KittyData::mint(Parent::dad(), b"father", UpForGrabs), - // TODO: Initial Transactions for Existence - ]); - - TuxedoGenesisConfig::new( - WASM_BINARY - .expect("Runtime WASM binary must exist.") - .to_vec(), - genesis_transactions, - ) -} - pub fn development_config() -> Result { Ok(ChainSpec::from_genesis( // Name diff --git a/tuxedo-template-runtime/src/genesis.rs b/tuxedo-template-runtime/src/genesis.rs new file mode 100644 index 000000000..e41a604f4 --- /dev/null +++ b/tuxedo-template-runtime/src/genesis.rs @@ -0,0 +1,195 @@ +//! Helper module to build a genesis configuration for the template runtime. + +use super::{ + kitties::{KittyData, Parent}, + money::Coin, + OuterConstraintChecker, OuterConstraintCheckerInherentHooks, OuterVerifier, WASM_BINARY, +}; +use hex_literal::hex; +use tuxedo_core::{ + inherents::InherentInternal, + verifier::{SigCheck, ThresholdMultiSignature, UpForGrabs}, +}; + +/// Helper type for the ChainSpec. +pub type RuntimeGenesisConfig = + tuxedo_core::genesis::TuxedoGenesisConfig; + +const SHAWN_PUB_KEY_BYTES: [u8; 32] = + hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67"); +const ANDREW_PUB_KEY_BYTES: [u8; 32] = + hex!("baa81e58b1b4d053c2e86d93045765036f9d265c7dfe8b9693bbc2c0f048d93a"); + +pub fn development_genesis_config() -> RuntimeGenesisConfig { + let signatories = vec![SHAWN_PUB_KEY_BYTES.into(), ANDREW_PUB_KEY_BYTES.into()]; + + // The inherents are computed using the appropriate method, and placed before the extrinsics. + let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); + + genesis_transactions.extend([ + // Money Transactions + Coin::<0>::mint(100, SigCheck::new(SHAWN_PUB_KEY_BYTES)), + Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), + // Kitty Transactions + KittyData::mint(Parent::mom(), b"mother", UpForGrabs), + KittyData::mint(Parent::dad(), b"father", UpForGrabs), + // TODO: Initial Transactions for Existence + ]); + + RuntimeGenesisConfig::new( + WASM_BINARY + .expect("Runtime WASM binary must exist.") + .to_vec(), + genesis_transactions, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::OuterVerifier; + use parity_scale_codec::{Decode, Encode}; + use sp_api::HashT; + use sp_core::testing::SR25519; + use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; + use sp_runtime::{traits::BlakeTwo256, BuildStorage}; + use std::sync::Arc; + use tuxedo_core::{ + dynamic_typing::{DynamicallyTypedData, UtxoData}, + inherents::InherentInternal, + types::{Output, OutputRef}, + }; + + // other random account generated with subkey + const SHAWN_PHRASE: &str = + "news slush supreme milk chapter athlete soap sausage put clutch what kitten"; + const ANDREW_PHRASE: &str = + "monkey happy total rib lumber scrap guide photo country online rose diet"; + + fn default_runtime_genesis_config() -> RuntimeGenesisConfig { + let keystore = MemoryKeystore::new(); + + let shawn_pub_key_bytes = keystore + .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) + .unwrap() + .0; + + let andrew_pub_key_bytes = keystore + .sr25519_generate_new(SR25519, Some(ANDREW_PHRASE)) + .unwrap() + .0; + + let signatories = vec![shawn_pub_key_bytes.into(), andrew_pub_key_bytes.into()]; + + let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); + genesis_transactions.extend([ + // Money Transactions + Coin::<0>::mint(100, SigCheck::new(shawn_pub_key_bytes)), + Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), + ]); + + RuntimeGenesisConfig::new( + WASM_BINARY + .expect("Runtime WASM binary must exist.") + .to_vec(), + genesis_transactions, + ) + } + + fn new_test_ext() -> sp_io::TestExternalities { + let keystore = MemoryKeystore::new(); + let storage = default_runtime_genesis_config() + .build_storage() + .expect("System builds valid default genesis config"); + + let mut ext = sp_io::TestExternalities::from(storage); + ext.register_extension(KeystoreExt(Arc::new(keystore))); + ext + } + + #[test] + fn genesis_utxo_money() { + new_test_ext().execute_with(|| { + let keystore = MemoryKeystore::new(); + let shawn_pub_key = keystore + .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) + .unwrap(); + + // Grab genesis value from storage and assert it is correct + let genesis_utxo = Output { + verifier: OuterVerifier::SigCheck(SigCheck { + owner_pubkey: shawn_pub_key.into(), + }), + payload: DynamicallyTypedData { + data: 100u128.encode(), + type_id: as UtxoData>::TYPE_ID, + }, + }; + + let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); + + let tx = default_runtime_genesis_config() + .get_transaction(inherents_len) + .unwrap() + .clone(); + + assert_eq!(tx.outputs.get(0), Some(&genesis_utxo)); + + let tx_hash = BlakeTwo256::hash_of(&tx.encode()); + let output_ref = OutputRef { + tx_hash, + index: 0_u32, + }; + + let encoded_utxo = + sp_io::storage::get(&output_ref.encode()).expect("Retrieve Genesis UTXO"); + let utxo = Output::decode(&mut &encoded_utxo[..]).expect("Can Decode UTXO correctly"); + assert_eq!(utxo, genesis_utxo); + }) + } + + #[test] + fn genesis_utxo_money_multi_sig() { + new_test_ext().execute_with(|| { + let keystore = MemoryKeystore::new(); + let shawn_pub_key = keystore + .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) + .unwrap(); + let andrew_pub_key = keystore + .sr25519_generate_new(SR25519, Some(ANDREW_PHRASE)) + .unwrap(); + + let genesis_multi_sig_utxo = Output { + verifier: OuterVerifier::ThresholdMultiSignature(ThresholdMultiSignature { + threshold: 1, + signatories: vec![shawn_pub_key.into(), andrew_pub_key.into()], + }), + payload: DynamicallyTypedData { + data: 100u128.encode(), + type_id: as UtxoData>::TYPE_ID, + }, + }; + + let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); + + let tx = default_runtime_genesis_config() + .get_transaction(1 + inherents_len) + .unwrap() + .clone(); + + assert_eq!(tx.outputs.get(0), Some(&genesis_multi_sig_utxo)); + + let tx_hash = BlakeTwo256::hash_of(&tx.encode()); + let output_ref = OutputRef { + tx_hash, + index: 0_u32, + }; + + let encoded_utxo = + sp_io::storage::get(&output_ref.encode()).expect("Retrieve Genesis MultiSig UTXO"); + let utxo = Output::decode(&mut &encoded_utxo[..]).expect("Can Decode UTXO correctly"); + assert_eq!(utxo, genesis_multi_sig_utxo); + }) + } +} diff --git a/tuxedo-template-runtime/src/lib.rs b/tuxedo-template-runtime/src/lib.rs index 0f4032bb9..6ff6867ff 100644 --- a/tuxedo-template-runtime/src/lib.rs +++ b/tuxedo-template-runtime/src/lib.rs @@ -9,6 +9,9 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +#[cfg(feature = "std")] +pub mod genesis; + use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; @@ -102,9 +105,6 @@ 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; -#[cfg(feature = "std")] -pub type RuntimeGenesisConfig = - tuxedo_core::genesis::TuxedoGenesisConfig; impl sp_runtime::traits::GetNodeBlockType for Runtime { type NodeBlock = opaque::Block; @@ -348,153 +348,3 @@ impl_runtime_apis! { } } } - -#[cfg(test)] -mod tests { - use super::*; - - use money::Coin; - use parity_scale_codec::Encode; - use sp_api::HashT; - use sp_core::testing::SR25519; - use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; - use sp_runtime::BuildStorage; - use std::sync::Arc; - use tuxedo_core::{ - dynamic_typing::{DynamicallyTypedData, UtxoData}, - inherents::InherentInternal, - types::OutputRef, - }; - - // other random account generated with subkey - const SHAWN_PHRASE: &str = - "news slush supreme milk chapter athlete soap sausage put clutch what kitten"; - const ANDREW_PHRASE: &str = - "monkey happy total rib lumber scrap guide photo country online rose diet"; - - fn default_runtime_genesis_config() -> RuntimeGenesisConfig { - let keystore = MemoryKeystore::new(); - - let shawn_pub_key_bytes = keystore - .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) - .unwrap() - .0; - - let andrew_pub_key_bytes = keystore - .sr25519_generate_new(SR25519, Some(ANDREW_PHRASE)) - .unwrap() - .0; - - let signatories = vec![shawn_pub_key_bytes.into(), andrew_pub_key_bytes.into()]; - - let mut genesis_transactions = OuterConstraintCheckerInherentHooks::genesis_transactions(); - genesis_transactions.extend([ - // Money Transactions - Coin::<0>::mint(100, SigCheck::new(shawn_pub_key_bytes)), - Coin::<0>::mint(100, ThresholdMultiSignature::new(1, signatories)), - ]); - - RuntimeGenesisConfig::new( - WASM_BINARY - .expect("Runtime WASM binary must exist.") - .to_vec(), - genesis_transactions, - ) - } - - fn new_test_ext() -> sp_io::TestExternalities { - let keystore = MemoryKeystore::new(); - let storage = default_runtime_genesis_config() - .build_storage() - .expect("System builds valid default genesis config"); - - let mut ext = sp_io::TestExternalities::from(storage); - ext.register_extension(KeystoreExt(Arc::new(keystore))); - ext - } - - #[test] - fn genesis_utxo_money() { - new_test_ext().execute_with(|| { - let keystore = MemoryKeystore::new(); - let shawn_pub_key = keystore - .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) - .unwrap(); - - // Grab genesis value from storage and assert it is correct - let genesis_utxo = Output { - verifier: OuterVerifier::SigCheck(SigCheck { - owner_pubkey: shawn_pub_key.into(), - }), - payload: DynamicallyTypedData { - data: 100u128.encode(), - type_id: as UtxoData>::TYPE_ID, - }, - }; - - let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); - - let tx = default_runtime_genesis_config() - .get_transaction(inherents_len) - .unwrap() - .clone(); - - assert_eq!(tx.outputs.get(0), Some(&genesis_utxo)); - - let tx_hash = BlakeTwo256::hash_of(&tx.encode()); - let output_ref = OutputRef { - tx_hash, - index: 0_u32, - }; - - let encoded_utxo = - sp_io::storage::get(&output_ref.encode()).expect("Retrieve Genesis UTXO"); - let utxo = Output::decode(&mut &encoded_utxo[..]).expect("Can Decode UTXO correctly"); - assert_eq!(utxo, genesis_utxo); - }) - } - - #[test] - fn genesis_utxo_money_multi_sig() { - new_test_ext().execute_with(|| { - let keystore = MemoryKeystore::new(); - let shawn_pub_key = keystore - .sr25519_generate_new(SR25519, Some(SHAWN_PHRASE)) - .unwrap(); - let andrew_pub_key = keystore - .sr25519_generate_new(SR25519, Some(ANDREW_PHRASE)) - .unwrap(); - - let genesis_multi_sig_utxo = Output { - verifier: OuterVerifier::ThresholdMultiSignature(ThresholdMultiSignature { - threshold: 1, - signatories: vec![shawn_pub_key.into(), andrew_pub_key.into()], - }), - payload: DynamicallyTypedData { - data: 100u128.encode(), - type_id: as UtxoData>::TYPE_ID, - }, - }; - - let inherents_len = OuterConstraintCheckerInherentHooks::genesis_transactions().len(); - - let tx = default_runtime_genesis_config() - .get_transaction(1 + inherents_len) - .unwrap() - .clone(); - - assert_eq!(tx.outputs.get(0), Some(&genesis_multi_sig_utxo)); - - let tx_hash = BlakeTwo256::hash_of(&tx.encode()); - let output_ref = OutputRef { - tx_hash, - index: 0_u32, - }; - - let encoded_utxo = - sp_io::storage::get(&output_ref.encode()).expect("Retrieve Genesis MultiSig UTXO"); - let utxo = Output::decode(&mut &encoded_utxo[..]).expect("Can Decode UTXO correctly"); - assert_eq!(utxo, genesis_multi_sig_utxo); - }) - } -}