Genesis Builder

[!Note] Resolve all TODO in runtime/src/utxo.rs and runtime/src/chain_spec.rs to complete this step.

Reading Materials

We've almost complete the UTXO pallet. However we have no balance to test it, that's quite ridiculous 🫤.

In this tutorial, I'll show you how to add gensis data for pallet, have initial UTXO balances, and something to easier to test.

Moreover, you can add faucet extrinsic to pallet, that's work too. I let this is challenge for you. Feel free to complete it. The solution is on main branch.

Implement

Firstly, we've to declare genesis data type.

[!Important] Because code is built on no-std feature. If we keep using the TransactionOutput struct, we'll get error

... "the trait Serialize is not implemented for TransactionOutput" ...

... "the trait Deserialize<'_> is not implemented for TransactionOutput" ...

Hence, we need to simplify data type to make it work in both std and no-std feature.

#![allow(unused)]
fn main() {
...
/// Genesis Utxo Type
pub type GenesisUtxoType = (Value, H256);

...
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
    pub _ph_data: Option<PhantomData<T>>,
    pub genesis_utxos: Vec<GenesisUtxoType>,
}
}

Implement Default trait for GenesisConfig:

#![allow(unused)]
fn main() {
impl<T: Config> Default for GenesisConfig<T> {
    fn default() -> Self {
        Self {
            _ph_data: Default::default(),
            genesis_utxos: Vec::<GenesisUtxoType>::new(),
        }
    }
}
}

Implement logic to build genesis data

#![allow(unused)]
fn main() {
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
    fn build(&self) {
        for utxo in self.genesis_utxos.iter() {
            let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
            let hash = BlakeTwo256::hash_of(&utxo);
            Pallet::<T>::store_utxo(&utxo, hash);
        }
    }
}
}

Additionally, I've put some codes to make it easier for testing as mentioned above

#![allow(unused)]
fn main() {
...

/// Keep track of latest UTXO hash of account
/// Mapping from `sr25519::Pubkey` to `BlakeTwo256::hash_of(transaction, index)`
/// Just for testing 🫤
/// Because 1 account may have multiple UTXOs
#[pallet::storage]
#[pallet::getter(fn utxo_of)]
pub type UtxoOf<T: Config> =
    StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;

...

fn store_utxo(utxo: &TransactionOutput, hash: H256) {
    ...    
    // Convert H256 back to sr25519::Public
    let pubkey = Public::from_h256(utxo.pubkey);
    UtxoOf::<T>::insert(pubkey, hash);
}

...
}

Move on the node/src/chain_spec.rs, add some genesis data for pallet UTXO:


...

use academy_pow_runtime::{
    AccountId,
    SS58Prefix,
    Signature,
    TOKEN_DECIMALS,
    TOKEN_SYMBOL,
    WASM_BINARY,
+   utxo::{GenesisUtxoType, Value},
};

...

pub fn development_config() -> Result<ChainSpec, String> {
    Ok(ChainSpec::builder(
        WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
        ForkingExtensions {
            manual_mode: 1, // change this to `0` if you want to try `auto_fork_validation`
            add_sha3_keccak: 10,
            remove_md5: 20,
            split_sha3_keccak: 30,
            maxi_position: String::from("follow-mining"),
        },
    )
    .with_name("Development")
    .with_id("dev")
    .with_chain_type(ChainType::Development)
    .with_genesis_config_patch(genesis(
        // Pre-funded accounts
        vec![
            get_account_id_from_seed::<sr25519::Public>("Alice"),
            get_account_id_from_seed::<sr25519::Public>("Bob"),
            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        ],
        // Initial Difficulty
        4_000_000,
+       vec![
+           get_account_id_from_seed::<sr25519::Public>("Alice"),
+           get_account_id_from_seed::<sr25519::Public>("Bob"),
+           get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+           get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+       ],
    ))
    .with_properties(system_properties())
    .build())
}

...


pub fn testnet_config() -> Result<ChainSpec, String> {
    Ok(ChainSpec::builder(
        WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
        ForkingExtensions {
            manual_mode: 1,
            add_sha3_keccak: 0,
            remove_md5: 0,
            split_sha3_keccak: 0,
            maxi_position: String::new(),
        },
    )
    .with_name("Testnet")
    .with_id("testnet")
    .with_chain_type(ChainType::Local)
    .with_genesis_config_patch(genesis(
        vec![
            get_account_id_from_seed::<sr25519::Public>("Alice"),
            get_account_id_from_seed::<sr25519::Public>("Bob"),
            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        ],
        4_000_000,
+        vec![
+            get_account_id_from_seed::<sr25519::Public>("Alice"),
+            get_account_id_from_seed::<sr25519::Public>("Bob"),
+            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+        ],
    ))
    .with_properties(system_properties())
    .build())
}

...



fn genesis(
    endowed_accounts: Vec<AccountId>,
    initial_difficulty: u32,
+   utxo_genesis_accounts: Vec<AccountId>,
) -> serde_json::Value {
    serde_json::json!({
        "balances": {
            // Configure endowed accounts with initial balance of 1 << 50.
            "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 50)).collect::<Vec<_>>(),
        },
        "keccakDifficultyAdjustment": {
            "initialDifficulty": u32_to_u8_32(initial_difficulty),
        },
        "md5DifficultyAdjustment": {
            "initialDifficulty": u32_to_u8_32(initial_difficulty),
        },
        "sha3DifficultyAdjustment": {
            "initialDifficulty": u32_to_u8_32(initial_difficulty),
        },
+         "utxo": {
+             "genesisUtxos": utxo_genesis_accounts
+                 .iter().cloned()
+                 .map(|k| {
+                     let hash = H256::from_slice(&k.as_slice()); 
+                     let value: Value = (1u64 << 50).into();
+                     let genesis_utxo: GenesisUtxoType = (value, hash);
+                     genesis_utxo
+                 }).collect::<Vec<GenesisUtxoType>>(),
+         },
    })
}

...

We've add some balances for Alice, Bob, also hard-derive account of Alice and Bob. Let's testing.


Build the code

cargo build --release
# start temporary local node in development environment
./target/release/academy-pow --dev --tmp

[!Note] Because Substrate default account is in SS58 format, so we've to map that address to sr25519 format. Powerful tool to convert SS58 account to sr25519::Pubkey: https://polkadot.subscan.io/tools/format_transform

  • Alice: from 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY to 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
  • Bob: from 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty to 0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48

Direct to https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/chainstate.

Select pallet UTXO > utxoOf:

  • Input: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d, press + button.
  • Output:
utxo.utxoOf: Option<H256>
0xc670c5f69081da78af400552edcafa3f0f31e84db1b50dd70776e0f87477b3dc`

Select pallet UTXO > utxoStore:

  • Input: 0xc670c5f69081da78af400552edcafa3f0f31e84db1b50dd70776e0f87477b3dc, press + button.
  • Output:
utxo.utxoStore: Option<AcademyPowRuntimeUtxoTransactionOutput>
{
  value: 1,125,899,906,842,624
  pubkey: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
}

Great work completing a new step! 💪 You're almost at the finish line. Now, let's dive into last step. Run this command to continue:

#![allow(unused)]
fn main() {
use std::str::FromStr;

use academy_pow_runtime::{
	AccountId, SS58Prefix, Signature, TOKEN_DECIMALS, TOKEN_SYMBOL, WASM_BINARY,
    // TODO [6-genesis-builder]
    utxo::{GenesisUtxoType, Value},
};
use multi_pow::{ForkHeights, ForkingConfig, MaxiPosition};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, ByteArray, Pair, Public, H256};
use sp_runtime::traits::{IdentifyAccount, Verify};

/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<ForkingExtensions>;

/// PoW and Forking related chain spec extensions to configure the client side forking behavior.
///
/// The forks here are all related to adding and removing hash algorithms from the PoW.
/// The chain begins supporting only md5. Later is adds sha3 and keccak. Later it removes md5.
/// And finally there is a contentious fork where people become maxis.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct ForkingExtensions {
	/// Manual mode is intended for when we you are running a live workshop.
	/// No forking happens automatically. Rather, you have to hard-code the forks.
	///
	/// If manual mode is enabled, the rest of the parameters are ignored.
	/// This should really be an enum, but I have to work around the broken extension system.
	///
	/// Aww damn it! I can't even use bool in this broken system? Okay then I guess 0 means
	/// automatic mode and anything else means manual mode.
	pub manual_mode: u32,
	/// The block height to perform the soft fork that adds sha3 and keccak support.
	pub add_sha3_keccak: u32,
	/// The block height to perform the hard fork that removes md5 support.
	pub remove_md5: u32,
	/// The block height to perform the contentious fork where some become sha3- or keccak-maxis.
	pub split_sha3_keccak: u32,
	// Damn extension thing is so fragile, I can't even use an enum here.
	// Let alone that time I tried to use the forked value feature.
	/// The political position that this node will take at the contentious fork.
	pub maxi_position: String,
}

impl From<&ForkingExtensions> for ForkingConfig {
	fn from(e: &ForkingExtensions) -> Self {
		if e.manual_mode > 0 {
			return Self::Manual;
		}

		let fork_heights = ForkHeights {
			add_sha3_keccak: e.add_sha3_keccak,
			remove_md5: e.remove_md5,
			split_sha3_keccak: e.split_sha3_keccak,
		};

		let maxi_position =
			MaxiPosition::from_str(&e.maxi_position).expect("Should have a valid maxi position...");

		Self::Automatic(fork_heights, maxi_position)
	}
}

impl ForkingExtensions {
	/// Try to get the extension from the given `ChainSpec`.
	pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
		sc_chain_spec::get_extension(chain_spec.extensions())
	}
}

/// Generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
	TPublic::Pair::from_string(&format!("//{}", seed), None)
		.expect("static values are valid; qed")
		.public()
}

type AccountPublic = <Signature as Verify>::Signer;

/// Generate an account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
	AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}

pub fn development_config() -> Result<ChainSpec, String> {
	Ok(ChainSpec::builder(
		WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
		ForkingExtensions {
			manual_mode: 1, // change this to `0` if you want to try `auto_fork_validation`
			add_sha3_keccak: 10,
			remove_md5: 20,
			split_sha3_keccak: 30,
			maxi_position: String::from("follow-mining"),
		},
	)
	.with_name("Development")
	.with_id("dev")
	.with_chain_type(ChainType::Development)
	.with_genesis_config_patch(genesis(
		// Pre-funded accounts
		vec![
			get_account_id_from_seed::<sr25519::Public>("Alice"),
			get_account_id_from_seed::<sr25519::Public>("Bob"),
			get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
		],
		// Initial Difficulty
		4_000_000,
        // TODO [6-genesis-builder]
        // vec![
        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        // ],
	))
	.with_properties(system_properties())
	.build())
}

pub fn testnet_config() -> Result<ChainSpec, String> {
	Ok(ChainSpec::builder(
		WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
		ForkingExtensions {
			manual_mode: 1,
			add_sha3_keccak: 0,
			remove_md5: 0,
			split_sha3_keccak: 0,
			maxi_position: String::new(),
		},
	)
	.with_name("Testnet")
	.with_id("testnet")
	.with_chain_type(ChainType::Local)
	.with_genesis_config_patch(genesis(
		vec![
			get_account_id_from_seed::<sr25519::Public>("Alice"),
			get_account_id_from_seed::<sr25519::Public>("Bob"),
			get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
		],
		4_000_000,
        // TODO [6-genesis-builder]
        // vec![
        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        // ],
	))
	.with_properties(system_properties())
	.build())
}

fn genesis(
    endowed_accounts: Vec<AccountId>,
    initial_difficulty: u32,
    // TODO [6-genesis-builder]
    // utxo_genesis_accounts: Vec<AccountId>,
) -> serde_json::Value {
	serde_json::json!({
		"balances": {
			// Configure endowed accounts with initial balance of 1 << 50.
			"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 50)).collect::<Vec<_>>(),
		},
		"keccakDifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
		"md5DifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
		"sha3DifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
        // TODO [6-genesis-builder]
        // "utxo": {
        //     "genesisUtxos": utxo_genesis_accounts
        //         .iter().cloned()
        //         .map(|k| {
        //             let hash = H256::from_slice(&k.as_slice()); 
        //             let value: Value = (1u64 << 50).into();
        //             let genesis_utxo: GenesisUtxoType = (value, hash);

        //             genesis_utxo
        //         }).collect::<Vec<GenesisUtxoType>>(),
        // },
	})
}

/// Convert u32 (default value) to [u8;32] (U256)
/// in little-endian format
pub fn u32_to_u8_32(num: u32) -> [u8; 32] {
	let mut result = [0u8; 32];
	let bytes = num.to_le_bytes();
	result[..4].copy_from_slice(&bytes);
	result
}

fn system_properties() -> sc_chain_spec::Properties {
	let mut properties = sc_chain_spec::Properties::new();

	properties.insert("ss58Format".into(), SS58Prefix::get().into());
	properties.insert("tokenSymbol".into(), TOKEN_SYMBOL.into());
	properties.insert("tokenDecimals".into(), TOKEN_DECIMALS.into());

	properties
}
}
#![allow(unused)]
fn main() {
// We make sure this pallet uses `no_std` for compiling to Wasm.
#![cfg_attr(not(feature = "std"), no_std)]

use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_core::{
    sr25519::{Public, Signature},
    ByteArray, H256, H512,
};
use sp_runtime::traits::{BlakeTwo256, Hash, SaturatedConversion};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

use super::{block_author::BlockAuthor, issuance::Issuance};

pub use pallet::*;

/// [2-data-structure]
pub type Value = u128;

/// [2-data-structure]
/// Single transaction to be dispatched
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct Transaction {
    /// UTXOs to be used as inputs for current transaction
    pub inputs: Vec<TransactionInput>,
    /// UTXOs to be created as a result of current transaction dispatch
    pub outputs: Vec<TransactionOutput>,
}

/// [2-data-structure]
/// Single transaction input that refers to one UTXO
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct TransactionInput {
    /// Reference to an UTXO to be spent
    pub outpoint: H256,

    /// Proof that transaction owner is authorized to spend referred UTXO &
    /// that the entire transaction is untampered
    pub sigscript: H512,
}

/// [2-data-structure]
/// Single transaction output to create upon transaction dispatch
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct TransactionOutput {
    /// Value associated with this output
    pub value: Value,

    /// Public key associated with this output. In order to spend this output
    /// owner must provide a proof by hashing the whole `Transaction` and
    /// signing it with a corresponding private key.
    pub pubkey: H256,
}


/// TODO [6-genesis-builder]
/// Because code is built on `no-std` feature.
/// And we got error:
/// ```
/// ...
/// the trait `Serialize` is not implemented for `TransactionOutput`
/// the trait `Deserialize<'_>` is not implemented for `TransactionOutput`
/// ...
/// ```
///
/// Hence, we need to simplify data type to make it work in both `std` and `no-std` feature.
/// Genesis Utxo Type
// pub type GenesisUtxoType = (Value, H256);

