Runtime

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

Reading Materials

Implement

From the first step of building environment, I've already import pallet into the runtime for ya

#![allow(unused)]
fn main() {
/// UTXOs serve as the digital equivalent of change you receive after making a cash purchase
pub mod utxo;
}

Now, you just have to add the pallet UTXO to the runtime

+ impl utxo::Config for Runtime {
+    type RuntimeEvent = RuntimeEvent;
+    type BlockAuthor = BlockAuthor;
+    type Issuance = issuance::BitcoinHalving;
+ }

... 

construct_runtime!(
    pub struct Runtime {
        System: frame_system,
        Timestamp: pallet_timestamp,
        Balances: pallet_balances,
        TransactionPayment: pallet_transaction_payment,
        Md5DifficultyAdjustment: difficulty::<Instance1>,
        Sha3DifficultyAdjustment: difficulty::<Instance2>,
        KeccakDifficultyAdjustment: difficulty::<Instance3>,
        BlockAuthor: block_author,
+        Utxo: utxo,
    }
);

...



impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
    fn validate_transaction(
        source: TransactionSource,
        tx: <Block as BlockT>::Extrinsic,
        block_hash: <Block as BlockT>::Hash,
    ) -> TransactionValidity {
+        // Extrinsics representing UTXO transaction need some special handling
+        if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
+        {
+            match Utxo::validate_transaction(&transaction) {
+                // Transaction verification failed
+                Err(e) => {
+                    sp_runtime::print(e);
+                    return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
+                }
+                // Race condition, or Transaction is good to go
+                Ok(tv) => { return Ok(tv); }
+            }
+        }

        // Fall back to default logic for non UTXO-spending extrinsics
        Executive::validate_transaction(source, tx, block_hash)
    }
}



Build the code

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

Direct to https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/explorer, and see block production. If you see after every a new block, there's also an event RewardDistributed, your work are perfect!

result


Well done on completing! 🎉 You're on fire! Now, let's tackle next step.

#![allow(unused)]
fn main() {
//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.

#![cfg_attr(not(feature = "std"), no_std)]
// The construct runtime macro does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]

// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

pub use frame_support::{
	construct_runtime, derive_impl, parameter_types,
	traits::{
		Currency, EstimateNextNewSession, Imbalance, IsSubType, KeyOwnerProofSystem,
		LockIdentifier, Nothing, OnUnbalanced, ValidatorSet, VariantCountOf,
	},
	weights::{
		constants::{
			BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND,
		},
		IdentityFee, Weight,
	},
	Callable, StorageValue,
};
use frame_support::{
	genesis_builder_helper::{build_state, get_preset},
	instances::{Instance1, Instance2, Instance3},
	sp_runtime::Perquintill,
	traits::{ConstU128, ConstU32, ConstU8},
};
use multi_pow::SupportedHashes;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
use parity_scale_codec::Decode;
use sp_api::impl_runtime_apis;
use sp_consensus_pow::POW_ENGINE_ID;
use sp_core::OpaqueMetadata;
// A few exports that help ease life for downstream crates.
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
use sp_runtime::{
	create_runtime_str, generic,
	traits::{
		AccountIdLookup, BlakeTwo256, Block as BlockT, Bounded, IdentifyAccount, One, Verify,
	},
	transaction_validity::{
		InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
	},
	ApplyExtrinsicResult, DigestItem, ExtrinsicInclusionMode, MultiSignature,
};
pub use sp_runtime::{FixedPointNumber, Perbill, Permill};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
/// An index to a block.
pub type BlockNumber = u32;

/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;

/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;

/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
/// never know...
pub type AccountIndex = u32;

/// Balance of an account.
pub type Balance = u128;

/// Index of a transaction in the chain.
pub type Nonce = u32;

/// Index of a transaction in the chain.
pub type Index = u32;

/// A hash of some data used by the chain.
pub type Hash = sp_core::H256;

/// Consensus digest containing block author and supported hash algorithm.
pub type PreDigest = (AccountId, SupportedHashes);

/// The BlockAuthor trait in `./block_author.rs`
pub mod block_author;

// /// The Difficulty Adjustment Algorithm in `./difficulty.rs`
pub mod difficulty;

/// The total issuance and halving time
pub mod issuance;

/// UTXOs serve as the digital equivalent of change you receive after making a cash purchase
pub mod utxo;

/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
/// to even the core data structures.
pub mod opaque {
	pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;

	use super::*;

	/// Opaque block header type.
	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
	/// Opaque block type.
	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
	/// Opaque block identifier type.
	pub type BlockId = generic::BlockId<Block>;
}

/// This runtime version.
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
	spec_name: create_runtime_str!("academy-pow"),
	impl_name: create_runtime_str!("academy-pow"),
	authoring_version: 1,
	spec_version: 1,
	impl_version: 1,
	apis: RUNTIME_API_VERSIONS,
	transaction_version: 1,
	state_version: 1,
};

