Create Your Block Type
The support module provided for us a bunch of generic types which can be customized for our simple state machine. To actually start using them, we need to define concrete versions of these types using our other concrete types.
Runtime Call
You will see the template provides an empty enum RuntimeCall
which we will expand later. This is an object which is supposed to represent all the various calls exposed by your blockchain to users and the outside world. We need to mock this enum at this step so that it can be used to build a concrete Extrinsic
type.
For now, there is just the transfer
function exposed by the Balances Pallet, but we will add more before this tutorial is complete, and figure out ways to automate the creation of our RuntimeCall
.
You can access this type within mod types
with crate::RuntimeCall
.
Building the Block Type
It's time to define the concrete Block
type that we will use to enhance our simple state machine.
- Using the
RuntimeCall
enum and theAccountId
type, you can define a concreteExtrinsic
type. - Using the
BlockNumber
type, you can define a concreteHeader
type. - Using the concrete
Header
andExtrinsic
types, you can define a concreteBlock
type.
As you can see, the Block
is composed of layers of generic types, allowing the whole structure to be flexible and customizable to our needs.
Pay attention to the generic type definitions to ensure that you use all the correct generic parameters in all the right places.
Your code should still compile with some "never constructed/used" warnings.
mod balances; mod support; mod system; // These are the concrete types we will use in our simple state machine. // Modules are configured for these types directly, and they satisfy all of our // trait requirements. mod types { pub type AccountId = String; pub type Balance = u128; pub type BlockNumber = u32; pub type Nonce = u32; /* TODO: Define a concrete `Extrinsic` type using `AccountId` and `RuntimeCall`. */ /* TODO: Define a concrete `Header` type using `BlockNumber`. */ /* TODO: Define a concrete `Block` type using `Header` and `Extrinsic`. */ } // These are all the calls which are exposed to the world. // Note that it is just an accumulation of the calls exposed by each module. pub enum RuntimeCall { // TODO: Not implemented yet. } // This is our main Runtime. // It accumulates all of the different pallets we want to use. #[derive(Debug)] pub struct Runtime { system: system::Pallet<Self>, balances: balances::Pallet<Self>, } impl system::Config for Runtime { type AccountId = types::AccountId; type BlockNumber = types::BlockNumber; type Nonce = types::Nonce; } impl balances::Config for Runtime { type Balance = types::Balance; } impl Runtime { // Create a new instance of the main Runtime, by creating a new instance of each pallet. fn new() -> Self { Self { system: system::Pallet::new(), balances: balances::Pallet::new() } } } fn main() { let mut runtime = Runtime::new(); let alice = "alice".to_string(); let bob = "bob".to_string(); let charlie = "charlie".to_string(); runtime.balances.set_balance(&alice, 100); // start emulating a block runtime.system.inc_block_number(); assert_eq!(runtime.system.block_number(), 1); // first transaction runtime.system.inc_nonce(&alice); let _res = runtime .balances .transfer(alice.clone(), bob, 30) .map_err(|e| eprintln!("{}", e)); // second transaction runtime.system.inc_nonce(&alice); let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e)); println!("{:#?}", runtime); }
mod balances; mod support; mod system; // These are the concrete types we will use in our simple state machine. // Modules are configured for these types directly, and they satisfy all of our // trait requirements. mod types { pub type AccountId = String; pub type Balance = u128; pub type BlockNumber = u32; pub type Nonce = u32; pub type Extrinsic = crate::support::Extrinsic<AccountId, crate::RuntimeCall>; pub type Header = crate::support::Header<BlockNumber>; pub type Block = crate::support::Block<Header, Extrinsic>; } // These are all the calls which are exposed to the world. // Note that it is just an accumulation of the calls exposed by each module. pub enum RuntimeCall { // TODO: Not implemented yet. } // This is our main Runtime. // It accumulates all of the different pallets we want to use. #[derive(Debug)] pub struct Runtime { system: system::Pallet<Self>, balances: balances::Pallet<Self>, } impl system::Config for Runtime { type AccountId = types::AccountId; type BlockNumber = types::BlockNumber; type Nonce = types::Nonce; } impl balances::Config for Runtime { type Balance = types::Balance; } impl Runtime { // Create a new instance of the main Runtime, by creating a new instance of each pallet. fn new() -> Self { Self { system: system::Pallet::new(), balances: balances::Pallet::new() } } } fn main() { let mut runtime = Runtime::new(); let alice = "alice".to_string(); let bob = "bob".to_string(); let charlie = "charlie".to_string(); runtime.balances.set_balance(&alice, 100); // start emulating a block runtime.system.inc_block_number(); assert_eq!(runtime.system.block_number(), 1); // first transaction runtime.system.inc_nonce(&alice); let _res = runtime .balances .transfer(alice.clone(), bob, 30) .map_err(|e| eprintln!("{}", e)); // second transaction runtime.system.inc_nonce(&alice); let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e)); println!("{:#?}", runtime); }
diff --git a/src/main.rs b/src/main.rs
index 597aca68..691aaccc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,6 +10,15 @@ mod types {
pub type Balance = u128;
pub type BlockNumber = u32;
pub type Nonce = u32;
+ /* TODO: Define a concrete `Extrinsic` type using `AccountId` and `RuntimeCall`. */
+ /* TODO: Define a concrete `Header` type using `BlockNumber`. */
+ /* TODO: Define a concrete `Block` type using `Header` and `Extrinsic`. */
+}
+
+// These are all the calls which are exposed to the world.
+// Note that it is just an accumulation of the calls exposed by each module.
+pub enum RuntimeCall {
+ // TODO: Not implemented yet.
}
// This is our main Runtime.
diff --git a/src/main.rs b/src/main.rs
index 691aaccc..5b6e139c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,9 +10,9 @@ mod types {
pub type Balance = u128;
pub type BlockNumber = u32;
pub type Nonce = u32;
- /* TODO: Define a concrete `Extrinsic` type using `AccountId` and `RuntimeCall`. */
- /* TODO: Define a concrete `Header` type using `BlockNumber`. */
- /* TODO: Define a concrete `Block` type using `Header` and `Extrinsic`. */
+ pub type Extrinsic = crate::support::Extrinsic<AccountId, crate::RuntimeCall>;
+ pub type Header = crate::support::Header<BlockNumber>;
+ pub type Block = crate::support::Block<Header, Extrinsic>;
}
// These are all the calls which are exposed to the world.