#[frame_support::pallet(dev_mode)]
pub mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    use super::*;

    /// [2-data-structure]
    #[pallet::config]
    pub trait Config: frame_system::Config {
        /// Because this pallet emits events, it depends on the runtime's definition of an event.
        /// Read more: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_runtime_types/index.html
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

        /// A source to determine the block author
        type BlockAuthor: BlockAuthor;

        /// A source to determine the issuance portion of the block reward
        type Issuance: Issuance<BlockNumberFor<Self>, Value>;
    }

    #[pallet::pallet]
    pub struct Pallet<T>(_);


    /// [2-data-structure]
    /// Total reward value to be redistributed among authorities.
    /// It is accumulated from transactions during block execution
    /// and then dispersed to validators on block finalization.
    #[pallet::storage]
    #[pallet::getter(fn total_reward)]
    pub type TotalReward<T: Config> = StorageValue<_, Value, ValueQuery>;

    /// [2-data-structure]
    /// All valid unspent transaction outputs are stored in this map.
    /// Initial set of UTXO is populated from the list stored in genesis.
    /// We use the identity hasher here because the cryptographic hashing is
    /// done explicitly.
    /// Mapping from `BlakeTwo256::hash_of(transaction, index)` to `TransactionOutput`
    #[pallet::storage]
    #[pallet::getter(fn utxo_store)]
    pub type UtxoStore<T: Config> = StorageMap<
        Hasher = Identity,
        Key = H256,
        Value = TransactionOutput,
        QueryKind = OptionQuery,
    >;

    /// TODO [6-genesis-builder]
    /// Keep track of latest UTXO hash of account
    /// Mapping from `sr25519::Pubkey` to `BlakeTwo256::hash_of(transaction, index)`
    /// Just for testing 🫤
    /// Because 1 account may have multiple UTXOs
    // #[pallet::storage]
    // #[pallet::getter(fn utxo_of)]
    // pub type UtxoOf<T: Config> =
    //     StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;

    /// TODO [6-genesis-builder]
    // #[pallet::genesis_config]
    // pub struct GenesisConfig<T: Config> {
    //     pub _ph_data: Option<PhantomData<T>>,
    //     pub genesis_utxos: Vec<GenesisUtxoType>,
    // }

    /// TODO [6-genesis-builder]
    // impl<T: Config> Default for GenesisConfig<T> {
    //     fn default() -> Self {
    //         Self {
    //             _ph_data: Default::default(),
    //             genesis_utxos: Vec::<GenesisUtxoType>::new(),
    //         }
    //     }
    // }

    /// TODO [6-genesis-builder]
    // #[pallet::genesis_build]
    // impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
    //     fn build(&self) {
    //         for utxo in self.genesis_utxos.iter() {
    //             let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
    //             let hash = BlakeTwo256::hash_of(&utxo);
    //             Pallet::<T>::store_utxo(&utxo, hash);
    //         }
    //     }
    // }

    /// [2-data-structure]
    /// Pallets use events to inform users when important changes are made.
    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// Dispatch transaction successful
        TransactionSuccess(Transaction),
        /// UTXO out processed
        TransactionOutputProcessed(H256),
        /// Reward distributed to `BlockAuthor`
        RewardDistributed(Value, H256),
        /// Faucet to `To`
        Faucet(Value, H256),
        /// No one get reward
        RewardWasted,
    }


    /// [2-data-structure]
    /// Errors inform users that something went wrong.
    #[pallet::error]
    pub enum Error<T> {
        /// Missing `Transaction` Input
        MissingInput,
        /// Reward overflow
        RewardOverflow,
        /// Maximum transaction depth
        MaximumTransactionDepth,
        /// Empty input
        EmptyInput,
        /// Empty output
        EmptyOutput,
        /// Each input must only be used once
        DuplicatedInput,
        /// Each output must be defined only once
        DuplicatedOutput,
        /// Input value is overflow
        InputOverflow,
        /// Output value is overflow
        OutputOverflow,
        /// Output spent must lte than Input spent
        OutputOverInput,
        /// Zero amount spent
        ZeroAmount,
        /// Invalid signature
        InvalidSignature,
    }

    /// [4-dispersed-reward]
    #[pallet::hooks]
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
        fn on_finalize(_n: BlockNumberFor<T>) {
            match T::BlockAuthor::block_author() {
                // Block author did not provide key to claim reward
                None => Self::deposit_event(Event::RewardWasted),
                // Block author did provide key, so issue thir reward
                Some(author) => Self::disperse_reward(&author),
            }
        }
    }

    /// [2-data-structure]
    /// Define extrinsics / dispatchable function
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult {
            // [3-spend-utxo]
            // validate transaction
            let transaction_validity = Self::validate_transaction(&transaction)?;
            ensure!(
                transaction_validity.requires.is_empty(),
                Error::<T>::MissingInput
            );

            // implement logic
            Self::do_spend(&transaction, transaction_validity.priority as Value)?;
            // emit event
            Self::deposit_event(Event::<T>::TransactionSuccess(transaction));

            Ok(())
        }
    }

    /// [2-data-structure]
    /// Define intrinsics
    impl<T: Config> Pallet<T> {
        /// Implement spend logic, update storage to reflect changes made by transaction
        /// Where each UTXO key is a hash of the entire transaction and its order in the `TransactionOutputs` vector
        fn do_spend(transaction: &Transaction, reward: Value) -> DispatchResult {
            // [3-spend-utxo]
            // Calculate new reward total. The rest of `total_input - total_output` will be used for block reward.
            let new_total = TotalReward::<T>::get()
                .checked_add(reward)
                .ok_or(Error::<T>::RewardOverflow)?;
            TotalReward::<T>::put(new_total);

            // Removing spent UTXOs
            for input in &transaction.inputs {
                UtxoStore::<T>::remove(input.outpoint);
            }

            let mut index: u64 = 0;
            for output in &transaction.outputs {
                let hash = BlakeTwo256::hash_of(&(&transaction.encode(), index));
                // validated before, this is safe
                index = index
                    .checked_add(1)
                    .ok_or(Error::<T>::MaximumTransactionDepth)
                    .unwrap();
                Self::store_utxo(output, hash);
                Self::deposit_event(Event::TransactionOutputProcessed(hash));
            }

            Ok(())
        }

        /// Redistribute combined reward value to block Author
        fn disperse_reward(author: &Public) {
            // [4-dispersed-reward]

            // take the rest of reward
            // plus issuance reward of current block number
            let reward = TotalReward::<T>::take()
            + T::Issuance::issuance(frame_system::Pallet::<T>::block_number());

            let utxo = TransactionOutput {
                value: reward,
                pubkey: H256::from_slice(author.as_slice()),
            };

            let hash = BlakeTwo256::hash_of(&(
                &utxo,
                frame_system::Pallet::<T>::block_number().saturated_into::<u64>(),
            ));

            Self::store_utxo(&utxo, hash);
            Self::deposit_event(Event::RewardDistributed(reward, hash));  
        }

        /// Mutate storage, insert / update new UTXOs
        fn store_utxo(utxo: &TransactionOutput, hash: H256) {
            // [3-spend-utxo]
            UtxoStore::<T>::insert(hash, utxo);
            
            // TODO [6-genesis-builder]
            // Convert H256 back to sr25519::Public
            // let pubkey = Public::from_h256(utxo.pubkey);
            // UtxoOf::<T>::insert(pubkey, hash);
        }

        /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
        fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> {
            // [3-spend-utxo]
            let mut trx = transaction.clone();
            for input in trx.inputs.iter_mut() {
                input.sigscript = H512::zero();
            }

            trx.encode()
        }

        /// Check transaction for validity, errors, & race conditions
        /// Called by both transaction pool and runtime execution
        pub fn validate_transaction(
            transaction: &Transaction,
        ) -> Result<ValidTransaction, &'static str> {
            // [3-spend-utxo]
            // Check inputs and outputs are not empty
            ensure!(!transaction.inputs.is_empty(), Error::<T>::EmptyInput);
            ensure!(!transaction.outputs.is_empty(), Error::<T>::EmptyOutput);

            // Check each input is used exactly once
            {
                let input_set: BTreeMap<_, ()> =
                    transaction.inputs.iter().map(|input| (input, ())).collect();
                ensure!(
                    input_set.len() == transaction.inputs.len(),
                    Error::<T>::DuplicatedInput
                );
            }
            {
                let output_set: BTreeMap<_, ()> = transaction
                    .outputs
                    .iter()
                    .map(|output| (output, ()))
                    .collect();
                ensure!(
                    output_set.len() == transaction.outputs.len(),
                    Error::<T>::DuplicatedOutput
                );
            }

            let mut total_input: Value = 0;
            let mut total_output: Value = 0;
            let mut output_index: u64 = 0;
            let simple_transaction = Self::get_simple_transaction(transaction);

            // Variables sent to transaction pool
            let mut missing_utxos = Vec::new();
            let mut new_utxos = Vec::new();
            let mut reward = 0;

            for input in transaction.inputs.iter() {
                // Check all inputs match to existing, unspent and unlocked outputs
                if let Some(input_utxo) = UtxoStore::<T>::get(&input.outpoint) {
                    // Check provided signatures are valid
                    let is_valid_sig = sp_io::crypto::sr25519_verify(
                        &Signature::from_raw(*input.sigscript.as_fixed_bytes()),
                        &simple_transaction,
                        &Public::from_h256(input_utxo.pubkey),
                    );
                    ensure!(is_valid_sig, Error::<T>::InvalidSignature);
                    // Check sum of input values does not overflow
                    total_input = total_input
                        .checked_add(input_utxo.value)
                        .ok_or(Error::<T>::InputOverflow)?;
                } else {
                    missing_utxos.push(input.outpoint.clone().as_fixed_bytes().to_vec());
                }
            }

            // Check each output is defined exactly once and has nonzero value
            for output in transaction.outputs.iter() {
                ensure!(output.value > 0, Error::<T>::ZeroAmount);
                let hash = BlakeTwo256::hash_of(&(&transaction.encode(), output_index));
                output_index = output_index
                    .checked_add(1)
                    .ok_or(Error::<T>::MaximumTransactionDepth)?;
                // Check new outputs do not collide with existing ones
                ensure!(
                    !UtxoStore::<T>::contains_key(hash),
                    Error::<T>::DuplicatedOutput
                );
                // Check sum of output values does not overflow
                total_output = total_output
                    .checked_add(output.value)
                    .ok_or(Error::<T>::OutputOverflow)?;
                new_utxos.push(hash.as_fixed_bytes().to_vec());
            }

            // If no race condition, check the math
            if missing_utxos.is_empty() {
                // Check total output value must not exceed total input value
                ensure!(total_input >= total_output, Error::<T>::OutputOverInput);
                reward = total_input
                    .checked_sub(total_output)
                    .ok_or(Error::<T>::RewardOverflow)?;
            }

            // Returns transaction details
            Ok(ValidTransaction {
                requires: missing_utxos,
                provides: new_utxos,
                priority: reward as u64,
                longevity: TransactionLongevity::max_value(),
                propagate: true,
            })
        }
    }
}
}
#![allow(unused)]
fn main() {
use std::str::FromStr;

use academy_pow_runtime::{
	AccountId, SS58Prefix, Signature, TOKEN_DECIMALS, TOKEN_SYMBOL, WASM_BINARY,
    // [6-genesis-builder]
    utxo::{GenesisUtxoType, Value},
};
use multi_pow::{ForkHeights, ForkingConfig, MaxiPosition};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, ByteArray, Pair, Public, H256};
use sp_runtime::traits::{IdentifyAccount, Verify};