/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
	NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}

const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
// native chain currency
pub const TOKEN_SYMBOL: &str = "Unit";
pub const TOKEN_DECIMALS: u32 = 12;
pub const TOKEN: u128 = 10u128.pow(TOKEN_DECIMALS);

parameter_types! {
	pub const BlockHashCount: BlockNumber = 2400;
	pub const Version: RuntimeVersion = VERSION;
	/// We allow for 2 seconds of compute with a 6 second average block time.
	pub BlockWeights: frame_system::limits::BlockWeights =
		frame_system::limits::BlockWeights::with_sensible_defaults(
			Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
			NORMAL_DISPATCH_RATIO,
		);
	pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
		::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
	pub const SS58Prefix: u8 = 42;
}

#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
impl frame_system::Config for Runtime {
	/// The basic call filter to use in dispatchable.
	type BaseCallFilter = frame_support::traits::Everything;
	/// Block & extrinsics weights: base values and limits.
	type BlockWeights = BlockWeights;
	/// The maximum length of a block (in bytes).
	type BlockLength = BlockLength;
	/// The identifier used to distinguish between accounts.
	type AccountId = AccountId;
	/// The aggregated dispatch type that is available for extrinsics.
	type RuntimeCall = RuntimeCall;
	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
	type Lookup = AccountIdLookup<AccountId, ()>;
	/// The type for hashing blocks and tries.
	type Hash = Hash;
	/// The hashing algorithm used.
	type Hashing = BlakeTwo256;
	/// The ubiquitous event type.
	type RuntimeEvent = RuntimeEvent;
	/// The ubiquitous origin type.
	type RuntimeOrigin = RuntimeOrigin;
	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
	type BlockHashCount = BlockHashCount;
	/// The weight of database operations that the runtime can invoke.
	type DbWeight = RocksDbWeight;
	/// Version of the runtime.
	type Version = Version;
	/// This type is being generated by the construct runtime macro.
	type PalletInfo = PalletInfo;
	/// What to do if a new account is created.
	type OnNewAccount = ();
	/// What to do if an account is fully reaped from the system.
	type OnKilledAccount = ();
	/// The data to be stored in an account.
	type AccountData = pallet_balances::AccountData<Balance>;
	/// Weight information for the extrinsics of this pallet.
	type SystemWeightInfo = ();
	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
	type SS58Prefix = SS58Prefix;
	/// The set code logic, just the default since we're not a parachain.
	type OnSetCode = ();
	type MaxConsumers = frame_support::traits::ConstU32<16>;
	type Nonce = Nonce;
	type Block = Block;
}

parameter_types! {
	pub const MinimumPeriod: u64 = 1000;
}

impl pallet_timestamp::Config for Runtime {
	/// A timestamp: milliseconds since the unix epoch.
	type Moment = u64;
	type OnTimestampSet = ();
	type MinimumPeriod = MinimumPeriod;
	type WeightInfo = ();
}

impl pallet_balances::Config for Runtime {
	type MaxLocks = ConstU32<50>;
	type MaxReserves = ();
	type ReserveIdentifier = [u8; 8];
	/// The type for recording an account's balance.
	type Balance = Balance;
	/// The ubiquitous event type.
	type RuntimeEvent = RuntimeEvent;
	type DustRemoval = ();
	type ExistentialDeposit = ConstU128<500>;
	type AccountStore = System;
	type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
	type FreezeIdentifier = RuntimeFreezeReason;
	type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
	type RuntimeHoldReason = RuntimeHoldReason;
	type RuntimeFreezeReason = RuntimeFreezeReason;
}

parameter_types! {
	pub const TargetBlockTime: u128 = 5_000;
	// Setting min difficulty to damp factor per recommendation
	pub const DampFactor: u128 = 3;
	pub const ClampFactor: u128 = 2;
	pub const MaxDifficulty: u128 = u128::max_value();
}

// Helper function to get the current blocks PoW algo from the predigest
fn current_blocks_mining_algo() -> SupportedHashes {
	System::digest()
		.logs
		.iter()
		.find_map(|digest_item| match digest_item {
			DigestItem::PreRuntime(POW_ENGINE_ID, pre_digest) =>
				PreDigest::decode(&mut &pre_digest[..]).map(|d| d.1).ok(),
			_ => None,
		})
		.expect("There should be exactly one pow pre-digest item")
}

