Creating UTXO Pallet
[!Note] Resolve all "/// TODO" in
runtime/src/utxo.rs
to complete this step.
Reading Materials
I would recommend you to read these materials below first before looking at the code implmentation of the data structures. These materials below cover very well the concepts of FRAME storage in Substrate development.
- Substrate Tutorial - Use macros in a custom pallet
- OpenGuild Blog - Code breakdown pallet template (Vietnamese)
- Polkadot Blockchain Academy - FRAME Storage lecture
- Substrate Docs - Runtime storage structure
- Polkadot Blockchain Academy - Event and Error
- Polkadot Blockchain Academy - Pallet coupling
Data structures to work with Storage API
The FRAME Storage module simplifies access to these layered storage abstractions. You can use the FRAME storage data structures to read or write any value that can be encoded by the SCALE codec. The storage module provides the following types of storage structures:
StorageValue
: to store any single value, such as a u64.StorageMap
: to store a single key to value mapping, such as a specific account key to a specific balance value.StorageDoubleMap
: to store values in a storage map with two keys as an optimization to efficiently remove all entries that have a common first key.StorageNMap
: to store values in a map with any arbitrary number of keys.
Struct data for UTXO
Simple type for storing balance of UTXO
#![allow(unused)] fn main() { pub type Value = u128; }
Struct for representing a transaction in a UTXO-based model. The struct includes macros for serialization, deserialization, and various traits that enable efficient use in a blockchain context. Let’s break down the purpose of each macro:
#![allow(unused)] fn main() { #[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>, } #[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, } #[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, } }
-
cfg_attr(feature = "std", derive(Serialize, Deserialize))
: This macro conditionally derives theSerialize
andDeserialize
traits when thestd
feature is enabled. This feature is useful for converting theTransaction
struct to and from formats like JSON or other text-based formats. This functionality is often used in scenarios like data exchange between systems, debugging, or interacting with APIs or frontends. -
Encode
,Decode
: These macros from the parity-scale-codec crate allow the struct to be serialized to and deserialized from the SCALE binary format, ensuring efficient storage and transmission on the blockchain. Read more SCALE. -
TypeInfo
: Generates metadata for the struct, allowing its type information to be included in the blockchain's runtime metadata. This is valuable for interoperability with tools like Substrate frontends.
Configure your pallet's types, events and errors
#![allow(unused)] fn main() { #[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 /// Read more: `runtime/src/block_author.rs` /// Pallet loosely coupling /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets type BlockAuthor: BlockAuthor; /// A source to determine the issuance portion of the block reward /// Read more: `runtime/src/issuance.rs` type Issuance: Issuance<BlockNumberFor<Self>, Value>; } }
This storage item represents the total reward value to be redistributed among authorities during block finalization.
#![allow(unused)] fn main() { /// 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>; }
This storage item represents a mapping of UTXOs to their respective keys, allowing efficient lookup and management of UTXOs in a UTXO-based blockchain model.
#![allow(unused)] fn main() { /// 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, >; }
Events & Errors
Events and errors are used to notify about specific activity. Please use this for debugging purpose only. Events and Errors should not be used as a communication method between functionalities. In our codebase, we will declare these errors and events.
To declare error, simply use macro #[pallet::error]
#![allow(unused)] fn main() { /// 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, } }
To declare event, use #[pallet::event]
. Moreover with #[pallet::generate_deposit(pub(super) fn deposit_event)]
, it automatically generate a function deposit_event
for emitting events.
#![allow(unused)] fn main() { #[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, } }
Build the code
cargo build --release
Great job! 🎉 You're making fantastic progress. Let's keep the momentum going and dive into next step
#![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::*; /// TODO [2-data-structure] // pub type Value = u128; /// TODO [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>, // } /// TODO [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, // } /// TODO [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, // } #[frame_support::pallet(dev_mode)] pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use super::*; /// TODO [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 // /// Read more: `runtime/src/block_author.rs` // /// Pallet loosely coupling // /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets // 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>(_); /// TODO [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>; /// TODO [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 [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, // } /// TODO [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, // } /// TODO [2-data-structure] /// Define extrinsics / dispatchable function // #[pallet::call] // impl<T: Config> Pallet<T> { // pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult { // todo!(); // } // } /// TODO [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 { // todo!(); // } // /// Redistribute combined reward value to block Author // fn disperse_reward(author: &Public) { // todo!(); // } // /// Mutate storage, insert / update new UTXOs // fn store_utxo(utxo: &TransactionOutput, hash: H256) { // todo!(); // } // /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash. // fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> { // todo!(); // } // /// 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> { // todo!(); // } // } } }
#![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, } #[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 /// Read more: `runtime/src/block_author.rs` /// Pallet loosely coupling /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets 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, >; /// [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, } /// [2-data-structure] /// Define extrinsics / dispatchable function #[pallet::call] impl<T: Config> Pallet<T> { pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult { todo!(); } } /// [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 { todo!(); } /// Redistribute combined reward value to block Author fn disperse_reward(author: &Public) { todo!(); } /// Mutate storage, insert / update new UTXOs fn store_utxo(utxo: &TransactionOutput, hash: H256) { todo!(); } /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash. fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> { todo!(); } /// 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> { todo!(); } } } }
diff --git a/runtime/src/utxo.rs b/runtime/src/utxo.rs
index d387d16..47950e4 100644
--- a/runtime/src/utxo.rs
+++ b/runtime/src/utxo.rs
@@ -6,8 +6,8 @@ use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_core::{
- sr25519::{Public, Signature},
- ByteArray, H256, H512,
+ sr25519::{Public, Signature},
+ ByteArray, H256, H512,
};
use sp_runtime::traits::{BlakeTwo256, Hash, SaturatedConversion};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
@@ -16,16 +16,188 @@ use super::{block_author::BlockAuthor, issuance::Issuance};
pub use pallet::*;
+/// TODO [2-data-structure]
+// pub type Value = u128;
+
+/// TODO [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>,
+// }
+
+/// TODO [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,
+// }
+
+/// TODO [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,
+// }
+
#[frame_support::pallet(dev_mode)]
pub mod pallet {
- use frame_support::pallet_prelude::*;
- use frame_system::pallet_prelude::*;
+ use frame_support::pallet_prelude::*;
+ use frame_system::pallet_prelude::*;
+
+ use super::*;
+
+ /// TODO [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
+ // /// Read more: `runtime/src/block_author.rs`
+ // /// Pallet loosely coupling
+ // /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets
+ // 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>(_);
+
+
+ /// TODO [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>;
+
+ /// TODO [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 [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,
+ // }
+
+
+ /// TODO [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,
+ // }
+
+
+ /// TODO [2-data-structure]
+ /// Define extrinsics / dispatchable function
+ // #[pallet::call]
+ // impl<T: Config> Pallet<T> {
+ // pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult {
+ // todo!();
+ // }
+
+ // }
+
+ /// TODO [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 {
+ // todo!();
+ // }
+
+ // /// Redistribute combined reward value to block Author
+ // fn disperse_reward(author: &Public) {
+ // todo!();
+ // }
- use super::*;
+ // /// Mutate storage, insert / update new UTXOs
+ // fn store_utxo(utxo: &TransactionOutput, hash: H256) {
+ // todo!();
+ // }
- #[pallet::config]
- pub trait Config: frame_system::Config {}
+ // /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
+ // fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> {
+ // todo!();
+ // }
- #[pallet::pallet]
- pub struct Pallet<T>(_);
-}
+ // /// 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> {
+ // todo!();
+ // }
+ // }
+}
\ No newline at end of file
diff --git a/runtime/src/utxo.rs b/runtime/src/utxo.rs
index 47950e4..69a9535 100644
--- a/runtime/src/utxo.rs
+++ b/runtime/src/utxo.rs
@@ -16,46 +16,46 @@ use super::{block_author::BlockAuthor, issuance::Issuance};
pub use pallet::*;
-/// TODO [2-data-structure]
-// pub type Value = u128;
+/// [2-data-structure]
+pub type Value = u128;
-/// TODO [2-data-structure]
+/// [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>,
-// }
-
-/// TODO [2-data-structure]
+#[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,
-// }
-
-/// TODO [2-data-structure]
+#[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,
-// }
+#[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,
+}
#[frame_support::pallet(dev_mode)]
pub mod pallet {
@@ -64,140 +64,140 @@ pub mod pallet {
use super::*;
- /// TODO [2-data-structure]
+ /// [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
- // /// Read more: `runtime/src/block_author.rs`
- // /// Pallet loosely coupling
- // /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets
- // type BlockAuthor: BlockAuthor;
-
- // /// A source to determine the issuance portion of the block reward
- // type Issuance: Issuance<BlockNumberFor<Self>, Value>;
+ /// 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
+ /// Read more: `runtime/src/block_author.rs`
+ /// Pallet loosely coupling
+ /// https://polkadot-blockchain-academy.github.io/pba-book/frame/coupling/page.html#loosely-coupled-pallets
+ 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>(_);
- /// TODO [2-data-structure]
+ /// [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>;
+ #[pallet::storage]
+ #[pallet::getter(fn total_reward)]
+ pub type TotalReward<T: Config> = StorageValue<_, Value, ValueQuery>;
- /// TODO [2-data-structure]
+ /// [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,
- // >;
+ #[pallet::storage]
+ #[pallet::getter(fn utxo_store)]
+ pub type UtxoStore<T: Config> = StorageMap<
+ Hasher = Identity,
+ Key = H256,
+ Value = TransactionOutput,
+ QueryKind = OptionQuery,
+ >;
- /// TODO [2-data-structure]
+ /// [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,
- // }
-
-
- /// TODO [2-data-structure]
+ #[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,
- // }
-
-
- /// TODO [2-data-structure]
+ #[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,
+ }
+
+
+ /// [2-data-structure]
/// Define extrinsics / dispatchable function
- // #[pallet::call]
- // impl<T: Config> Pallet<T> {
- // pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult {
- // todo!();
- // }
+ #[pallet::call]
+ impl<T: Config> Pallet<T> {
+ pub fn spend(_origin: OriginFor<T>, transaction: Transaction) -> DispatchResult {
+ todo!();
+ }
- // }
+ }
- /// TODO [2-data-structure]
+ /// [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 {
- // todo!();
- // }
-
- // /// Redistribute combined reward value to block Author
- // fn disperse_reward(author: &Public) {
- // todo!();
- // }
-
- // /// Mutate storage, insert / update new UTXOs
- // fn store_utxo(utxo: &TransactionOutput, hash: H256) {
- // todo!();
- // }
-
- // /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
- // fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> {
- // todo!();
- // }
-
- // /// 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> {
- // todo!();
- // }
- // }
+ 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 {
+ todo!();
+ }
+
+ /// Redistribute combined reward value to block Author
+ fn disperse_reward(author: &Public) {
+ todo!();
+ }
+
+ /// Mutate storage, insert / update new UTXOs
+ fn store_utxo(utxo: &TransactionOutput, hash: H256) {
+ todo!();
+ }
+
+ /// Strips a transaction of its Signature fields by replacing value with ZERO-initialized fixed hash.
+ fn get_simple_transaction(transaction: &Transaction) -> Vec<u8> {
+ todo!();
+ }
+
+ /// 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> {
+ todo!();
+ }
+ }
}
\ No newline at end of file