/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<ForkingExtensions>;

/// PoW and Forking related chain spec extensions to configure the client side forking behavior.
///
/// The forks here are all related to adding and removing hash algorithms from the PoW.
/// The chain begins supporting only md5. Later is adds sha3 and keccak. Later it removes md5.
/// And finally there is a contentious fork where people become maxis.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct ForkingExtensions {
	/// Manual mode is intended for when we you are running a live workshop.
	/// No forking happens automatically. Rather, you have to hard-code the forks.
	///
	/// If manual mode is enabled, the rest of the parameters are ignored.
	/// This should really be an enum, but I have to work around the broken extension system.
	///
	/// Aww damn it! I can't even use bool in this broken system? Okay then I guess 0 means
	/// automatic mode and anything else means manual mode.
	pub manual_mode: u32,
	/// The block height to perform the soft fork that adds sha3 and keccak support.
	pub add_sha3_keccak: u32,
	/// The block height to perform the hard fork that removes md5 support.
	pub remove_md5: u32,
	/// The block height to perform the contentious fork where some become sha3- or keccak-maxis.
	pub split_sha3_keccak: u32,
	// Damn extension thing is so fragile, I can't even use an enum here.
	// Let alone that time I tried to use the forked value feature.
	/// The political position that this node will take at the contentious fork.
	pub maxi_position: String,
}

impl From<&ForkingExtensions> for ForkingConfig {
	fn from(e: &ForkingExtensions) -> Self {
		if e.manual_mode > 0 {
			return Self::Manual;
		}

		let fork_heights = ForkHeights {
			add_sha3_keccak: e.add_sha3_keccak,
			remove_md5: e.remove_md5,
			split_sha3_keccak: e.split_sha3_keccak,
		};

		let maxi_position =
			MaxiPosition::from_str(&e.maxi_position).expect("Should have a valid maxi position...");

		Self::Automatic(fork_heights, maxi_position)
	}
}

impl ForkingExtensions {
	/// Try to get the extension from the given `ChainSpec`.
	pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
		sc_chain_spec::get_extension(chain_spec.extensions())
	}
}

/// Generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
	TPublic::Pair::from_string(&format!("//{}", seed), None)
		.expect("static values are valid; qed")
		.public()
}

type AccountPublic = <Signature as Verify>::Signer;

/// Generate an account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
	AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}