impl difficulty::Config<Instance1> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Md5
	}
}

impl difficulty::Config<Instance2> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Sha3
	}
}

impl difficulty::Config<Instance3> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Keccak
	}
}

impl block_author::Config for Runtime {
	// Each block mined issues 50 new tokens to the miner
	fn on_author_set(author_account: Self::AccountId) {
		let issuance = 50 * TOKEN;
		let _ = Balances::deposit_creating(&author_account, issuance);
	}
}

parameter_types! {
	// This value increases the priority of `Operational` transactions by adding
	// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
	// follows polkadot : https://github.com/paritytech/polkadot/blob/9ce5f7ef5abb1a4291454e8c9911b304d80679f9/runtime/polkadot/src/lib.rs#L369
	pub const OperationalFeeMultiplier: u8 = 5;
	// We expect that on average 25% of the normal capacity will be occupied with normal txs.
	pub const TargetSaturationLevel: Perquintill = Perquintill::from_percent(25);
	// During 20 blocks the fee may not change more than by 100%. This, together with the
	// `TargetSaturationLevel` value, results in variability ~0.067. For the corresponding
	// formulas please refer to Substrate code at `frame/transaction-payment/src/lib.rs`.
	pub FeeVariability: Multiplier = Multiplier::saturating_from_rational(67, 1000);
	// Fee should never be lower than the computational cost.
	pub MinimumMultiplier: Multiplier = Multiplier::one();
	pub MaximumMultiplier: Multiplier = Bounded::max_value();
}

parameter_types! {
	pub FeeMultiplier: Multiplier = Multiplier::one();
}

impl pallet_transaction_payment::Config for Runtime {
	type RuntimeEvent = RuntimeEvent;
	type OnChargeTransaction = FungibleAdapter<Balances, ()>;
	type OperationalFeeMultiplier = ConstU8<5>;
	type WeightToFee = IdentityFee<Balance>;
	type LengthToFee = IdentityFee<Balance>;
	type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
}


// TODO [5-runtime]
// impl utxo::Config for Runtime {
//     type RuntimeEvent = RuntimeEvent;
//     type BlockAuthor = BlockAuthor;
//     type Issuance = issuance::BitcoinHalving;
// }


construct_runtime!(
	pub struct Runtime {
		System: frame_system,
		Timestamp: pallet_timestamp,
		Balances: pallet_balances,
		TransactionPayment: pallet_transaction_payment,
		Md5DifficultyAdjustment: difficulty::<Instance1>,
		Sha3DifficultyAdjustment: difficulty::<Instance2>,
		KeccakDifficultyAdjustment: difficulty::<Instance3>,
		BlockAuthor: block_author,
        // TODO [5-runtime]
        // Utxo: utxo,
	}
);

