Skip to content

Commit

Permalink
move TuxedoGenesisConfig to tuxedo-core::genesis and remove `Tuxe…
Browse files Browse the repository at this point in the history
…doGenesisConfig::default`

Signed-off-by: muraca <mmuraca247@gmail.com>
  • Loading branch information
muraca committed Nov 9, 2023
1 parent 02a463f commit 5c4bddb
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 88 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
50 changes: 46 additions & 4 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -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<TuxedoGenesisConfig>;
pub type ChainSpec =
sc_service::GenericChainSpec<TuxedoGenesisConfig<OuterVerifier, OuterConstraintChecker>>;

// /// Generate a crypto pair from seed.
// pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
Expand All @@ -29,14 +40,44 @@ pub type ChainSpec = sc_service::GenericChainSpec<TuxedoGenesisConfig>;
// (get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
// }

const SHAWN_PUB_KEY_BYTES: [u8; 32] =
hex!("d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67");
const ANDREW_PUB_KEY_BYTES: [u8; 32] =
hex!("baa81e58b1b4d053c2e86d93045765036f9d265c7dfe8b9693bbc2c0f048d93a");

fn development_genesis_config() -> TuxedoGenesisConfig<OuterVerifier, OuterConstraintChecker> {
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<ChainSpec, String> {
Ok(ChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Development,
TuxedoGenesisConfig::default,
// TuxedoGenesisConfig
development_genesis_config,
// Bootnodes
vec![],
// Telemetry
Expand All @@ -58,7 +99,8 @@ pub fn local_testnet_config() -> Result<ChainSpec, String> {
// ID
"local_testnet",
ChainType::Local,
TuxedoGenesisConfig::default,
// TuxedoGenesisConfig
development_genesis_config,
// Bootnodes
vec![],
// Telemetry
Expand Down
99 changes: 73 additions & 26 deletions tuxedo-core/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -97,31 +97,78 @@ impl<'a, Block: BlockT, B: Backend<Block>, 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<V: Encode + TypeInfo, C: Encode + TypeInfo>(
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<V, C> {
wasm_binary: Vec<u8>,
genesis_transactions: Vec<Transaction<V, C>>,
) -> 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<V, C> TuxedoGenesisConfig<V, C> {
/// 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<u8>, genesis_transactions: Vec<Transaction<V, C>>) -> Self {
Self {
wasm_binary,
genesis_transactions,
}
}
}

impl<V, C> BuildStorage for TuxedoGenesisConfig<V, C>
where
V: Verifier,
C: ConstraintChecker<V>,
Transaction<V, C>: Encode,
Output<V>: 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(())
}
}
60 changes: 2 additions & 58 deletions tuxedo-template-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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<Transaction>);

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<OuterVerifier, OuterConstraintChecker>;
pub type BlockNumber = u32;
pub type Header = sp_runtime::generic::Header<BlockNumber, BlakeTwo256>;
Expand Down

0 comments on commit 5c4bddb

Please sign in to comment.