pub fn development_config() -> Result<ChainSpec, String> {
	Ok(ChainSpec::builder(
		WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
		ForkingExtensions {
			manual_mode: 1, // change this to `0` if you want to try `auto_fork_validation`
			add_sha3_keccak: 10,
			remove_md5: 20,
			split_sha3_keccak: 30,
			maxi_position: String::from("follow-mining"),
		},
	)
	.with_name("Development")
	.with_id("dev")
	.with_chain_type(ChainType::Development)
	.with_genesis_config_patch(genesis(
		// Pre-funded accounts
		vec![
			get_account_id_from_seed::<sr25519::Public>("Alice"),
			get_account_id_from_seed::<sr25519::Public>("Bob"),
			get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
		],
		// Initial Difficulty
		4_000_000,
        // [6-genesis-builder]
        vec![
            get_account_id_from_seed::<sr25519::Public>("Alice"),
            get_account_id_from_seed::<sr25519::Public>("Bob"),
            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        ],
	))
	.with_properties(system_properties())
	.build())
}

pub fn testnet_config() -> Result<ChainSpec, String> {
	Ok(ChainSpec::builder(
		WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
		ForkingExtensions {
			manual_mode: 1,
			add_sha3_keccak: 0,
			remove_md5: 0,
			split_sha3_keccak: 0,
			maxi_position: String::new(),
		},
	)
	.with_name("Testnet")
	.with_id("testnet")
	.with_chain_type(ChainType::Local)
	.with_genesis_config_patch(genesis(
		vec![
			get_account_id_from_seed::<sr25519::Public>("Alice"),
			get_account_id_from_seed::<sr25519::Public>("Bob"),
			get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
		],
		4_000_000,
        // [6-genesis-builder]
        vec![
            get_account_id_from_seed::<sr25519::Public>("Alice"),
            get_account_id_from_seed::<sr25519::Public>("Bob"),
            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        ],
	))
	.with_properties(system_properties())
	.build())
}

fn genesis(
    endowed_accounts: Vec<AccountId>,
    initial_difficulty: u32,
    // [6-genesis-builder]
    utxo_genesis_accounts: Vec<AccountId>,
) -> serde_json::Value {
	serde_json::json!({
		"balances": {
			// Configure endowed accounts with initial balance of 1 << 50.
			"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 50)).collect::<Vec<_>>(),
		},
		"keccakDifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
		"md5DifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
		"sha3DifficultyAdjustment": {
			"initialDifficulty": u32_to_u8_32(initial_difficulty),
		},
        // [6-genesis-builder]
        "utxo": {
            "genesisUtxos": utxo_genesis_accounts
                .iter().cloned()
                .map(|k| {
                    let hash = H256::from_slice(&k.as_slice()); 
                    let value: Value = (1u64 << 50).into();
                    let genesis_utxo: GenesisUtxoType = (value, hash);

                    genesis_utxo
                }).collect::<Vec<GenesisUtxoType>>(),
        },
	})
}

/// Convert u32 (default value) to [u8;32] (U256)
/// in little-endian format
pub fn u32_to_u8_32(num: u32) -> [u8; 32] {
	let mut result = [0u8; 32];
	let bytes = num.to_le_bytes();
	result[..4].copy_from_slice(&bytes);
	result
}