/// The address format for describing accounts.
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (
	frame_system::CheckNonZeroSender<Runtime>,
	frame_system::CheckSpecVersion<Runtime>,
	frame_system::CheckTxVersion<Runtime>,
	frame_system::CheckGenesis<Runtime>,
	frame_system::CheckEra<Runtime>,
	frame_system::CheckNonce<Runtime>,
	frame_system::CheckWeight<Runtime>,
	pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
	Runtime,
	Block,
	frame_system::ChainContext<Runtime>,
	Runtime,
	AllPalletsWithSystem,
>;

impl_runtime_apis! {
	impl sp_api::Core<Block> for Runtime {
		fn version() -> RuntimeVersion {
			VERSION
		}

		fn execute_block(block: Block) {
			Executive::execute_block(block)
		}

		fn initialize_block(header: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode {
			Executive::initialize_block(header)
		}
	}

	impl sp_api::Metadata<Block> for Runtime {
		fn metadata() -> OpaqueMetadata {
			OpaqueMetadata::new(Runtime::metadata().into())
		}

		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
			Runtime::metadata_at_version(version)
		}

		fn metadata_versions() -> sp_std::vec::Vec<u32> {
			Runtime::metadata_versions()
		}
	}

	impl sp_block_builder::BlockBuilder<Block> for Runtime {
		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
			Executive::apply_extrinsic(extrinsic)
		}

		fn finalize_block() -> <Block as BlockT>::Header {
			Executive::finalize_block()
		}

		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
			data.create_extrinsics()
		}

		fn check_inherents(
			block: Block,
			data: sp_inherents::InherentData,
		) -> sp_inherents::CheckInherentsResult {
			data.check_extrinsics(&block)
		}
	}

	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
		fn validate_transaction(
			source: TransactionSource,
			tx: <Block as BlockT>::Extrinsic,
			block_hash: <Block as BlockT>::Hash,
		) -> TransactionValidity {
            // TODO [5-runtime]

            // // Extrinsics representing UTXO transaction need some special handling
            // if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
            // {
            //     match Utxo::validate_transaction(&transaction) {
            //         // Transaction verification failed
            //         Err(e) => {
            //             sp_runtime::print(e);
            //             return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
            //         }
            //         // Race condition, or Transaction is good to go
            //         Ok(tv) => { return Ok(tv); }
            //     }
            // }

            // Fall back to default logic for non UTXO-spending extrinsics
			Executive::validate_transaction(source, tx, block_hash)
		}
	}

	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
		fn offchain_worker(header: &<Block as BlockT>::Header) {
			Executive::offchain_worker(header)
		}
	}

	impl sp_session::SessionKeys<Block> for Runtime {
		fn generate_session_keys(_seed: Option<Vec<u8>>) -> Vec<u8> {
			Vec::new()
		}

		fn decode_session_keys(
			_encoded: Vec<u8>,
		) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
			None
		}
	}

	impl sp_consensus_pow::DifficultyApi<Block, multi_pow::Threshold> for Runtime {
		fn difficulty() -> multi_pow::Threshold {
			multi_pow::Threshold {
				md5: Md5DifficultyAdjustment::difficulty(),
				sha3: Sha3DifficultyAdjustment::difficulty(),
				keccak: KeccakDifficultyAdjustment::difficulty(),
			}
		}
	}

	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
		fn account_nonce(account: AccountId) -> Index {
			System::account_nonce(account)
		}
	}

	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime
	{
		fn query_info(
			uxt: <Block as BlockT>::Extrinsic,
			len: u32,
		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
			TransactionPayment::query_info(uxt, len)
		}
		fn query_fee_details(
			uxt: <Block as BlockT>::Extrinsic,
			len: u32,
		) -> pallet_transaction_payment::FeeDetails<Balance> {
			TransactionPayment::query_fee_details(uxt, len)
		}
		fn query_weight_to_fee(weight: Weight) -> Balance {
			TransactionPayment::weight_to_fee(weight)
		}
		fn query_length_to_fee(length: u32) -> Balance {
			TransactionPayment::length_to_fee(length)
		}
	}

	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
		for Runtime
	{
		fn query_call_info(
			call: RuntimeCall,
			len: u32,
		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
			TransactionPayment::query_call_info(call, len)
		}
		fn query_call_fee_details(
			call: RuntimeCall,
			len: u32,
		) -> pallet_transaction_payment::FeeDetails<Balance> {
			TransactionPayment::query_call_fee_details(call, len)
		}
		fn query_weight_to_fee(weight: Weight) -> Balance {
			TransactionPayment::weight_to_fee(weight)
		}
		fn query_length_to_fee(length: u32) -> Balance {
			TransactionPayment::length_to_fee(length)
		}
	}

	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
		fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
			build_state::<RuntimeGenesisConfig>(config)
		}

		fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
			get_preset::<RuntimeGenesisConfig>(id, |_| None)
		}

		fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
			Default::default()
		}
	}
}
}
#![allow(unused)]
fn main() {
//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.

#![cfg_attr(not(feature = "std"), no_std)]
// The construct runtime macro does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]

// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

pub use frame_support::{
	construct_runtime, derive_impl, parameter_types,
	traits::{
		Currency, EstimateNextNewSession, Imbalance, IsSubType, KeyOwnerProofSystem,
		LockIdentifier, Nothing, OnUnbalanced, ValidatorSet, VariantCountOf,
	},
	weights::{
		constants::{
			BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND,
		},
		IdentityFee, Weight,
	},
	Callable, StorageValue,
};
use frame_support::{
	genesis_builder_helper::{build_state, get_preset},
	instances::{Instance1, Instance2, Instance3},
	sp_runtime::Perquintill,
	traits::{ConstU128, ConstU32, ConstU8},
};
use multi_pow::SupportedHashes;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
use parity_scale_codec::Decode;
use sp_api::impl_runtime_apis;
use sp_consensus_pow::POW_ENGINE_ID;
use sp_core::OpaqueMetadata;
// A few exports that help ease life for downstream crates.
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
use sp_runtime::{
	create_runtime_str, generic,
	traits::{
		AccountIdLookup, BlakeTwo256, Block as BlockT, Bounded, IdentifyAccount, One, Verify,
	},
	transaction_validity::{
		InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
	},
	ApplyExtrinsicResult, DigestItem, ExtrinsicInclusionMode, MultiSignature,
};
pub use sp_runtime::{FixedPointNumber, Perbill, Permill};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
/// An index to a block.
pub type BlockNumber = u32;

/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;

/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;

/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
/// never know...
pub type AccountIndex = u32;

/// Balance of an account.
pub type Balance = u128;

/// Index of a transaction in the chain.
pub type Nonce = u32;

/// Index of a transaction in the chain.
pub type Index = u32;

/// A hash of some data used by the chain.
pub type Hash = sp_core::H256;

/// Consensus digest containing block author and supported hash algorithm.
pub type PreDigest = (AccountId, SupportedHashes);

/// The BlockAuthor trait in `./block_author.rs`
pub mod block_author;

// /// The Difficulty Adjustment Algorithm in `./difficulty.rs`
pub mod difficulty;

/// The total issuance and halving time
pub mod issuance;

/// UTXOs serve as the digital equivalent of change you receive after making a cash purchase
pub mod utxo;

/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
/// to even the core data structures.
pub mod opaque {
	pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;

	use super::*;

	/// Opaque block header type.
	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
	/// Opaque block type.
	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
	/// Opaque block identifier type.
	pub type BlockId = generic::BlockId<Block>;
}

/// This runtime version.
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
	spec_name: create_runtime_str!("academy-pow"),
	impl_name: create_runtime_str!("academy-pow"),
	authoring_version: 1,
	spec_version: 1,
	impl_version: 1,
	apis: RUNTIME_API_VERSIONS,
	transaction_version: 1,
	state_version: 1,
};

/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
	NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}

const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
// native chain currency
pub const TOKEN_SYMBOL: &str = "Unit";
pub const TOKEN_DECIMALS: u32 = 12;
pub const TOKEN: u128 = 10u128.pow(TOKEN_DECIMALS);

parameter_types! {
	pub const BlockHashCount: BlockNumber = 2400;
	pub const Version: RuntimeVersion = VERSION;
	/// We allow for 2 seconds of compute with a 6 second average block time.
	pub BlockWeights: frame_system::limits::BlockWeights =
		frame_system::limits::BlockWeights::with_sensible_defaults(
			Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
			NORMAL_DISPATCH_RATIO,
		);
	pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
		::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
	pub const SS58Prefix: u8 = 42;
}

#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
impl frame_system::Config for Runtime {
	/// The basic call filter to use in dispatchable.
	type BaseCallFilter = frame_support::traits::Everything;
	/// Block & extrinsics weights: base values and limits.
	type BlockWeights = BlockWeights;
	/// The maximum length of a block (in bytes).
	type BlockLength = BlockLength;
	/// The identifier used to distinguish between accounts.
	type AccountId = AccountId;
	/// The aggregated dispatch type that is available for extrinsics.
	type RuntimeCall = RuntimeCall;
	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
	type Lookup = AccountIdLookup<AccountId, ()>;
	/// The type for hashing blocks and tries.
	type Hash = Hash;
	/// The hashing algorithm used.
	type Hashing = BlakeTwo256;
	/// The ubiquitous event type.
	type RuntimeEvent = RuntimeEvent;
	/// The ubiquitous origin type.
	type RuntimeOrigin = RuntimeOrigin;
	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
	type BlockHashCount = BlockHashCount;
	/// The weight of database operations that the runtime can invoke.
	type DbWeight = RocksDbWeight;
	/// Version of the runtime.
	type Version = Version;
	/// This type is being generated by the construct runtime macro.
	type PalletInfo = PalletInfo;
	/// What to do if a new account is created.
	type OnNewAccount = ();
	/// What to do if an account is fully reaped from the system.
	type OnKilledAccount = ();
	/// The data to be stored in an account.
	type AccountData = pallet_balances::AccountData<Balance>;
	/// Weight information for the extrinsics of this pallet.
	type SystemWeightInfo = ();
	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
	type SS58Prefix = SS58Prefix;
	/// The set code logic, just the default since we're not a parachain.
	type OnSetCode = ();
	type MaxConsumers = frame_support::traits::ConstU32<16>;
	type Nonce = Nonce;
	type Block = Block;
}

parameter_types! {
	pub const MinimumPeriod: u64 = 1000;
}