fn system_properties() -> sc_chain_spec::Properties {
	let mut properties = sc_chain_spec::Properties::new();

	properties.insert("ss58Format".into(), SS58Prefix::get().into());
	properties.insert("tokenSymbol".into(), TOKEN_SYMBOL.into());
	properties.insert("tokenDecimals".into(), TOKEN_DECIMALS.into());

	properties
}
}
#![allow(unused)]
fn main() {
// We make sure this pallet uses `no_std` for compiling to Wasm.
#![cfg_attr(not(feature = "std"), no_std)]

use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_core::{
    sr25519::{Public, Signature},
    ByteArray, H256, H512,
};
use sp_runtime::traits::{BlakeTwo256, Hash, SaturatedConversion};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

use super::{block_author::BlockAuthor, issuance::Issuance};

pub use pallet::*;

/// [2-data-structure]
pub type Value = u128;

/// [2-data-structure]
/// Single transaction to be dispatched
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct Transaction {
    /// UTXOs to be used as inputs for current transaction
    pub inputs: Vec<TransactionInput>,
    /// UTXOs to be created as a result of current transaction dispatch
    pub outputs: Vec<TransactionOutput>,
}

/// [2-data-structure]
/// Single transaction input that refers to one UTXO
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct TransactionInput {
    /// Reference to an UTXO to be spent
    pub outpoint: H256,

    /// Proof that transaction owner is authorized to spend referred UTXO &
    /// that the entire transaction is untampered
    pub sigscript: H512,
}

/// [2-data-structure]
/// Single transaction output to create upon transaction dispatch
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
pub struct TransactionOutput {
    /// Value associated with this output
    pub value: Value,

    /// Public key associated with this output. In order to spend this output
    /// owner must provide a proof by hashing the whole `Transaction` and
    /// signing it with a corresponding private key.
    pub pubkey: H256,
}


/// [6-genesis-builder]
/// Because code is built on `no-std` feature.
/// And we got error:
/// ```
/// ...
/// the trait `Serialize` is not implemented for `TransactionOutput`
/// the trait `Deserialize<'_>` is not implemented for `TransactionOutput`
/// ...
/// ```
///
/// Hence, we need to simplify data type to make it work in both `std` and `no-std` feature.
/// Genesis Utxo Type
pub type GenesisUtxoType = (Value, H256);

#[frame_support::pallet(dev_mode)]
pub mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    use super::*;

    /// [2-data-structure]
    #[pallet::config]
    pub trait Config: frame_system::Config {
        /// Because this pallet emits events, it depends on the runtime's definition of an event.
        /// Read more: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_runtime_types/index.html
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

        /// A source to determine the block author
        type BlockAuthor: BlockAuthor;

        /// A source to determine the issuance portion of the block reward
        type Issuance: Issuance<BlockNumberFor<Self>, Value>;
    }

    #[pallet::pallet]
    pub struct Pallet<T>(_);


    /// [2-data-structure]
    /// Total reward value to be redistributed among authorities.
    /// It is accumulated from transactions during block execution
    /// and then dispersed to validators on block finalization.
    #[pallet::storage]
    #[pallet::getter(fn total_reward)]
    pub type TotalReward<T: Config> = StorageValue<_, Value, ValueQuery>;

    /// [2-data-structure]
    /// All valid unspent transaction outputs are stored in this map.
    /// Initial set of UTXO is populated from the list stored in genesis.
    /// We use the identity hasher here because the cryptographic hashing is
    /// done explicitly.
    /// Mapping from `BlakeTwo256::hash_of(transaction, index)` to `TransactionOutput`
    #[pallet::storage]
    #[pallet::getter(fn utxo_store)]
    pub type UtxoStore<T: Config> = StorageMap<
        Hasher = Identity,
        Key = H256,
        Value = TransactionOutput,
        QueryKind = OptionQuery,
    >;

    /// [6-genesis-builder]
    /// Keep track of latest UTXO hash of account
    /// Mapping from `sr25519::Pubkey` to `BlakeTwo256::hash_of(transaction, index)`
    /// Just for testing 🫤
    /// Because 1 account may have multiple UTXOs
    #[pallet::storage]
    #[pallet::getter(fn utxo_of)]
    pub type UtxoOf<T: Config> =
        StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;

    /// [6-genesis-builder]
    #[pallet::genesis_config]
    pub struct GenesisConfig<T: Config> {
        pub _ph_data: Option<PhantomData<T>>,
        pub genesis_utxos: Vec<GenesisUtxoType>,
    }

    /// [6-genesis-builder]
    impl<T: Config> Default for GenesisConfig<T> {
        fn default() -> Self {
            Self {
                _ph_data: Default::default(),
                genesis_utxos: Vec::<GenesisUtxoType>::new(),
            }
        }
    }

    /// [6-genesis-builder]
    #[pallet::genesis_build]
    impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
        fn build(&self) {
            for utxo in self.genesis_utxos.iter() {
                let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
                let hash = BlakeTwo256::hash_of(&utxo);
                Pallet::<T>::store_utxo(&utxo, hash);
            }
        }
    }

    /// [2-data-structure]
    /// Pallets use events to inform users when important changes are made.
    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// Dispatch transaction successful
        TransactionSuccess(Transaction),
        /// UTXO out processed
        TransactionOutputProcessed(H256),
        /// Reward distributed to `BlockAuthor`
        RewardDistributed(Value, H256),
        /// Faucet to `To`
        Faucet(Value, H256),
        /// No one get reward
        RewardWasted,
    }


    /// [2-data-structure]
    /// Errors inform users that something went wrong.
    #[pallet::error]
    pub enum Error<T> {
        /// Missing `Transaction` Input
        MissingInput,
        /// Reward overflow
        RewardOverflow,
        /// Maximum transaction depth
        MaximumTransactionDepth,
        /// Empty input
        EmptyInput,
        /// Empty output
        EmptyOutput,
        /// Each input must only be used once
        DuplicatedInput,
        /// Each output must be defined only once
        DuplicatedOutput,
        /// Input value is overflow
        InputOverflow,
        /// Output value is overflow
        OutputOverflow,
        /// Output spent must lte than Input spent
        OutputOverInput,
        /// Zero amount spent
        ZeroAmount,
        /// Invalid signature
        InvalidSignature,
    }

    /// [4-dispersed-reward]
    #[pallet::hooks]
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
        fn on_finalize(_n: BlockNumberFor<T>) {
            match T::BlockAuthor::block_author() {
                // Block author did not provide key to claim reward
                None => Self::deposit_event(Event::RewardWasted),
                // Block author did provide key, so issue thir reward
                Some(author) => Self::disperse_reward(&author),
            }
        }
    }

    /// [2-data-structure]
    /// Define extrinsics / dispatchable function
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult {
            // [3-spend-utxo]
            // validate transaction
            let transaction_validity = Self::validate_transaction(&transaction)?;
            ensure!(
                transaction_validity.requires.is_empty(),
                Error::<T>::MissingInput
            );

            // implement logic
            Self::do_spend(&transaction, transaction_validity.priority as Value)?;
            // emit event
            Self::deposit_event(Event::<T>::TransactionSuccess(transaction));

            Ok(())
        }
    }

    /// [2-data-structure]
    /// Define intrinsics
    impl<T: Config> Pallet<T> {
        /// Implement spend logic, update storage to reflect changes made by transaction
        /// Where each UTXO key is a hash of the entire transaction and its order in the `TransactionOutputs` vector
        fn do_spend(transaction: &Transaction, reward: Value) -> DispatchResult {
            // [3-spend-utxo]
            // Calculate new reward total. The rest of `total_input - total_output` will be used for block reward.
            let new_total = TotalReward::<T>::get()
                .checked_add(reward)
                .ok_or(Error::<T>::RewardOverflow)?;
            TotalReward::<T>::put(new_total);

            // Removing spent UTXOs
            for input in &transaction.inputs {
                UtxoStore::<T>::remove(input.outpoint);
            }

            let mut index: u64 = 0;
            for output in &transaction.outputs {
                let hash = BlakeTwo256::hash_of(&(&transaction.encode(), index));
                // validated before, this is safe
                index = index
                    .checked_add(1)
                    .ok_or(Error::<T>::MaximumTransactionDepth)
                    .unwrap();
                Self::store_utxo(output, hash);
                Self::deposit_event(Event::TransactionOutputProcessed(hash));
            }

            Ok(())
        }

        /// Redistribute combined reward value to block Author
        fn disperse_reward(author: &Public) {
            // [4-dispersed-reward]

            // take the rest of reward
            // plus issuance reward of current block number
            let reward = TotalReward::<T>::take()
            + T::Issuance::issuance(frame_system::Pallet::<T>::block_number());

            let utxo = TransactionOutput {
                value: reward,
                pubkey: H256::from_slice(author.as_slice()),
            };

            let hash = BlakeTwo256::hash_of(&(
                &utxo,
                frame_system::Pallet::<T>::block_number().saturated_into::<u64>(),
            ));

            Self::store_utxo(&utxo, hash);
            Self::deposit_event(Event::RewardDistributed(reward, hash));  
        }

        /// Mutate storage, insert / update new UTXOs
        fn store_utxo(utxo: &TransactionOutput, hash: H256) {
            // [3-spend-utxo]
            UtxoStore::<T>::insert(hash, utxo);
            
            // [6-genesis-builder]
            // Convert H256 back to sr25519::Public
            let pubkey = Public::from_h256(utxo.pubkey);
            UtxoOf::<T>::insert(pubkey, hash);
        }

        /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
        fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> {
            // [3-spend-utxo]
            let mut trx = transaction.clone();
            for input in trx.inputs.iter_mut() {
                input.sigscript = H512::zero();
            }

            trx.encode()
        }

        /// Check transaction for validity, errors, & race conditions
        /// Called by both transaction pool and runtime execution
        pub fn validate_transaction(
            transaction: &Transaction,
        ) -> Result<ValidTransaction, &'static str> {
            // [3-spend-utxo]
            // Check inputs and outputs are not empty
            ensure!(!transaction.inputs.is_empty(), Error::<T>::EmptyInput);
            ensure!(!transaction.outputs.is_empty(), Error::<T>::EmptyOutput);

            // Check each input is used exactly once
            {
                let input_set: BTreeMap<_, ()> =
                    transaction.inputs.iter().map(|input| (input, ())).collect();
                ensure!(
                    input_set.len() == transaction.inputs.len(),
                    Error::<T>::DuplicatedInput
                );
            }
            {
                let output_set: BTreeMap<_, ()> = transaction
                    .outputs
                    .iter()
                    .map(|output| (output, ()))
                    .collect();
                ensure!(
                    output_set.len() == transaction.outputs.len(),
                    Error::<T>::DuplicatedOutput
                );
            }

            let mut total_input: Value = 0;
            let mut total_output: Value = 0;
            let mut output_index: u64 = 0;
            let simple_transaction = Self::get_simple_transaction(transaction);

            // Variables sent to transaction pool
            let mut missing_utxos = Vec::new();
            let mut new_utxos = Vec::new();
            let mut reward = 0;

            for input in transaction.inputs.iter() {
                // Check all inputs match to existing, unspent and unlocked outputs
                if let Some(input_utxo) = UtxoStore::<T>::get(&input.outpoint) {
                    // Check provided signatures are valid
                    let is_valid_sig = sp_io::crypto::sr25519_verify(
                        &Signature::from_raw(*input.sigscript.as_fixed_bytes()),
                        &simple_transaction,
                        &Public::from_h256(input_utxo.pubkey),
                    );
                    ensure!(is_valid_sig, Error::<T>::InvalidSignature);
                    // Check sum of input values does not overflow
                    total_input = total_input
                        .checked_add(input_utxo.value)
                        .ok_or(Error::<T>::InputOverflow)?;
                } else {
                    missing_utxos.push(input.outpoint.clone().as_fixed_bytes().to_vec());
                }
            }

            // Check each output is defined exactly once and has nonzero value
            for output in transaction.outputs.iter() {
                ensure!(output.value > 0, Error::<T>::ZeroAmount);
                let hash = BlakeTwo256::hash_of(&(&transaction.encode(), output_index));
                output_index = output_index
                    .checked_add(1)
                    .ok_or(Error::<T>::MaximumTransactionDepth)?;
                // Check new outputs do not collide with existing ones
                ensure!(
                    !UtxoStore::<T>::contains_key(hash),
                    Error::<T>::DuplicatedOutput
                );
                // Check sum of output values does not overflow
                total_output = total_output
                    .checked_add(output.value)
                    .ok_or(Error::<T>::OutputOverflow)?;
                new_utxos.push(hash.as_fixed_bytes().to_vec());
            }

            // If no race condition, check the math
            if missing_utxos.is_empty() {
                // Check total output value must not exceed total input value
                ensure!(total_input >= total_output, Error::<T>::OutputOverInput);
                reward = total_input
                    .checked_sub(total_output)
                    .ok_or(Error::<T>::RewardOverflow)?;
            }

            // Returns transaction details
            Ok(ValidTransaction {
                requires: missing_utxos,
                provides: new_utxos,
                priority: reward as u64,
                longevity: TransactionLongevity::max_value(),
                propagate: true,
            })
        }
    }
}
}
diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs
index 091d0e8..90e5e84 100644
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -2,6 +2,8 @@ use std::str::FromStr;
 
 use academy_pow_runtime::{
 	AccountId, SS58Prefix, Signature, TOKEN_DECIMALS, TOKEN_SYMBOL, WASM_BINARY,
+    // TODO [6-genesis-builder]
+    utxo::{GenesisUtxoType, Value},
 };
 use multi_pow::{ForkHeights, ForkingConfig, MaxiPosition};
 use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