impl pallet_timestamp::Config for Runtime {
	/// A timestamp: milliseconds since the unix epoch.
	type Moment = u64;
	type OnTimestampSet = ();
	type MinimumPeriod = MinimumPeriod;
	type WeightInfo = ();
}

impl pallet_balances::Config for Runtime {
	type MaxLocks = ConstU32<50>;
	type MaxReserves = ();
	type ReserveIdentifier = [u8; 8];
	/// The type for recording an account's balance.
	type Balance = Balance;
	/// The ubiquitous event type.
	type RuntimeEvent = RuntimeEvent;
	type DustRemoval = ();
	type ExistentialDeposit = ConstU128<500>;
	type AccountStore = System;
	type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
	type FreezeIdentifier = RuntimeFreezeReason;
	type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
	type RuntimeHoldReason = RuntimeHoldReason;
	type RuntimeFreezeReason = RuntimeFreezeReason;
}

parameter_types! {
	pub const TargetBlockTime: u128 = 5_000;
	// Setting min difficulty to damp factor per recommendation
	pub const DampFactor: u128 = 3;
	pub const ClampFactor: u128 = 2;
	pub const MaxDifficulty: u128 = u128::max_value();
}

// Helper function to get the current blocks PoW algo from the predigest
fn current_blocks_mining_algo() -> SupportedHashes {
	System::digest()
		.logs
		.iter()
		.find_map(|digest_item| match digest_item {
			DigestItem::PreRuntime(POW_ENGINE_ID, pre_digest) =>
				PreDigest::decode(&mut &pre_digest[..]).map(|d| d.1).ok(),
			_ => None,
		})
		.expect("There should be exactly one pow pre-digest item")
}

impl difficulty::Config<Instance1> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Md5
	}
}

impl difficulty::Config<Instance2> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Sha3
	}
}

impl difficulty::Config<Instance3> for Runtime {
	type TimeProvider = Timestamp;
	type TargetBlockTime = TargetBlockTime;
	type DampFactor = DampFactor;
	type ClampFactor = ClampFactor;
	type MaxDifficulty = MaxDifficulty;
	type MinDifficulty = DampFactor;

	fn relevant_to_this_instance() -> bool {
		current_blocks_mining_algo() == SupportedHashes::Keccak
	}
}

impl block_author::Config for Runtime {
	// Each block mined issues 50 new tokens to the miner
	fn on_author_set(author_account: Self::AccountId) {
		let issuance = 50 * TOKEN;
		let _ = Balances::deposit_creating(&author_account, issuance);
	}
}

parameter_types! {
	// This value increases the priority of `Operational` transactions by adding
	// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
	// follows polkadot : https://github.com/paritytech/polkadot/blob/9ce5f7ef5abb1a4291454e8c9911b304d80679f9/runtime/polkadot/src/lib.rs#L369
	pub const OperationalFeeMultiplier: u8 = 5;
	// We expect that on average 25% of the normal capacity will be occupied with normal txs.
	pub const TargetSaturationLevel: Perquintill = Perquintill::from_percent(25);
	// During 20 blocks the fee may not change more than by 100%. This, together with the
	// `TargetSaturationLevel` value, results in variability ~0.067. For the corresponding
	// formulas please refer to Substrate code at `frame/transaction-payment/src/lib.rs`.
	pub FeeVariability: Multiplier = Multiplier::saturating_from_rational(67, 1000);
	// Fee should never be lower than the computational cost.
	pub MinimumMultiplier: Multiplier = Multiplier::one();
	pub MaximumMultiplier: Multiplier = Bounded::max_value();
}

parameter_types! {
	pub FeeMultiplier: Multiplier = Multiplier::one();
}

impl pallet_transaction_payment::Config for Runtime {
	type RuntimeEvent = RuntimeEvent;
	type OnChargeTransaction = FungibleAdapter<Balances, ()>;
	type OperationalFeeMultiplier = ConstU8<5>;
	type WeightToFee = IdentityFee<Balance>;
	type LengthToFee = IdentityFee<Balance>;
	type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
}


// [5-runtime]
impl utxo::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type BlockAuthor = BlockAuthor;
    type Issuance = issuance::BitcoinHalving;
}


construct_runtime!(
	pub struct Runtime {
		System: frame_system,
		Timestamp: pallet_timestamp,
		Balances: pallet_balances,
		TransactionPayment: pallet_transaction_payment,
		Md5DifficultyAdjustment: difficulty::<Instance1>,
		Sha3DifficultyAdjustment: difficulty::<Instance2>,
		KeccakDifficultyAdjustment: difficulty::<Instance3>,
		BlockAuthor: block_author,
        // [5-runtime]
        Utxo: utxo,
	}
);

/// The address format for describing accounts.
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (
	frame_system::CheckNonZeroSender<Runtime>,
	frame_system::CheckSpecVersion<Runtime>,
	frame_system::CheckTxVersion<Runtime>,
	frame_system::CheckGenesis<Runtime>,
	frame_system::CheckEra<Runtime>,
	frame_system::CheckNonce<Runtime>,
	frame_system::CheckWeight<Runtime>,
	pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
	Runtime,
	Block,
	frame_system::ChainContext<Runtime>,
	Runtime,
	AllPalletsWithSystem,
>;

impl_runtime_apis! {
	impl sp_api::Core<Block> for Runtime {
		fn version() -> RuntimeVersion {
			VERSION
		}

		fn execute_block(block: Block) {
			Executive::execute_block(block)
		}

		fn initialize_block(header: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode {
			Executive::initialize_block(header)
		}
	}

	impl sp_api::Metadata<Block> for Runtime {
		fn metadata() -> OpaqueMetadata {
			OpaqueMetadata::new(Runtime::metadata().into())
		}

		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
			Runtime::metadata_at_version(version)
		}

		fn metadata_versions() -> sp_std::vec::Vec<u32> {
			Runtime::metadata_versions()
		}
	}

	impl sp_block_builder::BlockBuilder<Block> for Runtime {
		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
			Executive::apply_extrinsic(extrinsic)
		}

		fn finalize_block() -> <Block as BlockT>::Header {
			Executive::finalize_block()
		}

		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
			data.create_extrinsics()
		}

		fn check_inherents(
			block: Block,
			data: sp_inherents::InherentData,
		) -> sp_inherents::CheckInherentsResult {
			data.check_extrinsics(&block)
		}
	}

	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
		fn validate_transaction(
			source: TransactionSource,
			tx: <Block as BlockT>::Extrinsic,
			block_hash: <Block as BlockT>::Hash,
		) -> TransactionValidity {
            // [5-runtime]

            // Extrinsics representing UTXO transaction need some special handling
            if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
            {
                match Utxo::validate_transaction(&transaction) {
                    // Transaction verification failed
                    Err(e) => {
                        sp_runtime::print(e);
                        return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
                    }
                    // Race condition, or Transaction is good to go
                    Ok(tv) => { return Ok(tv); }
                }
            }

            // Fall back to default logic for non UTXO-spending extrinsics
			Executive::validate_transaction(source, tx, block_hash)
		}
	}

	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
		fn offchain_worker(header: &<Block as BlockT>::Header) {
			Executive::offchain_worker(header)
		}
	}

	impl sp_session::SessionKeys<Block> for Runtime {
		fn generate_session_keys(_seed: Option<Vec<u8>>) -> Vec<u8> {
			Vec::new()
		}

		fn decode_session_keys(
			_encoded: Vec<u8>,
		) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
			None
		}
	}

	impl sp_consensus_pow::DifficultyApi<Block, multi_pow::Threshold> for Runtime {
		fn difficulty() -> multi_pow::Threshold {
			multi_pow::Threshold {
				md5: Md5DifficultyAdjustment::difficulty(),
				sha3: Sha3DifficultyAdjustment::difficulty(),
				keccak: KeccakDifficultyAdjustment::difficulty(),
			}
		}
	}

	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
		fn account_nonce(account: AccountId) -> Index {
			System::account_nonce(account)
		}
	}

	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime
	{
		fn query_info(
			uxt: <Block as BlockT>::Extrinsic,
			len: u32,
		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
			TransactionPayment::query_info(uxt, len)
		}
		fn query_fee_details(
			uxt: <Block as BlockT>::Extrinsic,
			len: u32,
		) -> pallet_transaction_payment::FeeDetails<Balance> {
			TransactionPayment::query_fee_details(uxt, len)
		}
		fn query_weight_to_fee(weight: Weight) -> Balance {
			TransactionPayment::weight_to_fee(weight)
		}
		fn query_length_to_fee(length: u32) -> Balance {
			TransactionPayment::length_to_fee(length)
		}
	}

	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
		for Runtime
	{
		fn query_call_info(
			call: RuntimeCall,
			len: u32,
		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
			TransactionPayment::query_call_info(call, len)
		}
		fn query_call_fee_details(
			call: RuntimeCall,
			len: u32,
		) -> pallet_transaction_payment::FeeDetails<Balance> {
			TransactionPayment::query_call_fee_details(call, len)
		}
		fn query_weight_to_fee(weight: Weight) -> Balance {
			TransactionPayment::weight_to_fee(weight)
		}
		fn query_length_to_fee(length: u32) -> Balance {
			TransactionPayment::length_to_fee(length)
		}
	}

	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
		fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
			build_state::<RuntimeGenesisConfig>(config)
		}

		fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
			get_preset::<RuntimeGenesisConfig>(id, |_| None)
		}

		fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
			Default::default()
		}
	}
}
}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index b724b7e..258420d 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -325,6 +325,15 @@ impl pallet_transaction_payment::Config for Runtime {
 	type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
 }
 