@@ -109,6 +111,13 @@ pub fn development_config() -> Result<ChainSpec, String> {
 		],
 		// Initial Difficulty
 		4_000_000,
+        // TODO [6-genesis-builder]
+        // vec![
+        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
+        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
+        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+        // ],
 	))
 	.with_properties(system_properties())
 	.build())
@@ -136,12 +145,24 @@ pub fn testnet_config() -> Result<ChainSpec, String> {
 			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
 		],
 		4_000_000,
+        // TODO [6-genesis-builder]
+        // vec![
+        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
+        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
+        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+        // ],
 	))
 	.with_properties(system_properties())
 	.build())
 }
 
-fn genesis(endowed_accounts: Vec<AccountId>, initial_difficulty: u32) -> serde_json::Value {
+fn genesis(
+    endowed_accounts: Vec<AccountId>,
+    initial_difficulty: u32,
+    // TODO [6-genesis-builder]
+    // utxo_genesis_accounts: Vec<AccountId>,
+) -> serde_json::Value {
 	serde_json::json!({
 		"balances": {
 			// Configure endowed accounts with initial balance of 1 << 50.
@@ -156,6 +177,18 @@ fn genesis(endowed_accounts: Vec<AccountId>, initial_difficulty: u32) -> serde_j
 		"sha3DifficultyAdjustment": {
 			"initialDifficulty": u32_to_u8_32(initial_difficulty),
 		},
+        // TODO [6-genesis-builder]
+        // "utxo": {
+        //     "genesisUtxos": utxo_genesis_accounts
+        //         .iter().cloned()
+        //         .map(|k| {
+        //             let hash = H256::from_slice(&k.as_slice()); 
+        //             let value: Value = (1u64 << 50).into();
+        //             let genesis_utxo: GenesisUtxoType = (value, hash);
+
+        //             genesis_utxo
+        //         }).collect::<Vec<GenesisUtxoType>>(),
+        // },
 	})
 }
 
diff --git a/runtime/src/utxo.rs b/runtime/src/utxo.rs
index ed8ec6a..0632046 100644
--- a/runtime/src/utxo.rs
+++ b/runtime/src/utxo.rs
@@ -57,6 +57,21 @@ pub struct TransactionOutput {
     pub pubkey: H256,
 }
 
+
+/// TODO [6-genesis-builder]
+/// Because code is built on `no-std` feature.
+/// And we got error:
+/// ```
+/// ...
+/// the trait `Serialize` is not implemented for `TransactionOutput`
+/// the trait `Deserialize<'_>` is not implemented for `TransactionOutput`
+/// ...
+/// ```
+///
+/// Hence, we need to simplify data type to make it work in both `std` and `no-std` feature.
+/// Genesis Utxo Type
+// pub type GenesisUtxoType = (Value, H256);
+
 #[frame_support::pallet(dev_mode)]
 pub mod pallet {
     use frame_support::pallet_prelude::*;
@@ -105,6 +120,44 @@ pub mod pallet {
         QueryKind = OptionQuery,
     >;
 
+    /// TODO [6-genesis-builder]
+    /// Keep track of latest UTXO hash of account
+    /// Mapping from `sr25519::Pubkey` to `BlakeTwo256::hash_of(transaction, index)`
+    /// Just for testing 🫤
+    /// Because 1 account may have multiple UTXOs
+    // #[pallet::storage]
+    // #[pallet::getter(fn utxo_of)]
+    // pub type UtxoOf<T: Config> =
+    //     StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;
+
+    /// TODO [6-genesis-builder]
+    // #[pallet::genesis_config]
+    // pub struct GenesisConfig<T: Config> {
+    //     pub _ph_data: Option<PhantomData<T>>,
+    //     pub genesis_utxos: Vec<GenesisUtxoType>,
+    // }
+
+    /// TODO [6-genesis-builder]
+    // impl<T: Config> Default for GenesisConfig<T> {
+    //     fn default() -> Self {
+    //         Self {
+    //             _ph_data: Default::default(),
+    //             genesis_utxos: Vec::<GenesisUtxoType>::new(),
+    //         }
+    //     }
+    // }
+
+    /// TODO [6-genesis-builder]
+    // #[pallet::genesis_build]
+    // impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
+    //     fn build(&self) {
+    //         for utxo in self.genesis_utxos.iter() {
+    //             let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
+    //             let hash = BlakeTwo256::hash_of(&utxo);
+    //             Pallet::<T>::store_utxo(&utxo, hash);
+    //         }
+    //     }
+    // }
 
     /// [2-data-structure]
     /// Pallets use events to inform users when important changes are made.
@@ -250,7 +303,10 @@ pub mod pallet {
             // [3-spend-utxo]
             UtxoStore::<T>::insert(hash, utxo);
             
-            // // further update 😉
+            // TODO [6-genesis-builder]
+            // Convert H256 back to sr25519::Public
+            // let pubkey = Public::from_h256(utxo.pubkey);
+            // UtxoOf::<T>::insert(pubkey, hash);
         }
 
         /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs
index 90e5e84..71fc6c7 100644
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -2,7 +2,7 @@ use std::str::FromStr;
 
 use academy_pow_runtime::{
 	AccountId, SS58Prefix, Signature, TOKEN_DECIMALS, TOKEN_SYMBOL, WASM_BINARY,
-    // TODO [6-genesis-builder]
+    // [6-genesis-builder]
     utxo::{GenesisUtxoType, Value},
 };
 use multi_pow::{ForkHeights, ForkingConfig, MaxiPosition};
@@ -111,13 +111,13 @@ pub fn development_config() -> Result<ChainSpec, String> {
 		],
 		// Initial Difficulty
 		4_000_000,
-        // TODO [6-genesis-builder]
-        // vec![
-        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
-        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
-        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
-        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
-        // ],
+        // [6-genesis-builder]
+        vec![
+            get_account_id_from_seed::<sr25519::Public>("Alice"),
+            get_account_id_from_seed::<sr25519::Public>("Bob"),
+            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+        ],
 	))
 	.with_properties(system_properties())
 	.build())
@@ -145,13 +145,13 @@ pub fn testnet_config() -> Result<ChainSpec, String> {
 			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
 		],
 		4_000_000,
-        // TODO [6-genesis-builder]
-        // vec![
-        //     get_account_id_from_seed::<sr25519::Public>("Alice"),
-        //     get_account_id_from_seed::<sr25519::Public>("Bob"),
-        //     get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
-        //     get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
-        // ],
+        // [6-genesis-builder]
+        vec![
+            get_account_id_from_seed::<sr25519::Public>("Alice"),
+            get_account_id_from_seed::<sr25519::Public>("Bob"),
+            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+        ],
 	))
 	.with_properties(system_properties())
 	.build())