+
+// TODO [5-runtime]
+// impl utxo::Config for Runtime {
+//     type RuntimeEvent = RuntimeEvent;
+//     type BlockAuthor = BlockAuthor;
+//     type Issuance = issuance::BitcoinHalving;
+// }
+
+
 construct_runtime!(
 	pub struct Runtime {
 		System: frame_system,
@@ -335,6 +344,8 @@ construct_runtime!(
 		Sha3DifficultyAdjustment: difficulty::<Instance2>,
 		KeccakDifficultyAdjustment: difficulty::<Instance3>,
 		BlockAuthor: block_author,
+        // TODO [5-runtime]
+        // Utxo: utxo,
 	}
 );
 
@@ -425,6 +436,23 @@ impl_runtime_apis! {
 			tx: <Block as BlockT>::Extrinsic,
 			block_hash: <Block as BlockT>::Hash,
 		) -> TransactionValidity {
+            // TODO [5-runtime]
+
+            // // Extrinsics representing UTXO transaction need some special handling
+            // if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
+            // {
+            //     match Utxo::validate_transaction(&transaction) {
+            //         // Transaction verification failed
+            //         Err(e) => {
+            //             sp_runtime::print(e);
+            //             return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
+            //         }
+            //         // Race condition, or Transaction is good to go
+            //         Ok(tv) => { return Ok(tv); }
+            //     }
+            // }
+
+            // Fall back to default logic for non UTXO-spending extrinsics
 			Executive::validate_transaction(source, tx, block_hash)
 		}
 	}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 258420d..75498bf 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -326,12 +326,12 @@ impl pallet_transaction_payment::Config for Runtime {
 }
 
 
-// TODO [5-runtime]
-// impl utxo::Config for Runtime {
-//     type RuntimeEvent = RuntimeEvent;
-//     type BlockAuthor = BlockAuthor;
-//     type Issuance = issuance::BitcoinHalving;
-// }
+// [5-runtime]
+impl utxo::Config for Runtime {
+    type RuntimeEvent = RuntimeEvent;
+    type BlockAuthor = BlockAuthor;
+    type Issuance = issuance::BitcoinHalving;
+}
 
 
 construct_runtime!(
@@ -344,8 +344,8 @@ construct_runtime!(
 		Sha3DifficultyAdjustment: difficulty::<Instance2>,
 		KeccakDifficultyAdjustment: difficulty::<Instance3>,
 		BlockAuthor: block_author,
-        // TODO [5-runtime]
-        // Utxo: utxo,
+        // [5-runtime]
+        Utxo: utxo,
 	}
 );
 
@@ -436,21 +436,21 @@ impl_runtime_apis! {
 			tx: <Block as BlockT>::Extrinsic,
 			block_hash: <Block as BlockT>::Hash,
 		) -> TransactionValidity {
-            // TODO [5-runtime]
-
-            // // Extrinsics representing UTXO transaction need some special handling
-            // if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
-            // {
-            //     match Utxo::validate_transaction(&transaction) {
-            //         // Transaction verification failed
-            //         Err(e) => {
-            //             sp_runtime::print(e);
-            //             return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
-            //         }
-            //         // Race condition, or Transaction is good to go
-            //         Ok(tv) => { return Ok(tv); }
-            //     }
-            // }
+            // [5-runtime]
+
+            // Extrinsics representing UTXO transaction need some special handling
+            if let Some(&utxo::Call::spend{ ref transaction }) = IsSubType::<<Utxo as Callable<Runtime>>::RuntimeCall>::is_sub_type(&tx.function)
+            {
+                match Utxo::validate_transaction(&transaction) {
+                    // Transaction verification failed
+                    Err(e) => {
+                        sp_runtime::print(e);
+                        return Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)));
+                    }
+                    // Race condition, or Transaction is good to go
+                    Ok(tv) => { return Ok(tv); }
+                }
+            }
 
             // Fall back to default logic for non UTXO-spending extrinsics
 			Executive::validate_transaction(source, tx, block_hash)