@@ -160,8 +160,8 @@ pub fn testnet_config() -> Result<ChainSpec, String> {
 fn genesis(
     endowed_accounts: Vec<AccountId>,
     initial_difficulty: u32,
-    // TODO [6-genesis-builder]
-    // utxo_genesis_accounts: Vec<AccountId>,
+    // [6-genesis-builder]
+    utxo_genesis_accounts: Vec<AccountId>,
 ) -> serde_json::Value {
 	serde_json::json!({
 		"balances": {
@@ -177,18 +177,18 @@ fn genesis(
 		"sha3DifficultyAdjustment": {
 			"initialDifficulty": u32_to_u8_32(initial_difficulty),
 		},
-        // TODO [6-genesis-builder]
-        // "utxo": {
-        //     "genesisUtxos": utxo_genesis_accounts
-        //         .iter().cloned()
-        //         .map(|k| {
-        //             let hash = H256::from_slice(&k.as_slice()); 
-        //             let value: Value = (1u64 << 50).into();
-        //             let genesis_utxo: GenesisUtxoType = (value, hash);
-
-        //             genesis_utxo
-        //         }).collect::<Vec<GenesisUtxoType>>(),
-        // },
+        // [6-genesis-builder]
+        "utxo": {
+            "genesisUtxos": utxo_genesis_accounts
+                .iter().cloned()
+                .map(|k| {
+                    let hash = H256::from_slice(&k.as_slice()); 
+                    let value: Value = (1u64 << 50).into();
+                    let genesis_utxo: GenesisUtxoType = (value, hash);
+
+                    genesis_utxo
+                }).collect::<Vec<GenesisUtxoType>>(),
+        },
 	})
 }
 
diff --git a/runtime/src/utxo.rs b/runtime/src/utxo.rs
index 0632046..5f0bda0 100644
--- a/runtime/src/utxo.rs
+++ b/runtime/src/utxo.rs
@@ -58,7 +58,7 @@ pub struct TransactionOutput {
 }
 
 
-/// TODO [6-genesis-builder]
+/// [6-genesis-builder]
 /// Because code is built on `no-std` feature.
 /// And we got error:
 /// ```
@@ -70,7 +70,7 @@ pub struct TransactionOutput {
 ///
 /// Hence, we need to simplify data type to make it work in both `std` and `no-std` feature.
 /// Genesis Utxo Type
-// pub type GenesisUtxoType = (Value, H256);
+pub type GenesisUtxoType = (Value, H256);
 
 #[frame_support::pallet(dev_mode)]
 pub mod pallet {
@@ -120,44 +120,44 @@ pub mod pallet {
         QueryKind = OptionQuery,
     >;
 
-    /// TODO [6-genesis-builder]
+    /// [6-genesis-builder]
     /// Keep track of latest UTXO hash of account
     /// Mapping from `sr25519::Pubkey` to `BlakeTwo256::hash_of(transaction, index)`
     /// Just for testing 🫤
     /// Because 1 account may have multiple UTXOs
-    // #[pallet::storage]
-    // #[pallet::getter(fn utxo_of)]
-    // pub type UtxoOf<T: Config> =
-    //     StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;
-
-    /// TODO [6-genesis-builder]
-    // #[pallet::genesis_config]
-    // pub struct GenesisConfig<T: Config> {
-    //     pub _ph_data: Option<PhantomData<T>>,
-    //     pub genesis_utxos: Vec<GenesisUtxoType>,
-    // }
-
-    /// TODO [6-genesis-builder]
-    // impl<T: Config> Default for GenesisConfig<T> {
-    //     fn default() -> Self {
-    //         Self {
-    //             _ph_data: Default::default(),
-    //             genesis_utxos: Vec::<GenesisUtxoType>::new(),
-    //         }
-    //     }
-    // }
-
-    /// TODO [6-genesis-builder]
-    // #[pallet::genesis_build]
-    // impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
-    //     fn build(&self) {
-    //         for utxo in self.genesis_utxos.iter() {
-    //             let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
-    //             let hash = BlakeTwo256::hash_of(&utxo);
-    //             Pallet::<T>::store_utxo(&utxo, hash);
-    //         }
-    //     }
-    // }
+    #[pallet::storage]
+    #[pallet::getter(fn utxo_of)]
+    pub type UtxoOf<T: Config> =
+        StorageMap<Hasher = Identity, Key = Public, Value = H256, QueryKind = OptionQuery>;
+
+    /// [6-genesis-builder]
+    #[pallet::genesis_config]
+    pub struct GenesisConfig<T: Config> {
+        pub _ph_data: Option<PhantomData<T>>,
+        pub genesis_utxos: Vec<GenesisUtxoType>,
+    }
+
+    /// [6-genesis-builder]
+    impl<T: Config> Default for GenesisConfig<T> {
+        fn default() -> Self {
+            Self {
+                _ph_data: Default::default(),
+                genesis_utxos: Vec::<GenesisUtxoType>::new(),
+            }
+        }
+    }
+
+    /// [6-genesis-builder]
+    #[pallet::genesis_build]
+    impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
+        fn build(&self) {
+            for utxo in self.genesis_utxos.iter() {
+                let utxo = TransactionOutput { value: utxo.0, pubkey: utxo.1 };
+                let hash = BlakeTwo256::hash_of(&utxo);
+                Pallet::<T>::store_utxo(&utxo, hash);
+            }
+        }
+    }
 
     /// [2-data-structure]
     /// Pallets use events to inform users when important changes are made.
@@ -303,10 +303,10 @@ pub mod pallet {
             // [3-spend-utxo]
             UtxoStore::<T>::insert(hash, utxo);
             
-            // TODO [6-genesis-builder]
+            // [6-genesis-builder]
             // Convert H256 back to sr25519::Public
-            // let pubkey = Public::from_h256(utxo.pubkey);
-            // UtxoOf::<T>::insert(pubkey, hash);
+            let pubkey = Public::from_h256(utxo.pubkey);
+            UtxoOf::<T>::insert(pubkey, hash);
         }
 
         /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.