Introduction to the Rust State Machine

Welcome to the Rust State Machine tutorial.

This is a guided tutorial intended to teach readers the basics of Rust, Blockchain, and eventually the inner workings of the Polkadot SDK.

It has been my experience that the hardest part of building your first blockchain using the Polkadot SDK is navigating the advance Rust features used by Substrate, and understanding the underlying magic behind various macros which generate code for you.

This tutorial tries to directly address this by having you build a completely vanilla Rust project which does all the same tricks as the Polkadot SDK, so you know first hand what is going on behind the scenes.

This tutorial does not assume the reader has much previous knowledge about Rust, Blockchain, or the Polkadot SDK, however, this tutorial does not replace a basic introduction of any of those topics.

It is strongly recommended that before you begin this tutorial, that you at least have read the first 11 chapters of the Rust Book.

You need not be an expert in all that you read, but it will help to have exposure to all the various topics like: ownership, basic data types, structures, enums, crates, error handling, traits, generic types, and tests.

The tutorial is broken into sections which cover specific learning goals for the reader, and can act as good pause points if you need them.

All of the content of this tutorial is open source, free to access, and can be found here.

If you have suggestions which can improve the tutorial, comments, issues and pull requests are welcome.

Without further ado, enjoy and I hope you learn a ton!

Initialize your Rust Project

In this step, we will initialize a basic rust project, where we can start building our simple Rust state machine.

cargo init

  1. Create a directory where you want your project to live, and navigate to that folder. We will be using a folder named rust-state-machine.

    mkdir rust-state-machine
    cd rust-state-machine
    
  2. In that folder, initialize your rust project using cargo init:

    cargo init
    

    This will scaffold a basic Rust executable which we can use to start building.

  3. You can verify that your new project is working as expected by running:

    cargo run
    

    You should see "Hello, World!" appear at the end of the compilation:

    ➜  rust-state-machine git:(master) ✗ cargo run
    Compiling rust-state-machine v0.1.0 (/Users/shawntabrizi/Documents/GitHub/rust-state-machine)
    	Finished dev [unoptimized + debuginfo] target(s) in 2.19s
    	Running `target/debug/rust-state-machine`
    Hello, world!
    

If we look at what has been generated, in that folder, you will see the following:

  • src/main.rs - This is the entry point to your program. We will be building everything for this project in the src folder.
  • Cargo.toml - This is a configuration file for your Rust project. Quite similar to a package.json that you would see in a Node.JS project. We will modify this in the future when we import crates to use in our project, but We can leave this alone for now.
  • Cargo.lock - This is an autogenerated lock file based on your cargo.toml and the compilation. This usually defines the very specific versions of each crate being imported, and should not be manually edited.
  • target/* - You might also see a target folder if you did cargo run. This is a folder where all the build artifacts are placed during compilation. We do not commit this folder into our git history.

All of this should be pretty familiar to you if you have already had some minimal experience with Rust. If any of this is new, I would suggest you first walk through the Rust Book and Rust by Example, as this is already an indication that this guide might not be targeted at your level of knowledge.

[package]
name = "rust-state-machine"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
fn main() {
    println!("Hello, world!");
}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..400485bd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+**/target/
+.DS_Store
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 00000000..75fe297f
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "rust-state-machine"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..c7fe36cd
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "rust-state-machine"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 00000000..e7a11a96
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}

Rust Tooling

In this step, we will initialize a basic rust project, where we can start building our simple Rust state machine.

rustfmt

To keep your code clean and easy to read, we use a tool called rustfmt. To access all the latest features of rustfmt we specifically use the nightly toolchain.

To install rustfmt for nightly:

rustup component add rustfmt --toolchain nightly

To configure the behavior of rustfmt, we will create a rustfmt.toml file:

  1. Create a new file in your project's root directory called rustfmt.toml.

    touch rustfmt.toml
    
  2. Use the provided rustfmt.toml file to configure your formatting preferences.

  3. Run the code formatter using the following command:

    cargo +nightly fmt
    

You shouldn't see any changes this time around, but as you write more code, you will be able to see cargo +nightly fmt make everything look pretty, consistent, and easy to read.

We recommend you run cargo +nightly fmt after every step!

Rust Analyzer

Another popular tool in the Rust community is Rust Analyzer.

It provides many features like code completion and goto definition for code editors like VS Code.

However, to provide the full functionality that it does, Rust Analyzer needs to compile your code. For a small project like this one, this is not a problem, however working with a large project like Substrate / Polkadot-SDK, it is.

It is my personal recommendation that Rust Analyzer is not needed in this workshop, and generally you should not use it for Substrate development. However, this section might be updated in the future to include special configurations of Rust Analyzer which will work well with Polkadot SDK in the future.

However, if you would like to use it anyway, now is the right time to set it up.

# Basic
edition = "2021"
hard_tabs = true
max_width = 100
use_small_heuristics = "Max"
# Imports
imports_granularity = "Crate"
reorder_imports = true
# Consistency
newline_style = "Unix"
# Misc
chain_width = 80
spaces_around_ranges = false
binop_separator = "Back"
reorder_impl_items = false
match_arm_leading_pipes = "Preserve"
match_arm_blocks = false
match_block_trailing_comma = true
trailing_comma = "Vertical"
trailing_semicolon = false
use_field_init_shorthand = true
# Format comments
comment_width = 100
wrap_comments = true
fn main() {
	println!("Hello, world!");
}
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 00000000..c3421539
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,24 @@
+# Basic
+edition = "2021"
+hard_tabs = true
+max_width = 100
+use_small_heuristics = "Max"
+# Imports
+imports_granularity = "Crate"
+reorder_imports = true
+# Consistency
+newline_style = "Unix"
+# Misc
+chain_width = 80
+spaces_around_ranges = false
+binop_separator = "Back"
+reorder_impl_items = false
+match_arm_leading_pipes = "Preserve"
+match_arm_blocks = false
+match_block_trailing_comma = true
+trailing_comma = "Vertical"
+trailing_semicolon = false
+use_field_init_shorthand = true
+# Format comments
+comment_width = 100
+wrap_comments = true
diff --git a/src/main.rs b/src/main.rs
index e7a11a96..a30eb952 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,3 @@
 fn main() {
-    println!("Hello, world!");
+	println!("Hello, world!");
 }

The Balances Pallet

In this section, we will build the very first logic for our state machine: a Balances Pallet.

This Pallet will manage the balances of users and allow them to transfer tokens to one another.

Along the way, you will learn about safe math, options, error handling, and more.

By the end of this section, you will have designed the logic of a simple cryptocurrency.

Creating a Balances Pallet

As mentioned earlier, at the heart of a blockchain is a state machine.

We can create a very naive state machine using simple Rust abstractions, and through this help learn about Rust in the context of blockchains.

We want keep our code organized, so we will not really start building in the main.rs file, but actually in separate Rust modules. We can think of the main.rs file as glue which brings everything together, and we will see that over the course of this workshop.

"Pallet" is a term specific to the Polkadot SDK, which refers to Rust modules which contain logic specific for your blockchain runtime. We are going to start using this term here because what we build here will closely mirror what you will see with the Polkadot SDK.

Balances

Pretty much every blockchain has logic handles the balances of users on that blockchain.

This Pallet will tell you: how much balance each user has, provide functions which allow users to transfer those balances, and even some low level functions to allow your blockchain system to manipulate those balances if needed. Think for example if you want to mint new tokens which don't already exist.

This is a great starting point, and the very first Pallet we will build.

Creating a Struct

  1. Create a new file in your src folder named balances.rs

    touch src/balances.rs
    
  2. In this file, create a struct, which will act as the state and entry point for this module:

    #![allow(unused)]
    fn main() {
    pub struct Pallet {}
    }
  3. Now go back to src/main.rs, and import this new module, which will include all the logic inside of it:

    #![allow(unused)]
    fn main() {
    mod balances;
    }
  4. If we run your program now, you will see it still compiles and runs, but might show you some warnings like:

    warning: struct `Pallet` is never constructed
    --> src/balances.rs:1:12
    |
    1 | pub struct Pallet {    }
    |              ^^^^^^
    |
    = note: `#[warn(dead_code)]` on by default
    
    warning: `pr` (bin "pr") generated 1 warning
    

    That's fine! We haven't started using our Pallet yet, but you can see that the Rust compiler is detecting our new code, and bringing that logic into our main program. This is the start of building our first state machine module.

#![allow(unused)]
fn main() {
/* TODO: create a new public struct named `Pallet`. */
}
/* TODO: use your new module `balances` */

fn main() {
	println!("Hello, world!");
}
#![allow(unused)]
fn main() {
pub struct Pallet {}
}
mod balances;

fn main() {
	println!("Hello, world!");
}
diff --git a/src/balances.rs b/src/balances.rs
new file mode 100644
index 00000000..dae1c4f1
--- /dev/null
+++ b/src/balances.rs
@@ -0,0 +1 @@
+/* TODO: create a new public struct named `Pallet`. */
diff --git a/src/main.rs b/src/main.rs
index a30eb952..2b4f7670 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+/* TODO: use your new module `balances` */
+
 fn main() {
 	println!("Hello, world!");
 }
diff --git a/src/balances.rs b/src/balances.rs
index dae1c4f1..4a1da04e 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1 +1 @@
-/* TODO: create a new public struct named `Pallet`. */
+pub struct Pallet {}
diff --git a/src/main.rs b/src/main.rs
index 2b4f7670..ea8024e5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,4 @@
-/* TODO: use your new module `balances` */
+mod balances;
 
 fn main() {
 	println!("Hello, world!");

Adding State to Our Pallet

So let's add some simple state to our balances.rs module.

We can do this by adding fields into our Pallet struct.

For a balance system, we really only need to keep track of one thing: how much balance each user has in our system.

For this we will use a BTreeMap, which we can import from the Rust std library.

Maps are simple key -> value objects, allowing us to define an arbitrary sized storage where we can map some user identifier (key) to their account balance (value).

  1. Import the BTreeMap object.

    #![allow(unused)]
    fn main() {
    use std::collections::BTreeMap;
    }
  2. Create a balances field in Pallet using the BTreeMap.

    For the key, we are using a simple static string for now. This way we can access users like "alice", "bob", etc... This will be changed in the future.

    For the value, we will use a u128, which is the largest natively supported type in Rust. This will allow our users to have very, very large balances if we want.

    In the end, that looks like:

    #![allow(unused)]
    fn main() {
    pub struct Pallet {
    	balances: BTreeMap<String, u128>,
    }
    }
  3. Finally, we need a way to initialize this object and its state. For this, we will implement a function on the Pallet called fn new():

    #![allow(unused)]
    fn main() {
    impl Pallet {
    	pub fn new() -> Self {
    		Self {
    			balances: BTreeMap::new()
    		}
    	}
    }
    }

You can confirm at this point that everything should still be compiling, and that you haven't made any small errors. Warnings are okay.

Next we will actually start to use this module.

Notes

It is important to note that this is NOT how Pallet storage works with the Polkadot SDK, but just a simple emulation of the behaviors.

In the Polkadot SDK, there is a separate storage layer which manages a proper key-value database which holds all the information (past and present) of our blockchain system. There are abstractions which look and behave just like a BTreeMap in the Polkadot SDK, but the underlying logic which maintains that data is much more complex.

Using simple fields in a struct keeps this project simple, and illustrates that each Pallet really is meant to manage it's own storage. However, this simplification also leads to issues if you design more complex systems where multiple pallets interact with one another.

We won't have any cross pallet interactions in this workshop, however, this is definitely doable with the Polkadot SDK and a proper database.

#![allow(unused)]
fn main() {
/* TODO: Import `std::collections::BTreeMap` so it can be used below. */

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	/* TODO: Add a field `balances` which is a `BTreeMap` fom `String` to `u128`. */
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		/* TODO: Return a new instance of the `Pallet` struct. */
		/* TODO: Remove `unimplemented!()`. */
		unimplemented!()
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index 4a1da04e..003e8383 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1 +1,18 @@
-pub struct Pallet {}
+/* TODO: Import `std::collections::BTreeMap` so it can be used below. */
+
+/// This is the Balances Module.
+/// It is a simple module which keeps track of how much balance each account has in this state
+/// machine.
+pub struct Pallet {
+	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
+	/* TODO: Add a field `balances` which is a `BTreeMap` fom `String` to `u128`. */
+}
+
+impl Pallet {
+	/// Create a new instance of the balances module.
+	pub fn new() -> Self {
+		/* TODO: Return a new instance of the `Pallet` struct. */
+		/* TODO: Remove `unimplemented!()`. */
+		unimplemented!()
+	}
+}
diff --git a/src/balances.rs b/src/balances.rs
index 003e8383..43377478 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,18 +1,16 @@
-/* TODO: Import `std::collections::BTreeMap` so it can be used below. */
+use std::collections::BTreeMap;
 
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
 pub struct Pallet {
 	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
-	/* TODO: Add a field `balances` which is a `BTreeMap` fom `String` to `u128`. */
+	balances: BTreeMap<String, u128>,
 }
 
 impl Pallet {
 	/// Create a new instance of the balances module.
 	pub fn new() -> Self {
-		/* TODO: Return a new instance of the `Pallet` struct. */
-		/* TODO: Remove `unimplemented!()`. */
-		unimplemented!()
+		Self { balances: BTreeMap::new() }
 	}
 }

Interacting with Balances

Now that we have established the basics of our balances module, let's add ways to interact with it.

To do this, we will continue to create more functions implemented on Pallet which grants access to read, write, and update the balances: BTreeMap we created.

Finally, we will see what it looks like to actually start interacting with our balances pallet from the main.rs file.

Rust Prerequisite Knowledge

Before we continue, let's take a moment to go over some Rust which we will be using in this next section.

Option and Option Handling

One of the key principals of Rust is to remove undefined behavior from your code.

One way undefined behavior can happen is by allowing states like null to exist. Rust prevents this by having the user explicitly handle all cases, and this is where the creation of the Option type comes in. Spend a moment to re-review the section on Option from the Rust book if needed.

The BTreeMap api uses an Option when reading values from the map, since it could be that you ask to read the value of some key that you did not set. For example:

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

let mut map = BTreeMap::new();
map.insert("alice", 100);
assert_eq!(map.get(&"alice"), Some(&100));
assert_eq!(map.get(&"bob"), None);
}

Once we have an Option type, there are lots of different ways we can interact with it using Rust.

The most verbose way is using a match statement:

#![allow(unused)]
fn main() {
let maybe_value = map.get(&"alice");
match maybe_value {
	Some(value) => {
		// do something with the `value`
	},
	None => {
		// perhaps return an error since there was no value there
	}
}
}

IMPORTANT NOTE!

What you SHOULD NOT do is blindly unwrap() options. This will result in a panic in your code, which is exactly the kind of thing Rust was designed to prevent! Instead, you should always explicitly handle all of your different logical cases, and if you let Rust do it's job, your code will be super safe.

In the context of what we are designing for with the balances module, we have a map which has an arbitrary number of user keys, and their balance values.

What should we do when we read the balance of a user which does not exist in our map?

Well, the trick here is that in the context of blockchains, a user having None balance, and a user having 0 balance is the same. Of course, there is some finer details to be expressed between a user who exists in our state with value 0 and a user which does not exist at all, but for the purposes of our APIs, we can treat them the same.

What does this look like?

Well, we can use unwrap_or(...) to safely handle this condition, and make our future APIs more ergonomic to use. For example:

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

let mut map = BTreeMap::new();
map.insert("alice", 100);
assert_eq!(*map.get(&"alice").unwrap_or(&0), 100);
assert_eq!(*map.get(&"bob").unwrap_or(&0), 0);
}

As you can see, by using unwrap_or(&0) after reading from our map, we are able to turn our Option into a basic integer, where users with some value have their value exposed, and users with None get turned into 0.

Let's see how that can be used next.

Setting and Reading User Balances

As you can see, our initial state machine starts that everyone has no balance.

To make our module useful, we need to at least have some functions which will allow us to mint new balances for users, and to read those balances.

  1. Create a new function inside impl Pallet called fn set_balance:

    #![allow(unused)]
    fn main() {
    impl Pallet {
    	pub fn set_balance(&mut self, who: &String, amount: u128) {
    		self.balances.insert(who.clone(), amount);
    	}
    
    	// -- snip --
    }
    }

    As you can see, this function simply takes input about which user we want to set the balance of, and what balance we want to set. This then pushes that information into our BTreeMap, and that is all.

  2. Create a new function inside impl Pallet called fn balance:

    #![allow(unused)]
    fn main() {
    pub fn balance(&self, who: &String) -> u128 {
    	*self.balances.get(who).unwrap_or(&0)
    }
    }

    As you can see, this function allows us to read the balance of users in our map. The function allows you to input some user, and we will return their balance.

    Important Detail!

    Note that we do our little trick here! Rather than exposing an API which forces the user downstream to handle an Option, we instead are able to have our API always return a u128 by converting any user with None value into 0.

As always, confirm everything is still compiling. Warnings are okay.

Next we will write our first test and actually interact with our balances module.

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		/* Insert `amount` into the BTreeMap under `who`. */
		unimplemented!()
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		/* Return the balance of `who`, returning zero if `None`. */
		unimplemented!()
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index 43377478..6a03b5bd 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -13,4 +13,17 @@ impl Pallet {
 	pub fn new() -> Self {
 		Self { balances: BTreeMap::new() }
 	}
+
+	/// Set the balance of an account `who` to some `amount`.
+	pub fn set_balance(&mut self, who: &String, amount: u128) {
+		/* Insert `amount` into the BTreeMap under `who`. */
+		unimplemented!()
+	}
+
+	/// Get the balance of an account `who`.
+	/// If the account has no stored balance, we return zero.
+	pub fn balance(&self, who: &String) -> u128 {
+		/* Return the balance of `who`, returning zero if `None`. */
+		unimplemented!()
+	}
 }
diff --git a/src/balances.rs b/src/balances.rs
index 6a03b5bd..2a6bbfbc 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -16,14 +16,12 @@ impl Pallet {
 
 	/// Set the balance of an account `who` to some `amount`.
 	pub fn set_balance(&mut self, who: &String, amount: u128) {
-		/* Insert `amount` into the BTreeMap under `who`. */
-		unimplemented!()
+		self.balances.insert(who.clone(), amount);
 	}
 
 	/// Get the balance of an account `who`.
 	/// If the account has no stored balance, we return zero.
 	pub fn balance(&self, who: &String) -> u128 {
-		/* Return the balance of `who`, returning zero if `None`. */
-		unimplemented!()
+		*self.balances.get(who).unwrap_or(&0)
 	}
 }

Basic Balance Test

Now that we have the basics of our Pallet set up, let's actually interact with it.

For that, we will go back to the main.rs file, and create our first #[test] which will play with the code we have written so far.

  1. In your src/balances.rs file, add a new #[test] named fn init_balances():

    #![allow(unused)]
    fn main() {
    #[test]
    fn init_balances() { }
    }
  2. To begin our test, we need to initialize a new instance of our Pallet:

    #![allow(unused)]
    fn main() {
    #[test]
    fn init_balances() {
    	let mut balances = super::Pallet::new();
    }
    }

    Note that we make this variable mut since we plan to mutate our state using our newly created API.

  3. Finally, let's check that our read and write APIs are working as expected:

    #![allow(unused)]
    fn main() {
    #[test]
    fn init_balances() {
    	let mut balances = super::Pallet::new();
    
    	assert_eq!(balances.balance(&"alice".to_string()), 0);
    	balances.set_balance(&"alice".to_string(), 100);
    	assert_eq!(balances.balance(&"alice".to_string()), 100);
    	assert_eq!(balances.balance(&"bob".to_string()), 0);
    }
    }
  4. We can run our tests using cargo test, where hopefully you should see that it passes. There should be no compiler warnings now!

I hope at this point you can start to see the beginnings of your simple blockchain state machine.

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		/* TODO: Create a mutable variable `balances`, which is a new instance of `Pallet`. */

		/* TODO: Assert that the balance of `alice` starts at zero. */
		/* TODO: Set the balance of `alice` to 100. */
		/* TODO: Assert the balance of `alice` is now 100. */
		/* TODO: Assert the balance of `bob` has not changed and is 0. */
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index 2a6bbfbc..788d61c1 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -25,3 +25,16 @@ impl Pallet {
 		*self.balances.get(who).unwrap_or(&0)
 	}
 }
+
+#[cfg(test)]
+mod tests {
+	#[test]
+	fn init_balances() {
+		/* TODO: Create a mutable variable `balances`, which is a new instance of `Pallet`. */
+
+		/* TODO: Assert that the balance of `alice` starts at zero. */
+		/* TODO: Set the balance of `alice` to 100. */
+		/* TODO: Assert the balance of `alice` is now 100. */
+		/* TODO: Assert the balance of `bob` has not changed and is 0. */
+	}
+}
diff --git a/src/balances.rs b/src/balances.rs
index 788d61c1..ea4e0424 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -30,11 +30,11 @@ impl Pallet {
 mod tests {
 	#[test]
 	fn init_balances() {
-		/* TODO: Create a mutable variable `balances`, which is a new instance of `Pallet`. */
+		let mut balances = super::Pallet::new();
 
-		/* TODO: Assert that the balance of `alice` starts at zero. */
-		/* TODO: Set the balance of `alice` to 100. */
-		/* TODO: Assert the balance of `alice` is now 100. */
-		/* TODO: Assert the balance of `bob` has not changed and is 0. */
+		assert_eq!(balances.balance(&"alice".to_string()), 0);
+		balances.set_balance(&"alice".to_string(), 100);
+		assert_eq!(balances.balance(&"alice".to_string()), 100);
+		assert_eq!(balances.balance(&"bob".to_string()), 0);
 	}
 }

Enable Balance Transfers

Now that we have initialized and started to use our balances module, let's add probably the most important API: transfer.

Learn

Before we write our function, it is important that we review some of the principles of blockchain and Rust.

Bad Actors

In a blockchain system, security is paramount. Bad actors may attempt to exploit vulnerabilities, such as insufficient balances during fund transfers, or overflow / underflow issues. Rust's safe math and error handling mechanisms help mitigate these risks.

Safe Math

Rust's safe math operations prevent overflow and underflow. The checked_add and checked_sub methods return an Option that allows handling potential arithmetic errors safely.

In Rust, the Option type is a fundamental part of the standard library, designed to handle scenarios where a value may or may not be present. It's commonly used in situations where the result of an operation might be undefined or absent.

Methods like checked_add and checked_sub return Option to indicate success or failure due to overflow or underflow.

#![allow(unused)]
fn main() {
let result = a.checked_add(b);
match result {
    Some(sum) => println!("Sum: {}", sum),
    None => println!("Overflow occurred."),
}
}

Error Handling

In Rust, error handling is an integral part of writing robust and safe code. The Result type is commonly used for functions that may encounter errors during their execution.

The Result type is an enum defined in the standard library. It has two variants: Ok(value) for a successful result and Err(error) for an error:

#![allow(unused)]
fn main() {
enum Result<T, E> {
    Ok(T),
    Err(E),
}
}

T and E are generic parameters that allow you to customize the result type for your needs. For the purposes of this tutorial, we will always return Ok(()) when everything completes okay, and a Err(&'static str) to describe any errors with a basic string.

You can then define the Result type like:

#![allow(unused)]
fn main() {
Result<(), &'static str>
}

Options and Results

You can use the Option type to trigger an Err, which is helpful when you only want your function to execute when everything goes as expected.

In this context, we want a function that will return an error whenever some safe math operation returns None.

For this, we can chain ok_or along with ? directly after the safe math operation like so:

#![allow(unused)]
fn main() {
let new_from_balance = from_balance
    .checked_sub(amount)
    .ok_or("Not enough funds.")?;
}

If checked_sub returns None, we will then return an Err with the message "Not enough funds." that can be displayed to the user. Otherwise, if checked_sub returns Some(value), we will assign new_from_balance directly to that value.

In this case, we are writing code which completely handles the Option type in a safe and ergonomic way.

Create Transfer

Follow the instructions in the template to create a safe and simple transfer function in your Balances Pallet.

Create a test showing that everything is working as expected, including error handling. There should be no compiler warnings!

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: String,
		to: String,
		amount: u128,
	) -> Result<(), &'static str> {
		/* TODO:
			- Get the balance of account `caller`.
			- Get the balance of account `to`.

			- Use safe math to calculate a `new_caller_balance`.
			- Use safe math to calculate a `new_to_balance`.

			- Insert the new balance of `caller`.
			- Insert the new balance of `to`.
		*/

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		/* TODO: Create a test that checks the following:
			- That `alice` cannot transfer funds she does not have.
			- That `alice` can successfully transfer funds to `bob`.
			- That the balance of `alice` and `bob` is correctly updated.
		*/
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: String,
		to: String,
		amount: u128,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index ea4e0424..d2217619 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -24,6 +24,29 @@ impl Pallet {
 	pub fn balance(&self, who: &String) -> u128 {
 		*self.balances.get(who).unwrap_or(&0)
 	}
+
+	/// Transfer `amount` from one account to another.
+	/// This function verifies that `from` has at least `amount` balance to transfer,
+	/// and that no mathematical overflows occur.
+	pub fn transfer(
+		&mut self,
+		caller: String,
+		to: String,
+		amount: u128,
+	) -> Result<(), &'static str> {
+		/* TODO:
+			- Get the balance of account `caller`.
+			- Get the balance of account `to`.
+
+			- Use safe math to calculate a `new_caller_balance`.
+			- Use safe math to calculate a `new_to_balance`.
+
+			- Insert the new balance of `caller`.
+			- Insert the new balance of `to`.
+		*/
+
+		Ok(())
+	}
 }
 
 #[cfg(test)]
@@ -37,4 +60,13 @@ mod tests {
 		assert_eq!(balances.balance(&"alice".to_string()), 100);
 		assert_eq!(balances.balance(&"bob".to_string()), 0);
 	}
+
+	#[test]
+	fn transfer_balance() {
+		/* TODO: Create a test that checks the following:
+			- That `alice` cannot transfer funds she does not have.
+			- That `alice` can successfully transfer funds to `bob`.
+			- That the balance of `alice` and `bob` is correctly updated.
+		*/
+	}
 }
diff --git a/src/balances.rs b/src/balances.rs
index d2217619..78f233df 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -34,16 +34,14 @@ impl Pallet {
 		to: String,
 		amount: u128,
 	) -> Result<(), &'static str> {
-		/* TODO:
-			- Get the balance of account `caller`.
-			- Get the balance of account `to`.
+		let caller_balance = self.balance(&caller);
+		let to_balance = self.balance(&to);
 
-			- Use safe math to calculate a `new_caller_balance`.
-			- Use safe math to calculate a `new_to_balance`.
+		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
+		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;
 
-			- Insert the new balance of `caller`.
-			- Insert the new balance of `to`.
-		*/
+		self.balances.insert(caller, new_caller_balance);
+		self.balances.insert(to, new_to_balance);
 
 		Ok(())
 	}
@@ -63,10 +61,21 @@ mod tests {
 
 	#[test]
 	fn transfer_balance() {
-		/* TODO: Create a test that checks the following:
-			- That `alice` cannot transfer funds she does not have.
-			- That `alice` can successfully transfer funds to `bob`.
-			- That the balance of `alice` and `bob` is correctly updated.
-		*/
+		let mut balances = super::Pallet::new();
+
+		assert_eq!(
+			balances.transfer("alice".to_string(), "bob".to_string(), 51),
+			Err("Not enough funds.")
+		);
+
+		balances.set_balance(&"alice".to_string(), 100);
+		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
+		assert_eq!(balances.balance(&"alice".to_string()), 49);
+		assert_eq!(balances.balance(&"bob".to_string()), 51);
+
+		assert_eq!(
+			balances.transfer("alice".to_string(), "bob".to_string(), 51),
+			Err("Not enough funds.")
+		);
 	}
 }

The System and Runtime

In this section, you will create the System Pallet, a low level Pallet for managing basic blockchain state.

Then you will integrate both the Balances Pallet and System Pallet into your state transition function, called the Runtime.

Introduce the System Pallet

We have basically completed the creation of a basic Balances Pallet. This is the pallet that most users will interact with.

However, your blockchain usually needs to keep track of many other pieces of data to function properly.

For this, we will create a new pallet called the System Pallet.

What is the System Pallet?

The System Pallet is a "meta"-pallet which stores all the metadata needed for your blockchain to function. For example, the current blocknumber or the nonce of users on your blockchain.

This pallet does not need to expose any functions to end users, but can still play an important role in our overall state transition function.

We will see the importance of the System Pallet evolve as you walk through the steps of building it.

Create the System Pallet

  1. Create a new file src/system.rs in your project.
  2. Copy the starting template provided, then complete the steps outlined by the template code.
  3. Import the system module into your main.rs file.

You will notice that the instructions here are quite brief. You have already done all of these steps before, so you should already be familiar with everything you need to complete this step.

Confirm everything is compiling. You should expect some "never used/constructed" warnings. That is okay.

mod balances;
/* TODO: Import your new `system` module. */

fn main() {
	println!("Hello, world!");
}
#![allow(unused)]
fn main() {
/* TODO: You might need to update your imports. */

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
pub struct Pallet {
	/// The current block number.
	/* TODO: Create a field `block_number` that stores a `u32`. */
	/// A map from an account to their nonce.
	/* TODO: Create a field `nonce` that is a `BTreeMap` from `String` to `u32`. */
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		/* TODO: Return a new instance of the `Pallet` struct. */
	}
}
}
mod balances;
mod system;

fn main() {
	println!("Hello, world!");
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}
}
}
diff --git a/src/main.rs b/src/main.rs
index ea8024e5..d2fffb8b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
 mod balances;
+/* TODO: Import your new `system` module. */
 
 fn main() {
 	println!("Hello, world!");
diff --git a/src/system.rs b/src/system.rs
new file mode 100644
index 00000000..b4e6ef4e
--- /dev/null
+++ b/src/system.rs
@@ -0,0 +1,17 @@
+/* TODO: You might need to update your imports. */
+
+/// This is the System Pallet.
+/// It handles low level state needed for your blockchain.
+pub struct Pallet {
+	/// The current block number.
+	/* TODO: Create a field `block_number` that stores a `u32`. */
+	/// A map from an account to their nonce.
+	/* TODO: Create a field `nonce` that is a `BTreeMap` from `String` to `u32`. */
+}
+
+impl Pallet {
+	/// Create a new instance of the System Pallet.
+	pub fn new() -> Self {
+		/* TODO: Return a new instance of the `Pallet` struct. */
+	}
+}
diff --git a/src/main.rs b/src/main.rs
index d2fffb8b..815fd741 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
 mod balances;
-/* TODO: Import your new `system` module. */
+mod system;
 
 fn main() {
 	println!("Hello, world!");
diff --git a/src/system.rs b/src/system.rs
index b4e6ef4e..99d537c8 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -1,17 +1,17 @@
-/* TODO: You might need to update your imports. */
+use std::collections::BTreeMap;
 
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 pub struct Pallet {
 	/// The current block number.
-	/* TODO: Create a field `block_number` that stores a `u32`. */
+	block_number: u32,
 	/// A map from an account to their nonce.
-	/* TODO: Create a field `nonce` that is a `BTreeMap` from `String` to `u32`. */
+	nonce: BTreeMap<String, u32>,
 }
 
 impl Pallet {
 	/// Create a new instance of the System Pallet.
 	pub fn new() -> Self {
-		/* TODO: Return a new instance of the `Pallet` struct. */
+		Self { block_number: 0, nonce: BTreeMap::new() }
 	}
 }

Making Your System Functional

We have again established the basis of a new Pallet.

Let's add functions which make it useful.

Block Number

Your blockchain's blocknumber is stored in the System Pallet, and the System Pallet needs to expose functions which allow us to access and modify the block number.

For this we need two simple functions:

  • fn block_number - a function that returns the currently stored blocknumber.
  • fn inc_block_number - a function that increments the current block number by one.

This should be everything that a basic blockchain needs to function.

Nonce

The nonce represents "a number used once".

In this context, each user on your blockchain has a nonce which gives a unique value to each transaction the user submits to the blockchain.

Remember that blockchains are decentralized and distributed systems, and transactions do not inherently have a deterministic order. For a user, we can assign an order to different transactions by using this nonce to keep track of how many transactions the user has executed on the blockchain.

For this, we again use a BTreeMap to give each user their own nonce counter.

Our simple blockchain won't use this value, but for the sake of example, we will keep track of it by creating an inc_nonce function. If you were creating a more complex blockchain, the user nonce would become an important part of your system.

Safe Math?

We just explained the importance of using safe math when writing the Balances Pallet.

In that context, it is easy to see how a user could provide malicious inputs, and cause simple underflows or overflows if our system did not check the math.

However, you will see in the templates provided, that these new functions in the System Pallet do not return a result, and thus do not provide error handling.

Is this okay?

As you will notice, the blocknumber and nonce storage items only provide APIs to increment by one. In our System, both of these numbers are represented by u32, which means that over 4.2 billion calls to those functions need to occur before an overflow would happen.

Assuming a user does one transaction every block, and a new block is generated every 6 seconds, it would take over 800 years for an overflow to occur. So in this situation, we are preferring an API which requires no error handling rather than one which does.

End of the day, this is a design decision and a preference which is left to the developer. This tutorial chooses this API because this is exactly the API exposed by Substrate and the Polkadot SDK. There is nothing wrong with making these functions handle errors, so feel free to do this if you choose.

Build Your System Pallet

Follow the instructions in the template to complete:

  1. fn block_number
  2. fn inc_block_number
  3. fn inc_nonce

Then write tests which verify that these functions work as expected, and that your state is correctly updated. There should be no compiler warnings after this step!

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> u32 {
		/* TODO: Return the current block number. */
		unimplemented!()
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		/* TODO: Increment the current block number by one. */
		unimplemented!()
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &String) {
		/* TODO: Get the current nonce of `who`, and increment it by one. */
		unimplemented!()
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		/* TODO: Create a test which checks the following:
			- Increment the current block number.
			- Increment the nonce of `alice`.

			- Check the block number is what we expect.
			- Check the nonce of `alice` is what we expect.
			- Check the nonce of `bob` is what we expect.
		*/
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> u32 {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &String) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
diff --git a/src/system.rs b/src/system.rs
index 99d537c8..b46402c3 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -14,4 +14,39 @@ impl Pallet {
 	pub fn new() -> Self {
 		Self { block_number: 0, nonce: BTreeMap::new() }
 	}
+
+	/// Get the current block number.
+	pub fn block_number(&self) -> u32 {
+		/* TODO: Return the current block number. */
+		unimplemented!()
+	}
+
+	// This function can be used to increment the block number.
+	// Increases the block number by one.
+	pub fn inc_block_number(&mut self) {
+		/* TODO: Increment the current block number by one. */
+		unimplemented!()
+	}
+
+	// Increment the nonce of an account. This helps us keep track of how many transactions each
+	// account has made.
+	pub fn inc_nonce(&mut self, who: &String) {
+		/* TODO: Get the current nonce of `who`, and increment it by one. */
+		unimplemented!()
+	}
+}
+
+#[cfg(test)]
+mod test {
+	#[test]
+	fn init_system() {
+		/* TODO: Create a test which checks the following:
+			- Increment the current block number.
+			- Increment the nonce of `alice`.
+
+			- Check the block number is what we expect.
+			- Check the nonce of `alice` is what we expect.
+			- Check the nonce of `bob` is what we expect.
+		*/
+	}
 }
diff --git a/src/system.rs b/src/system.rs
index b46402c3..967578d0 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -17,22 +17,21 @@ impl Pallet {
 
 	/// Get the current block number.
 	pub fn block_number(&self) -> u32 {
-		/* TODO: Return the current block number. */
-		unimplemented!()
+		self.block_number
 	}
 
 	// This function can be used to increment the block number.
 	// Increases the block number by one.
 	pub fn inc_block_number(&mut self) {
-		/* TODO: Increment the current block number by one. */
-		unimplemented!()
+		self.block_number += 1;
 	}
 
 	// Increment the nonce of an account. This helps us keep track of how many transactions each
 	// account has made.
 	pub fn inc_nonce(&mut self, who: &String) {
-		/* TODO: Get the current nonce of `who`, and increment it by one. */
-		unimplemented!()
+		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
+		let new_nonce = nonce + 1;
+		self.nonce.insert(who.clone(), new_nonce);
 	}
 }
 
@@ -40,13 +39,12 @@ impl Pallet {
 mod test {
 	#[test]
 	fn init_system() {
-		/* TODO: Create a test which checks the following:
-			- Increment the current block number.
-			- Increment the nonce of `alice`.
+		let mut system = super::Pallet::new();
+		system.inc_block_number();
+		system.inc_nonce(&"alice".to_string());
 
-			- Check the block number is what we expect.
-			- Check the nonce of `alice` is what we expect.
-			- Check the nonce of `bob` is what we expect.
-		*/
+		assert_eq!(system.block_number(), 1);
+		assert_eq!(system.nonce.get("alice"), Some(&1));
+		assert_eq!(system.nonce.get("bob"), None);
 	}
 }

Creating Our Runtime

We have now established two different Pallets for our blockchain: the System and Balances Pallet.

How do these pallets work together to create a unified blockchain system?

For that, we will need to create a Runtime.

What is the Runtime?

Remember that there is a separation between the blockchain client and the state transition function of our blockchain.

You can think of the runtime as the accumulation of all logic which composes your state transition function. It will combine all of your pallets into a single object, and then expose that single object as the entry point for your users to interact with.

Certainly this sounds pretty abstract, but it will make more sense as we complete this tutorial.

Create the Runtime

Just like our Pallets, our Runtime will be represented with a simple struct, however in this case, the fields of our struct will be our Pallets!

Complete the instructions for creating a new runtime which includes our System and Balances pallets. For this, you will need to take advantage of the new() functions we exposed for each of the Pallets.

Make sure your code is formatted and everything is still compiling. Compiler warnings about "never read/used" are okay.

mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
pub struct Runtime {
	/* TODO:
		- Create a field `system` which is of type `system::Pallet`.
		- Create a field `balances` which is of type `balances::Pallet`.
	*/
}

impl Runtime {
	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
	fn new() -> Self {
		/* TODO: Create a new `Runtime` by creating new instances of `system` and `balances`. */
		unimplemented!()
	}
}

fn main() {
	println!("Hello, world!");
}
mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet,
}

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() {
	println!("Hello, world!");
}
diff --git a/src/main.rs b/src/main.rs
index 815fd741..24ff8681 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,23 @@
 mod balances;
 mod system;
 
+// This is our main Runtime.
+// It accumulates all of the different pallets we want to use.
+pub struct Runtime {
+	/* TODO:
+		- Create a field `system` which is of type `system::Pallet`.
+		- Create a field `balances` which is of type `balances::Pallet`.
+	*/
+}
+
+impl Runtime {
+	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
+	fn new() -> Self {
+		/* TODO: Create a new `Runtime` by creating new instances of `system` and `balances`. */
+		unimplemented!()
+	}
+}
+
 fn main() {
 	println!("Hello, world!");
 }
diff --git a/src/main.rs b/src/main.rs
index 24ff8681..2d9887b5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,17 +4,14 @@ mod system;
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 pub struct Runtime {
-	/* TODO:
-		- Create a field `system` which is of type `system::Pallet`.
-		- Create a field `balances` which is of type `balances::Pallet`.
-	*/
+	system: system::Pallet,
+	balances: balances::Pallet,
 }
 
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
 	fn new() -> Self {
-		/* TODO: Create a new `Runtime` by creating new instances of `system` and `balances`. */
-		unimplemented!()
+		Self { system: system::Pallet::new(), balances: balances::Pallet::new() }
 	}
 }
 

Using Our Runtime

Until now, we have just been scaffolding parts of our blockchain. Tests have ensured that the code we have written so far make sense, but we haven't actually USED any of the logic we have written for our main program.

Let's change that by using our Runtime and actually executing logic on our blockchain.

Simulating a Block

The input to any blockchain state transition function is a block of transactions.

Later in the tutorial we will actually spend more time to build proper blocks and execute them, but for now, we can "simulate" all the basics of what a block would do by individually calling the functions our Pallets expose.

Genesis State

The state of your blockchain will propagate from block to block. This means if Alice received 100 tokens on block 4, that she can transfer at least 100 tokens on block 5, and so on.

But how do users get any balance to begin with?

The answer to this question can be different for different blockchains, but in general most modern blockchains start with a Genesis State. This is the starting state of your blockchain on "block 0".

This means anything set in the genesis state can be used on block 1, and can bootstrap your blockchain to being functional.

In our situation, you can simply call low level functions like set_balance before we simulate our first block to establish our genesis state.

Steps of a Basic Block

Let's quickly break down the steps of executing a basic block:

  1. First we increment the blocknumber, since each new block will have a new blocknumber.
  2. Then we go through an execute each transaction in that block:
    1. Each transaction for our blockchain will come from a user, thus we will increment the users nonce as we process their transaction.
    2. Then we will attempt to execute the function they want to call, for example transfer.
    3. Repeat this process for every transaction.

Handling Errors

The main() function in Rust cannot propagate or handle errors itself. Either everything inside of it is handled, or you will have to trigger a panic.

As you have already learned, triggering a panic is generally not good, but may be the only thing you can do if something is seriously wrong. For our blockchain, the only thing which can really cause a panic is importing a block which does not match the expected blocknumber. There is nothing in this case we can do to "handle" this error. If someone is telling us to execute the wrong block, then we have some larger problem with our overall system that needs to be fixed.

However, users can also submit transactions which result in an error. For example, Alice trying to send more funds than she has in her account.

Should we panic?

Absolutely not! This is the kind of error that our runtime should be able to handle since it is expected that such errors would occur. A block can be valid even if transactions in the block are invalid!

When a transaction returns an error we should show that error to the user, and then "swallow" the result. For example:

#![allow(unused)]
fn main() {
let _res = i_can_return_error().map_err(|e| eprintln!("{}", e));
}

In this case, you can see that any error that i_can_return_error would return gets printed to the console, but otherwise, the Result of that function gets placed in an unused variable _res.

You should be VERY CAREFUL when you do this. Swallowing an error is exactly the opposite of proper error handling that Rust provides to developers. However, we really do not have a choice here in our main function, and we fully understand what we are doing here.

On real blockchain systems, users are still charged a transaction fee, even when their transaction results in an Err. This ensures that users are still paying a cost for triggering logic on the blockchain, even when the function fails. This is an important part of keeping our blockchain resilient to DDOS and sybil attacks.

Simulate Your First Block

Do you think you understand everything it takes to simulate your first block?

Follow the instructions provided by the template to turn your main function from "Hello, World!" to actually executing your blockchain's runtime.

At the end of this step, everything should compile and run without warnings!

mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet,
}

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() {
	/* TODO: Create a mutable variable `runtime`, which is a new instance of `Runtime`. */
	/* TODO: Set the balance of `alice` to 100, allowing us to execute other transactions. */

	// start emulating a block
	/* TODO: Increment the block number in system. */
	/* TODO: Assert the block number is what we expect. */

	// first transaction
	/* TODO: Increment the nonce of `alice`. */
	/* TODO: Execute a transfer from `alice` to `bob` for 30 tokens.
		- The transfer _could_ return an error. We should use `map_err` to print
		  the error if there is one.
		- We should capture the result of the transfer in an unused variable like `_res`.
	*/

	// second transaction
	/* TODO: Increment the nonce of `alice` again. */
	/* TODO: Execute another balance transfer, this time from `alice` to `charlie` for 20. */
}
mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet,
}

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));
}
diff --git a/src/main.rs b/src/main.rs
index 2d9887b5..6c117f65 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,5 +16,22 @@ impl Runtime {
 }
 
 fn main() {
-	println!("Hello, world!");
+	/* TODO: Create a mutable variable `runtime`, which is a new instance of `Runtime`. */
+	/* TODO: Set the balance of `alice` to 100, allowing us to execute other transactions. */
+
+	// start emulating a block
+	/* TODO: Increment the block number in system. */
+	/* TODO: Assert the block number is what we expect. */
+
+	// first transaction
+	/* TODO: Increment the nonce of `alice`. */
+	/* TODO: Execute a transfer from `alice` to `bob` for 30 tokens.
+		- The transfer _could_ return an error. We should use `map_err` to print
+		  the error if there is one.
+		- We should capture the result of the transfer in an unused variable like `_res`.
+	*/
+
+	// second transaction
+	/* TODO: Increment the nonce of `alice` again. */
+	/* TODO: Execute another balance transfer, this time from `alice` to `charlie` for 20. */
 }
diff --git a/src/main.rs b/src/main.rs
index 6c117f65..808d6732 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,22 +16,25 @@ impl Runtime {
 }
 
 fn main() {
-	/* TODO: Create a mutable variable `runtime`, which is a new instance of `Runtime`. */
-	/* TODO: Set the balance of `alice` to 100, allowing us to execute other transactions. */
+	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
-	/* TODO: Increment the block number in system. */
-	/* TODO: Assert the block number is what we expect. */
+	runtime.system.inc_block_number();
+	assert_eq!(runtime.system.block_number(), 1);
 
 	// first transaction
-	/* TODO: Increment the nonce of `alice`. */
-	/* TODO: Execute a transfer from `alice` to `bob` for 30 tokens.
-		- The transfer _could_ return an error. We should use `map_err` to print
-		  the error if there is one.
-		- We should capture the result of the transfer in an unused variable like `_res`.
-	*/
+	runtime.system.inc_nonce(&alice);
+	let _res = runtime
+		.balances
+		.transfer(alice.clone(), bob, 30)
+		.map_err(|e| eprintln!("{}", e));
 
 	// second transaction
-	/* TODO: Increment the nonce of `alice` again. */
-	/* TODO: Execute another balance transfer, this time from `alice` to `charlie` for 20. */
+	runtime.system.inc_nonce(&alice);
+	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));
 }

Derive Debug

In Rust, derive macros provide a convenient way to automatically implement trait functionality for custom data structures.

Macros

In the most simple terms, Macros are rust code that write more rust code.

Macros can make your code easier to read, help avoid repetition, and even let you create your own special rules for coding in Rust.

We will be using (but not writing) macros heavily near the end of this tutorial, and you will see how powerful they can be.

For now, treat them as "magic".

Traits

Think of traits in Rust as shared rules for different types. They allow you to define a set of things that types must be able to do. This way, you can make sure different parts of your code follow the same rules.

Take a look at this example or re-read the Rust Book if you need a refresher on Traits.

We will make and use custom traits later in this tutorial, but know for this step that #[derive(Debug)] is a macro which implements the Debug trait for your custom types.

Debug Trait

The Debug trait in Rust is part of the standard library and is used to print and format values for debugging purposes. It provides a default implementation through the `#[derive(Debug)] annotation.

For example:

#![allow(unused)]
fn main() {
#[derive(Debug)]
pub struct MyStruct {
    field1: i32,
    field2: String,
}
}

With the Debug trait derived, you can now print the struct to console:

#![allow(unused)]
fn main() {
let my_instance = MyStruct { field1: 42, field2: "Hello".to_string() };
println!("{:#?}", my_instance);
}

The characters :#? help format the output to make it more readable.

Derive the Debug Trait for Your Runtime

This is a very simple, but helpful step!

We want to be able to print out the current state of our Runtime at the end of our main to allow us to easily inspect what it looks like and that everything is functioning as we expect.

To do this, we need to add #[derive(Debug)] to the struct Runtime.

However... struct Runtime is composed of system::Pallet and balances::Pallet, so these structs ALSO need to implement the Debug trait.

Complete the TODOs across the different files in your project and print out your final runtime at the end of the main function.

You can use cargo run to see the output of your println. Everything should compile and run without warnings.

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: String,
		to: String,
		amount: u128,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
/* TODO: Add the derive macro to implement the `Debug` trait for `Runtime`. */
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet,
}

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));

	/* TODO: Print the final runtime state after all transactions. */
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> u32 {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &String) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: String,
		to: String,
		amount: u128,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod system;

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet,
}

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);
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> u32 {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &String) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index 78f233df..1b9d9d85 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -3,6 +3,7 @@ use std::collections::BTreeMap;
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
+/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
 pub struct Pallet {
 	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
 	balances: BTreeMap<String, u128>,
diff --git a/src/main.rs b/src/main.rs
index 808d6732..b79655ae 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ mod system;
 
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
+/* TODO: Add the derive macro to implement the `Debug` trait for `Runtime`. */
 pub struct Runtime {
 	system: system::Pallet,
 	balances: balances::Pallet,
@@ -37,4 +38,6 @@ fn main() {
 	// second transaction
 	runtime.system.inc_nonce(&alice);
 	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));
+
+	/* TODO: Print the final runtime state after all transactions. */
 }
diff --git a/src/system.rs b/src/system.rs
index 967578d0..cbf3b195 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -2,6 +2,7 @@ use std::collections::BTreeMap;
 
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
+/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
 pub struct Pallet {
 	/// The current block number.
 	block_number: u32,
diff --git a/src/balances.rs b/src/balances.rs
index 1b9d9d85..e09906cb 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
-/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
+#[derive(Debug)]
 pub struct Pallet {
 	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
 	balances: BTreeMap<String, u128>,
diff --git a/src/main.rs b/src/main.rs
index b79655ae..1ebef924 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,7 @@ mod system;
 
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
-/* TODO: Add the derive macro to implement the `Debug` trait for `Runtime`. */
+#[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet,
 	balances: balances::Pallet,
@@ -39,5 +39,5 @@ fn main() {
 	runtime.system.inc_nonce(&alice);
 	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));
 
-	/* TODO: Print the final runtime state after all transactions. */
+	println!("{:#?}", runtime);
 }
diff --git a/src/system.rs b/src/system.rs
index cbf3b195..2fc5d764 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
 
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
-/* TODO: Add the derive macro to implement the `Debug` trait for `Pallet`. */
+#[derive(Debug)]
 pub struct Pallet {
 	/// The current block number.
 	block_number: u32,

Generic and Configurable Types

In this section, we will be harnessing the full power of Rust to create a generic and configurable Runtime.

There will be no real logical changes happening in the next steps.

Instead, we will be gradually abstracting away the concrete types defined in our Pallets, and instead structure our code to handle purely generic types.

At the end of the section, you will have a project whose structure exactly mirrors what is found in the Polkadot SDK and understand how all of it works.

Using Named Types

Up till now, we have just been hardcoding raw types into our structs and function definitions.

There are already examples where this can be confusing, for example if you see a function accept a u32 parameter, is it a blocknumber or a nonce?

To make our code more clear, let's extract all of our raw types and define custom named types for our structs and functions.

Across the Balances and System Pallet, we need to define the following types:

  1. type AccountId = String;
  2. type Balance = u128;
  3. type Nonce = u32;
  4. type BlockNumber = u32;

Note that extracting these types into common type definitions also allows us to update the types more easily if we choose to.

As we go further into this tutorial, we will show you how we can make these type definitions even more flexible and customizable in the context of building a blockchain SDK for developers like yourself.

Create Custom Types

Follow the TODOs in the template to add these type definitions to each of your Pallets, and update all of your structs and functions to use these types.

#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/*
	TODO: Define the common types used in this pallet:
		- `AccountID`
		- `Balance`

	Then update this pallet to use these common types.
*/

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet {
	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
	balances: BTreeMap<String, u128>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &String, amount: u128) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &String) -> u128 {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: String,
		to: String,
		amount: u128,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

/*
	TODO: Define the common types used in this pallet:
		- `AccountID`
		- `BlockNumber`
		- `Nonce`

	Then update this pallet to use these common types.
*/

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet {
	/// The current block number.
	block_number: u32,
	/// A map from an account to their nonce.
	nonce: BTreeMap<String, u32>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> u32 {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &String) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

type AccountId = String;
type Balance = u128;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<AccountId, Balance>,
}

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &AccountId) -> Balance {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: AccountId,
		to: AccountId,
		amount: Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

type AccountId = String;
type BlockNumber = u32;
type Nonce = u32;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet {
	/// The current block number.
	block_number: BlockNumber,
	/// A map from an account to their nonce.
	nonce: BTreeMap<AccountId, Nonce>,
}

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> BlockNumber {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &AccountId) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index e09906cb..51aea28f 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,5 +1,13 @@
 use std::collections::BTreeMap;
 
+/*
+	TODO: Define the common types used in this pallet:
+		- `AccountID`
+		- `Balance`
+
+	Then update this pallet to use these common types.
+*/
+
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
diff --git a/src/system.rs b/src/system.rs
index 2fc5d764..a4740a6b 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -1,5 +1,14 @@
 use std::collections::BTreeMap;
 
+/*
+	TODO: Define the common types used in this pallet:
+		- `AccountID`
+		- `BlockNumber`
+		- `Nonce`
+
+	Then update this pallet to use these common types.
+*/
+
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
diff --git a/src/balances.rs b/src/balances.rs
index 51aea28f..543111e7 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,20 +1,15 @@
 use std::collections::BTreeMap;
 
-/*
-	TODO: Define the common types used in this pallet:
-		- `AccountID`
-		- `Balance`
-
-	Then update this pallet to use these common types.
-*/
+type AccountId = String;
+type Balance = u128;
 
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
 #[derive(Debug)]
 pub struct Pallet {
-	// A simple storage mapping from accounts (`String`) to their balances (`u128`).
-	balances: BTreeMap<String, u128>,
+	// A simple storage mapping from accounts to their balances.
+	balances: BTreeMap<AccountId, Balance>,
 }
 
 impl Pallet {
@@ -24,13 +19,13 @@ impl Pallet {
 	}
 
 	/// Set the balance of an account `who` to some `amount`.
-	pub fn set_balance(&mut self, who: &String, amount: u128) {
+	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
 		self.balances.insert(who.clone(), amount);
 	}
 
 	/// Get the balance of an account `who`.
 	/// If the account has no stored balance, we return zero.
-	pub fn balance(&self, who: &String) -> u128 {
+	pub fn balance(&self, who: &AccountId) -> Balance {
 		*self.balances.get(who).unwrap_or(&0)
 	}
 
@@ -39,9 +34,9 @@ impl Pallet {
 	/// and that no mathematical overflows occur.
 	pub fn transfer(
 		&mut self,
-		caller: String,
-		to: String,
-		amount: u128,
+		caller: AccountId,
+		to: AccountId,
+		amount: Balance,
 	) -> Result<(), &'static str> {
 		let caller_balance = self.balance(&caller);
 		let to_balance = self.balance(&to);
diff --git a/src/system.rs b/src/system.rs
index a4740a6b..b63ab24e 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -1,22 +1,17 @@
 use std::collections::BTreeMap;
 
-/*
-	TODO: Define the common types used in this pallet:
-		- `AccountID`
-		- `BlockNumber`
-		- `Nonce`
-
-	Then update this pallet to use these common types.
-*/
+type AccountId = String;
+type BlockNumber = u32;
+type Nonce = u32;
 
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
 pub struct Pallet {
 	/// The current block number.
-	block_number: u32,
+	block_number: BlockNumber,
 	/// A map from an account to their nonce.
-	nonce: BTreeMap<String, u32>,
+	nonce: BTreeMap<AccountId, Nonce>,
 }
 
 impl Pallet {
@@ -26,7 +21,7 @@ impl Pallet {
 	}
 
 	/// Get the current block number.
-	pub fn block_number(&self) -> u32 {
+	pub fn block_number(&self) -> BlockNumber {
 		self.block_number
 	}
 
@@ -38,7 +33,7 @@ impl Pallet {
 
 	// Increment the nonce of an account. This helps us keep track of how many transactions each
 	// account has made.
-	pub fn inc_nonce(&mut self, who: &String) {
+	pub fn inc_nonce(&mut self, who: &AccountId) {
 		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
 		let new_nonce = nonce + 1;
 		self.nonce.insert(who.clone(), new_nonce);

Import the Num Crate

Rust is designed to be very lightweight and provides very little right out of the box.

Within the ecosystem, many functions and features which you might expect to be included into Rust std or core are actually delegated to small, well-known, and widely used crates.

For our next step, we want to access traits for basic numerical operations like:

  • CheckedAdd - A type which supports checked_add
  • CheckedSub - A type which supports checked_sub
  • Zero - A type which can return the value zero when calling zero()
  • One - A type which can return the value one when calling one()

To access these traits, we will need to import a new crate into our project.

Cargo.toml

When we first initialized our project, a Cargo.toml file was generated for us.

As mentioned before, it is very similar to a package.json file you would expect to find in a Node.js project.

Already in your Cargo.toml is metadata like the name of your project, the version of the crate you are building, and the edition of Rust you are using.

What you can see is that you can also add dependencies to your crate which will allow you to use other external crates and libraries in your project.

You can add the dependency by hand by editing your Cargo.toml file or you can run cargo add num.

Crates.io

Where is this crate coming from?

The Rust community has a large registry of available crates on crates.io. When you import a crate, it will use crates.io by default.

You can also import crates directly from github by specifying the repo where the source code can be found.

That would look something like:

[dependencies]
pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }

Add the Num Crate to Your Project

This step is short and simple.

Run cargo add num in your project directory and make sure your project compiles afterward.

You should see something like:

➜  rust-state-machine git:(master) ✗ cargo add num
    Updating crates.io index
      Adding num v0.4.1 to dependencies.
             Features:
             + std
             - alloc
             - libm
             - num-bigint
             - rand
             - serde
    Updating crates.io index
➜  rust-state-machine git:(master) ✗ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/rust-state-machine`
[package]
name = "rust-state-machine"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num = "0.4.1"
diff --git a/Cargo.lock b/Cargo.lock
index 75fe297f..10ded84b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,91 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "num"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
+dependencies = [
+ "num-bigint",
+ "num-complex",
+ "num-integer",
+ "num-iter",
+ "num-rational",
+ "num-traits",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
+dependencies = [
+ "autocfg",
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
 [[package]]
 name = "rust-state-machine"
 version = "0.1.0"
+dependencies = [
+ "num",
+]
diff --git a/Cargo.toml b/Cargo.toml
index c7fe36cd..42b80bf8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,3 +6,4 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+num = "0.4.1"

Make Balances Pallet Generic

Our goal over the next few steps will be to continually make our runtime more generic and configurable over the types we use in our Pallets.

Why Generic?

The flexibility of generic runtime means that we can write code which works for multiple different configurations and types.

For example, up until now, we have been using &'static str to represent the accounts of users. This is obviously not the right thing to do, but is easy to implement for a basic blockchain tutorial like this.

What would you need to change in order to use more traditional cryptographic public keys?

Well, currently there are definitions of the account type in both the Balances Pallet and the System Pallet. Imagine if you had many more Pallets too! Such refactoring could be very difficult, but also totally avoided if we used generic types to begin with.

Truthfully, the advantage of generic types will not be super obvious in this tutorial, but when building a blockchain SDK like the Substrate, this kind of flexibility will allow ecosystem developers to reach their full potential.

For example, teams have used Substrate to build fully compatible Ethereum blockchains, while other teams have experimented with cutting edge cryptographic primitives. This generic framework allows both teams to be successful.

Generic Types

You have already been lightly exposed to generic types with the Result type. Remember that this type is flexible to allow for you to configure what type is returned when there is Ok or Err.

If we wanted to make our Pallet generic, it would look something like:

#![allow(unused)]
fn main() {
pub struct Pallet<AccountId, Balance> {
 	balances: BTreeMap<AccountId, Balance>,
}
}

And implementing functions on Pallet would look like:

#![allow(unused)]
fn main() {
impl<AccountId, Balance> Pallet<AccountId, Balance> {
	// functions which use these types
}
}

In this case, we have not defined what the AccountId and Balance type are concretely, just that we will be storing a BTreeMap where the AccountId type is a key and Balance type is a value.

Trait Constraints

The Result generic type is extremely flexible because there are no constraints on what the Ok or Err type has to be. Every type will work for this situation.

However, our Pallets are not that flexible. The Balance type cannot literally be any type. Because we have functions like fn transfer, we must require that the Balance type at least has access to the function checked_sub, checked_add, and has some representation of zero.

This is where the num crate will come in hand. From the num crate, you can import traits which define types which expose these functions:

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
}

Then, where applicable, you need to constrain your generic types to have these traits.

That will look like:

#![allow(unused)]
fn main() {
impl<AccountId, Balance> Pallet<AccountId, Balance>
where
	AccountId: Ord,
	Balance: Zero + CheckedSub + CheckedAdd + Copy,
{
	// functions which use these types and have access to the traits specified
}
}

You will notice other types like Copy and Ord that have been added. These constrains come from using structures like the BTreeMap, which requires that the key type is "orderable".

You can actually try compiling your code without these type constraints, and the compiler will tell you which traits you are missing, and what you need to include.

Instantiating a Generic Type

The final piece of the puzzle is instantiating our generic types.

Previously we could simply write:

#![allow(unused)]
fn main() {
let mut balances = super::Pallet::new();
}

But now that Pallet is generic, we need to concretely define those types when we instantiate it.

That syntax looks like:

#![allow(unused)]
fn main() {
let mut balances = super::Pallet::<&'static str, u128>::new();
}

You will notice that now the types are defined wherever the generic struct Pallet is being instantiated. This means that you can extract the types out of your Pallets, and move them into the Runtime.

Get Generic!

Its time to turn your balances pallet generic.

  1. Follow the TODOs in the balances.rs file to make Pallet generic.
  2. Move the type definitions for AccountId and Balance to your main.rs.
  3. Update your struct Runtime to use these types when defining the balances::Pallet.

To be honest, this is one of the places that developers most frequently have problems when learning Rust, which is why there is such an emphasis on teaching you and having you learn by doing these steps yourself.

Don't be afraid in this step to peek at the solution if you get stuck, but do try and learn the patterns of using generic types, and what all the syntax means in terms of what the compiler is trying to guarantee about type safety.

#![allow(unused)]
fn main() {
/* TODO: You might need to import some stuff for this step. */
use std::collections::BTreeMap;

type AccountId = String;
type Balance = u128;

/*
	TODO:
	Update the `Pallet` struct to be generic over the `AccountId` and `Balance` type.

	You won't need the type definitions above after you are done.
	Types will now be defined in `main.rs`. See the TODOs there.
*/

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<AccountId, Balance>,
}

/*
	TODO:
	The generic types need to satisfy certain traits in order to be used in the functions below.
		- AccountId: Ord
		- Balance: Zero + CheckedSub + CheckedAdd + Copy

	You could figure these traits out yourself by letting the compiler tell you what you're missing.

	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
*/

impl Pallet {
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &AccountId) -> Balance {
		*self.balances.get(who).unwrap_or(&0)
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: AccountId,
		to: AccountId,
		amount: Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		/*
			TODO:
			When creating an instance of `Pallet`, you should explicitly define the types you use.
		*/
		let mut balances = super::Pallet::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		/*
			TODO:
			When creating an instance of `Pallet`, you should explicitly define the types you use.
		*/
		let mut balances = super::Pallet::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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 {
	/*
		TODO: Move your type definitions for `AccountId` and `Balance` here.
	*/
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet,
	/* TODO: Use your type definitions for your new generic `balances::Pallet`. */
	balances: balances::Pallet,
}

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);
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<AccountId, Balance> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<AccountId, Balance>,
}

impl<AccountId, Balance> Pallet<AccountId, Balance>
where
	AccountId: Ord + Clone,
	Balance: Zero + CheckedSub + CheckedAdd + Copy,
{
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &AccountId) -> Balance {
		*self.balances.get(who).unwrap_or(&Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: AccountId,
		to: AccountId,
		amount: Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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;
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet,
	balances: balances::Pallet<types::AccountId, 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/balances.rs b/src/balances.rs
index 543111e7..1effef7a 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,8 +1,17 @@
+/* TODO: You might need to import some stuff for this step. */
 use std::collections::BTreeMap;
 
 type AccountId = String;
 type Balance = u128;
 
+/*
+	TODO:
+	Update the `Pallet` struct to be generic over the `AccountId` and `Balance` type.
+
+	You won't need the type definitions above after you are done.
+	Types will now be defined in `main.rs`. See the TODOs there.
+*/
+
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
@@ -12,6 +21,17 @@ pub struct Pallet {
 	balances: BTreeMap<AccountId, Balance>,
 }
 
+/*
+	TODO:
+	The generic types need to satisfy certain traits in order to be used in the functions below.
+		- AccountId: Ord
+		- Balance: Zero + CheckedSub + CheckedAdd + Copy
+
+	You could figure these traits out yourself by letting the compiler tell you what you're missing.
+
+	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
+*/
+
 impl Pallet {
 	/// Create a new instance of the balances module.
 	pub fn new() -> Self {
@@ -55,6 +75,10 @@ impl Pallet {
 mod tests {
 	#[test]
 	fn init_balances() {
+		/*
+			TODO:
+			When creating an instance of `Pallet`, you should explicitly define the types you use.
+		*/
 		let mut balances = super::Pallet::new();
 
 		assert_eq!(balances.balance(&"alice".to_string()), 0);
@@ -65,6 +89,10 @@ mod tests {
 
 	#[test]
 	fn transfer_balance() {
+		/*
+			TODO:
+			When creating an instance of `Pallet`, you should explicitly define the types you use.
+		*/
 		let mut balances = super::Pallet::new();
 
 		assert_eq!(
diff --git a/src/main.rs b/src/main.rs
index 1ebef924..1cfc058c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,21 @@
 mod balances;
 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 {
+	/*
+		TODO: Move your type definitions for `AccountId` and `Balance` here.
+	*/
+}
+
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 #[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet,
+	/* TODO: Use your type definitions for your new generic `balances::Pallet`. */
 	balances: balances::Pallet,
 }
 
diff --git a/src/balances.rs b/src/balances.rs
index 1effef7a..e333e0d9 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,38 +1,20 @@
-/* TODO: You might need to import some stuff for this step. */
+use num::traits::{CheckedAdd, CheckedSub, Zero};
 use std::collections::BTreeMap;
 
-type AccountId = String;
-type Balance = u128;
-
-/*
-	TODO:
-	Update the `Pallet` struct to be generic over the `AccountId` and `Balance` type.
-
-	You won't need the type definitions above after you are done.
-	Types will now be defined in `main.rs`. See the TODOs there.
-*/
-
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
 #[derive(Debug)]
-pub struct Pallet {
+pub struct Pallet<AccountId, Balance> {
 	// A simple storage mapping from accounts to their balances.
 	balances: BTreeMap<AccountId, Balance>,
 }
 
-/*
-	TODO:
-	The generic types need to satisfy certain traits in order to be used in the functions below.
-		- AccountId: Ord
-		- Balance: Zero + CheckedSub + CheckedAdd + Copy
-
-	You could figure these traits out yourself by letting the compiler tell you what you're missing.
-
-	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
-*/
-
-impl Pallet {
+impl<AccountId, Balance> Pallet<AccountId, Balance>
+where
+	AccountId: Ord + Clone,
+	Balance: Zero + CheckedSub + CheckedAdd + Copy,
+{
 	/// Create a new instance of the balances module.
 	pub fn new() -> Self {
 		Self { balances: BTreeMap::new() }
@@ -46,7 +28,7 @@ impl Pallet {
 	/// Get the balance of an account `who`.
 	/// If the account has no stored balance, we return zero.
 	pub fn balance(&self, who: &AccountId) -> Balance {
-		*self.balances.get(who).unwrap_or(&0)
+		*self.balances.get(who).unwrap_or(&Balance::zero())
 	}
 
 	/// Transfer `amount` from one account to another.
@@ -61,8 +43,8 @@ impl Pallet {
 		let caller_balance = self.balance(&caller);
 		let to_balance = self.balance(&to);
 
-		let new_caller_balance = caller_balance.checked_sub(amount).ok_or("Not enough funds.")?;
-		let new_to_balance = to_balance.checked_add(amount).ok_or("Overflow")?;
+		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
+		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;
 
 		self.balances.insert(caller, new_caller_balance);
 		self.balances.insert(to, new_to_balance);
@@ -75,11 +57,7 @@ impl Pallet {
 mod tests {
 	#[test]
 	fn init_balances() {
-		/*
-			TODO:
-			When creating an instance of `Pallet`, you should explicitly define the types you use.
-		*/
-		let mut balances = super::Pallet::new();
+		let mut balances = super::Pallet::<String, u128>::new();
 
 		assert_eq!(balances.balance(&"alice".to_string()), 0);
 		balances.set_balance(&"alice".to_string(), 100);
@@ -89,11 +67,7 @@ mod tests {
 
 	#[test]
 	fn transfer_balance() {
-		/*
-			TODO:
-			When creating an instance of `Pallet`, you should explicitly define the types you use.
-		*/
-		let mut balances = super::Pallet::new();
+		let mut balances = super::Pallet::<String, u128>::new();
 
 		assert_eq!(
 			balances.transfer("alice".to_string(), "bob".to_string(), 51),
diff --git a/src/main.rs b/src/main.rs
index 1cfc058c..b314856b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,9 +5,8 @@ mod system;
 // Modules are configured for these types directly, and they satisfy all of our
 // trait requirements.
 mod types {
-	/*
-		TODO: Move your type definitions for `AccountId` and `Balance` here.
-	*/
+	pub type AccountId = String;
+	pub type Balance = u128;
 }
 
 // This is our main Runtime.
@@ -15,8 +14,7 @@ mod types {
 #[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet,
-	/* TODO: Use your type definitions for your new generic `balances::Pallet`. */
-	balances: balances::Pallet,
+	balances: balances::Pallet<types::AccountId, types::Balance>,
 }
 
 impl Runtime {

Make System Pallet Generic

Now that you have some practice with the Balances Pallet, let's do the same task for the System Pallet.

  1. In this case we need to make System generic over AccountId, BlockNumber, and Nonce.

  2. You will also need to figure out the trait constraints needed for these types to be compatible with the logic you have previously written. The compiler is your friend here to help you navigate everything.

  3. Update your tests.

  4. Finally move your type definitions to your main.rs file and update your Runtime.

Make sure everything compiles and all tests pass after this step.

If you need help, I recommend to look at your Balances Pallet rather than the solution for this step. All of the patterns are the same as before, so it is better that you start to connect the dots yourself rather than relying on the solution.

If you struggled here, it is a good opportunity to take a pause and re-review generic types from other examples across the Rust ecosystem.

mod balances;
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;
	/* TODO: Move your type definitions for `BlockNumber` and `Nonce` here. */
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	/* TODO: Use your type definitions for your new generic `system::Pallet`. */
	system: system::Pallet,
	balances: balances::Pallet<types::AccountId, 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);
}
#![allow(unused)]
fn main() {
use std::collections::BTreeMap;

type AccountId = String;
type BlockNumber = u32;
type Nonce = u32;

/*
	TODO:
	Update the `Pallet` struct to be generic over the `AccountId`, `BlockNumber`, and `Nonce` type.
	You won't need the type definitions above after you are done.
	Types will now be defined in `main.rs`. See the TODOs there.
*/

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet {
	/// The current block number.
	block_number: BlockNumber,
	/// A map from an account to their nonce.
	nonce: BTreeMap<AccountId, Nonce>,
}

/*
	TODO:
	The generic types need to satisfy certain traits in order to be used in the functions below.
	See if you can figure them out yourself.

	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
*/

impl Pallet {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: 0, nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> BlockNumber {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += 1;
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &AccountId) {
		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
		let new_nonce = nonce + 1;
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		/*
			TODO:
			When creating an instance of `Pallet`, you should explicitly define the types you use.
		*/
		let mut system = super::Pallet::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
mod balances;
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;
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet<types::AccountId, types::BlockNumber, types::Nonce>,
	balances: balances::Pallet<types::AccountId, 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);
}
#![allow(unused)]
fn main() {
use core::ops::AddAssign;
use num::traits::{One, Zero};
use std::collections::BTreeMap;

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet<AccountId, BlockNumber, Nonce> {
	/// The current block number.
	block_number: BlockNumber,
	/// A map from an account to their nonce.
	nonce: BTreeMap<AccountId, Nonce>,
}

impl<AccountId, BlockNumber, Nonce> Pallet<AccountId, BlockNumber, Nonce>
where
	AccountId: Ord + Clone,
	BlockNumber: Zero + One + AddAssign + Copy,
	Nonce: Zero + One + Copy,
{
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: BlockNumber::zero(), nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> BlockNumber {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += BlockNumber::one();
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &AccountId) {
		let nonce: Nonce = *self.nonce.get(who).unwrap_or(&Nonce::zero());
		let new_nonce = nonce + Nonce::one();
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	#[test]
	fn init_system() {
		let mut system = super::Pallet::<String, u32, u32>::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
diff --git a/src/main.rs b/src/main.rs
index b314856b..df9057af 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,12 +7,14 @@ mod system;
 mod types {
 	pub type AccountId = String;
 	pub type Balance = u128;
+	/* TODO: Move your type definitions for `BlockNumber` and `Nonce` here. */
 }
 
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 #[derive(Debug)]
 pub struct Runtime {
+	/* TODO: Use your type definitions for your new generic `system::Pallet`. */
 	system: system::Pallet,
 	balances: balances::Pallet<types::AccountId, types::Balance>,
 }
diff --git a/src/system.rs b/src/system.rs
index b63ab24e..a50b5e77 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -4,6 +4,13 @@ type AccountId = String;
 type BlockNumber = u32;
 type Nonce = u32;
 
+/*
+	TODO:
+	Update the `Pallet` struct to be generic over the `AccountId`, `BlockNumber`, and `Nonce` type.
+	You won't need the type definitions above after you are done.
+	Types will now be defined in `main.rs`. See the TODOs there.
+*/
+
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
@@ -14,6 +21,14 @@ pub struct Pallet {
 	nonce: BTreeMap<AccountId, Nonce>,
 }
 
+/*
+	TODO:
+	The generic types need to satisfy certain traits in order to be used in the functions below.
+	See if you can figure them out yourself.
+
+	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
+*/
+
 impl Pallet {
 	/// Create a new instance of the System Pallet.
 	pub fn new() -> Self {
@@ -44,6 +59,10 @@ impl Pallet {
 mod test {
 	#[test]
 	fn init_system() {
+		/*
+			TODO:
+			When creating an instance of `Pallet`, you should explicitly define the types you use.
+		*/
 		let mut system = super::Pallet::new();
 		system.inc_block_number();
 		system.inc_nonce(&"alice".to_string());
diff --git a/src/main.rs b/src/main.rs
index df9057af..8d30b1be 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,15 +7,15 @@ mod system;
 mod types {
 	pub type AccountId = String;
 	pub type Balance = u128;
-	/* TODO: Move your type definitions for `BlockNumber` and `Nonce` here. */
+	pub type BlockNumber = u32;
+	pub type Nonce = u32;
 }
 
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 #[derive(Debug)]
 pub struct Runtime {
-	/* TODO: Use your type definitions for your new generic `system::Pallet`. */
-	system: system::Pallet,
+	system: system::Pallet<types::AccountId, types::BlockNumber, types::Nonce>,
 	balances: balances::Pallet<types::AccountId, types::Balance>,
 }
 
diff --git a/src/system.rs b/src/system.rs
index a50b5e77..c7563896 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -1,38 +1,26 @@
+use core::ops::AddAssign;
+use num::traits::{One, Zero};
 use std::collections::BTreeMap;
 
-type AccountId = String;
-type BlockNumber = u32;
-type Nonce = u32;
-
-/*
-	TODO:
-	Update the `Pallet` struct to be generic over the `AccountId`, `BlockNumber`, and `Nonce` type.
-	You won't need the type definitions above after you are done.
-	Types will now be defined in `main.rs`. See the TODOs there.
-*/
-
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
-pub struct Pallet {
+pub struct Pallet<AccountId, BlockNumber, Nonce> {
 	/// The current block number.
 	block_number: BlockNumber,
 	/// A map from an account to their nonce.
 	nonce: BTreeMap<AccountId, Nonce>,
 }
 
-/*
-	TODO:
-	The generic types need to satisfy certain traits in order to be used in the functions below.
-	See if you can figure them out yourself.
-
-	NOTE: You might need to adjust some of the functions below to satisfy the borrow checker.
-*/
-
-impl Pallet {
+impl<AccountId, BlockNumber, Nonce> Pallet<AccountId, BlockNumber, Nonce>
+where
+	AccountId: Ord + Clone,
+	BlockNumber: Zero + One + AddAssign + Copy,
+	Nonce: Zero + One + Copy,
+{
 	/// Create a new instance of the System Pallet.
 	pub fn new() -> Self {
-		Self { block_number: 0, nonce: BTreeMap::new() }
+		Self { block_number: BlockNumber::zero(), nonce: BTreeMap::new() }
 	}
 
 	/// Get the current block number.
@@ -43,14 +31,14 @@ impl Pallet {
 	// This function can be used to increment the block number.
 	// Increases the block number by one.
 	pub fn inc_block_number(&mut self) {
-		self.block_number += 1;
+		self.block_number += BlockNumber::one();
 	}
 
 	// Increment the nonce of an account. This helps us keep track of how many transactions each
 	// account has made.
 	pub fn inc_nonce(&mut self, who: &AccountId) {
-		let nonce: u32 = *self.nonce.get(who).unwrap_or(&0);
-		let new_nonce = nonce + 1;
+		let nonce: Nonce = *self.nonce.get(who).unwrap_or(&Nonce::zero());
+		let new_nonce = nonce + Nonce::one();
 		self.nonce.insert(who.clone(), new_nonce);
 	}
 }
@@ -59,11 +47,7 @@ impl Pallet {
 mod test {
 	#[test]
 	fn init_system() {
-		/*
-			TODO:
-			When creating an instance of `Pallet`, you should explicitly define the types you use.
-		*/
-		let mut system = super::Pallet::new();
+		let mut system = super::Pallet::<String, u32, u32>::new();
 		system.inc_block_number();
 		system.inc_nonce(&"alice".to_string());
 

Make System Configurable

We have one more step to take to make our Runtime as generic and configurable as possible.

To do it, we will need to take advantage of traits.

Custom Traits

We have already used traits provided to us in order to make our types generic.

Let's take a quick look at how you can define a custom trait:

#![allow(unused)]
fn main() {
pub trait Config {}
}

Traits can contain within it two things:

  1. functions which must be implemented by the type
  2. associated types

Custom Functions

The more obvious use of traits is to define custom functions

Let's say we want to expose a function which returns the name of something.

You could a trait GetName:

#![allow(unused)]
fn main() {
pub trait GetName {
	fn name() -> String;
}
}

Then you could implement this trait for any object.

#![allow(unused)]
fn main() {
struct Shawn;
impl GetName for Shawn {
	fn name() -> String {
		return "shawn".to_string();
	}
}
}

And then call that function on the object which implements it.

fn main() {
	println!("{}", Shawn::name());
}

We won't actually use this feature of traits in our simple blockchain, but there are plenty of use cases for this when developing more complex blockchain systems.

Associated Types

The other thing you can do with traits is define Associated Types.

This is covered in chapter 19 of the Rust Book under "Advance Traits".

Let's learn this concept by first looking at the problem we are trying to solve.

So far our simple blockchain code looks perfectly fine with generic types. However, let's imagine that our blockchain becomes more and more complex, requiring more and more generic types.

For example:

#![allow(unused)]
fn main() {
pub struct Pallet<AccountId, BlockNumber, BlockLength, BlockWeight, Hash, Nonce, Runtime, Version, ...> {
	// a bunch of stuff
}
}

Imagine every time you wanted to instantiate this struct, you would need to fill out each and every one of those types. Well systems do get this complex, and more, and the ability to abstract these types one level further can really simplify your code and make it much more readable.

For this we will use a trait with a bunch of associated types:

#![allow(unused)]
fn main() {
pub trait Config {
	type AccountId: Ord;
	type BlockNumber: Zero + One + AddAssign + Copy;
	type Nonce: Zero + One + Copy;
	// and more if needed
}
}

Then we can define our generic type using a single generic parameter!

#![allow(unused)]
fn main() {
pub struct Pallet<T: Config> {
	block_number: T::BlockNumber,
	nonce: BTreeMap<T::AccountId, T::Nonce>,
}
}

and implement functions using:

#![allow(unused)]
fn main() {
impl<T: Config> Pallet<T> {
	// functions using types from T here
}
}

Let's try to understand this syntax real quick.

  1. There is a generic type T. T has no meaningful name because it represents a bunch of stuff, and this is the convention most commonly used in Rust.
  2. T is required to implement the trait Config, which we previously defined.
  3. Because T implements Config, and Config has the associated types AccountId, BlockNumber, and Nonce, we can access those types like so:
    • T::AccountId
    • T::BlockNumber
    • T::Nonce

There is no meaningful difference between what we had before with 3 generic parameters, and a single generic parameter represented by a Config trait, but it certainly makes everything more scalable, easy to read, and easy to configure.

In this context, we call the trait Config because it is used to configure all the types for our Pallet.

Implementing the Config Trait

Let's round this out with showing how you can actually implement and use the Config trait.

Just like before, we need some object which will implement this trait. In our case, we can use the Runtime struct itself.

#![allow(unused)]
fn main() {
impl system::Config for Runtime {
	type AccountId = String;
	type BlockNumber = u32;
	type Nonce = u32;
}
}

Then, when defining the system::Pallet within the Runtime, we can use the following syntax:

#![allow(unused)]
fn main() {
pub struct Runtime {
	system: system::Pallet<Self>,
}
}

Here we are basically saying that Pallet will use Runtime as its generic type, but this is defined within the Runtime, so we refer to it as Self.

Make Your System Configurable

Phew. That was a lot.

Let's practice all you have learned to create Config trait for your System Pallet, and then configure the pallet for the Runtime in main.rs.

  1. Define the Config trait which will have your 3 associated types AccountId, BlockNumber, and Nonce.
  2. Make sure these types have their trait constraints defined in Config.
  3. Update your struct Pallet to use T: Config and reference your types using the T:: syntax.
  4. Update all of your functions to use the T:: syntax.
  5. Update your test, creating a struct TestConfig, and implementing Config for it, and using it to instantiate your Pallet struct.
  6. Go to your main.rs file, and implement system::Config for the Runtime struct.
  7. Update your Runtime definition to instantiate system::Pallet with Self.

Again, this is a big step for new Rust developers, and a common place that people can get very confused.

You will have the opportunity to do this whole process again for the Balances Pallet, so don't be afraid to peek at the solution this time around if you cannot get your code working.

Really take time to understand this step, what is happening, and what all of this syntax means to Rust.

Remember that Rust is a language which is completely type safe, so end of the day, all of these generic types and configurations need to make sense to the Rust compiler.

mod balances;
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:
	Implement the `system::Config` trait you created on your `Runtime`.
	Use `Self` to satisfy the generic parameter required for `system::Pallet`.
*/

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet<types::AccountId, types::BlockNumber, types::Nonce>,
	balances: balances::Pallet<types::AccountId, 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);
}
#![allow(unused)]
fn main() {
use core::ops::AddAssign;
use num::traits::{One, Zero};
use std::collections::BTreeMap;

/*
	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
*/

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet<AccountId, BlockNumber, Nonce> {
	/// The current block number.
	block_number: BlockNumber,
	/// A map from an account to their nonce.
	nonce: BTreeMap<AccountId, Nonce>,
}

/*
	TODO: Update all of these functions to use your new configuration trait.
*/

impl<AccountId, BlockNumber, Nonce> Pallet<AccountId, BlockNumber, Nonce>
where
	AccountId: Ord + Clone,
	BlockNumber: Zero + One + AddAssign + Copy,
	Nonce: Zero + One + Copy,
{
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: BlockNumber::zero(), nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> BlockNumber {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += BlockNumber::one();
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &AccountId) {
		let nonce: Nonce = *self.nonce.get(who).unwrap_or(&Nonce::zero());
		let new_nonce = nonce + Nonce::one();
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	/*
		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
		Use this struct to instantiate your `Pallet`.
	*/

	#[test]
	fn init_system() {
		let mut system = super::Pallet::<String, u32, u32>::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
mod balances;
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;
}

// 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<types::AccountId, types::Balance>,
}

impl system::Config for Runtime {
	type AccountId = types::AccountId;
	type BlockNumber = types::BlockNumber;
	type Nonce = types::Nonce;
}

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);
}
#![allow(unused)]
fn main() {
use core::ops::AddAssign;
use num::traits::{One, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the System Pallet.
/// This controls the common types used throughout our state machine.
pub trait Config {
	/// A type which can identify an account in our state machine.
	/// On a real blockchain, you would want this to be a cryptographic public key.
	type AccountId: Ord + Clone;
	/// A type which can be used to represent the current block number.
	/// Usually a basic unsigned integer.
	type BlockNumber: Zero + One + AddAssign + Copy;
	/// A type which can be used to keep track of the number of transactions from each account.
	/// Usually a basic unsigned integer.
	type Nonce: Zero + One + Copy;
}

/// This is the System Pallet.
/// It handles low level state needed for your blockchain.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// The current block number.
	block_number: T::BlockNumber,
	/// A map from an account to their nonce.
	nonce: BTreeMap<T::AccountId, T::Nonce>,
}

/// The System Pallet is a low level system which is not really meant to be exposed to the outside
/// world. Instead, these functions are used by your low level blockchain systems.
impl<T: Config> Pallet<T> {
	/// Create a new instance of the System Pallet.
	pub fn new() -> Self {
		Self { block_number: T::BlockNumber::zero(), nonce: BTreeMap::new() }
	}

	/// Get the current block number.
	pub fn block_number(&self) -> T::BlockNumber {
		self.block_number
	}

	// This function can be used to increment the block number.
	// Increases the block number by one.
	pub fn inc_block_number(&mut self) {
		self.block_number += T::BlockNumber::one();
	}

	// Increment the nonce of an account. This helps us keep track of how many transactions each
	// account has made.
	pub fn inc_nonce(&mut self, who: &T::AccountId) {
		let nonce: T::Nonce = *self.nonce.get(who).unwrap_or(&T::Nonce::zero());
		let new_nonce = nonce + T::Nonce::one();
		self.nonce.insert(who.clone(), new_nonce);
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;
	impl super::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn init_system() {
		let mut system = super::Pallet::<TestConfig>::new();
		system.inc_block_number();
		system.inc_nonce(&"alice".to_string());

		assert_eq!(system.block_number(), 1);
		assert_eq!(system.nonce.get("alice"), Some(&1));
		assert_eq!(system.nonce.get("bob"), None);
	}
}
}
diff --git a/src/main.rs b/src/main.rs
index 8d30b1be..d681065c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,6 +11,12 @@ mod types {
 	pub type Nonce = u32;
 }
 
+/*
+	TODO:
+	Implement the `system::Config` trait you created on your `Runtime`.
+	Use `Self` to satisfy the generic parameter required for `system::Pallet`.
+*/
+
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 #[derive(Debug)]
diff --git a/src/system.rs b/src/system.rs
index c7563896..1f061b1d 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -2,6 +2,11 @@ use core::ops::AddAssign;
 use num::traits::{One, Zero};
 use std::collections::BTreeMap;
 
+/*
+	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
+	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
+*/
+
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
@@ -12,6 +17,10 @@ pub struct Pallet<AccountId, BlockNumber, Nonce> {
 	nonce: BTreeMap<AccountId, Nonce>,
 }
 
+/*
+	TODO: Update all of these functions to use your new configuration trait.
+*/
+
 impl<AccountId, BlockNumber, Nonce> Pallet<AccountId, BlockNumber, Nonce>
 where
 	AccountId: Ord + Clone,
@@ -45,6 +54,11 @@ where
 
 #[cfg(test)]
 mod test {
+	/*
+		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
+		Use this struct to instantiate your `Pallet`.
+	*/
+
 	#[test]
 	fn init_system() {
 		let mut system = super::Pallet::<String, u32, u32>::new();
diff --git a/src/main.rs b/src/main.rs
index d681065c..40dc8ac5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,20 +11,20 @@ mod types {
 	pub type Nonce = u32;
 }
 
-/*
-	TODO:
-	Implement the `system::Config` trait you created on your `Runtime`.
-	Use `Self` to satisfy the generic parameter required for `system::Pallet`.
-*/
-
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
 #[derive(Debug)]
 pub struct Runtime {
-	system: system::Pallet<types::AccountId, types::BlockNumber, types::Nonce>,
+	system: system::Pallet<Self>,
 	balances: balances::Pallet<types::AccountId, types::Balance>,
 }
 
+impl system::Config for Runtime {
+	type AccountId = types::AccountId;
+	type BlockNumber = types::BlockNumber;
+	type Nonce = types::Nonce;
+}
+
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
 	fn new() -> Self {
diff --git a/src/system.rs b/src/system.rs
index 1f061b1d..8bef9918 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -2,66 +2,70 @@ use core::ops::AddAssign;
 use num::traits::{One, Zero};
 use std::collections::BTreeMap;
 
-/*
-	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
-	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
-*/
+/// The configuration trait for the System Pallet.
+/// This controls the common types used throughout our state machine.
+pub trait Config {
+	/// A type which can identify an account in our state machine.
+	/// On a real blockchain, you would want this to be a cryptographic public key.
+	type AccountId: Ord + Clone;
+	/// A type which can be used to represent the current block number.
+	/// Usually a basic unsigned integer.
+	type BlockNumber: Zero + One + AddAssign + Copy;
+	/// A type which can be used to keep track of the number of transactions from each account.
+	/// Usually a basic unsigned integer.
+	type Nonce: Zero + One + Copy;
+}
 
 /// This is the System Pallet.
 /// It handles low level state needed for your blockchain.
 #[derive(Debug)]
-pub struct Pallet<AccountId, BlockNumber, Nonce> {
+pub struct Pallet<T: Config> {
 	/// The current block number.
-	block_number: BlockNumber,
+	block_number: T::BlockNumber,
 	/// A map from an account to their nonce.
-	nonce: BTreeMap<AccountId, Nonce>,
+	nonce: BTreeMap<T::AccountId, T::Nonce>,
 }
 
-/*
-	TODO: Update all of these functions to use your new configuration trait.
-*/
-
-impl<AccountId, BlockNumber, Nonce> Pallet<AccountId, BlockNumber, Nonce>
-where
-	AccountId: Ord + Clone,
-	BlockNumber: Zero + One + AddAssign + Copy,
-	Nonce: Zero + One + Copy,
-{
+/// The System Pallet is a low level system which is not really meant to be exposed to the outside
+/// world. Instead, these functions are used by your low level blockchain systems.
+impl<T: Config> Pallet<T> {
 	/// Create a new instance of the System Pallet.
 	pub fn new() -> Self {
-		Self { block_number: BlockNumber::zero(), nonce: BTreeMap::new() }
+		Self { block_number: T::BlockNumber::zero(), nonce: BTreeMap::new() }
 	}
 
 	/// Get the current block number.
-	pub fn block_number(&self) -> BlockNumber {
+	pub fn block_number(&self) -> T::BlockNumber {
 		self.block_number
 	}
 
 	// This function can be used to increment the block number.
 	// Increases the block number by one.
 	pub fn inc_block_number(&mut self) {
-		self.block_number += BlockNumber::one();
+		self.block_number += T::BlockNumber::one();
 	}
 
 	// Increment the nonce of an account. This helps us keep track of how many transactions each
 	// account has made.
-	pub fn inc_nonce(&mut self, who: &AccountId) {
-		let nonce: Nonce = *self.nonce.get(who).unwrap_or(&Nonce::zero());
-		let new_nonce = nonce + Nonce::one();
+	pub fn inc_nonce(&mut self, who: &T::AccountId) {
+		let nonce: T::Nonce = *self.nonce.get(who).unwrap_or(&T::Nonce::zero());
+		let new_nonce = nonce + T::Nonce::one();
 		self.nonce.insert(who.clone(), new_nonce);
 	}
 }
 
 #[cfg(test)]
 mod test {
-	/*
-		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
-		Use this struct to instantiate your `Pallet`.
-	*/
+	struct TestConfig;
+	impl super::Config for TestConfig {
+		type AccountId = String;
+		type BlockNumber = u32;
+		type Nonce = u32;
+	}
 
 	#[test]
 	fn init_system() {
-		let mut system = super::Pallet::<String, u32, u32>::new();
+		let mut system = super::Pallet::<TestConfig>::new();
 		system.inc_block_number();
 		system.inc_nonce(&"alice".to_string());
 

Make Balances Configurable

There is nothing new to learn in this step, just repeating the same process we did for our System Pallet for the Balances pallet.

In this case, our Config trait will only have two associated types: AccountId and Balance.

For this step, try to avoid looking at the solution, and instead refer to the changes you made to get the System Pallet configurable.

  1. Define the Config trait which will have your associated types.
  2. Make sure these types have their trait constraints defined in Config.
  3. Update your struct Pallet to use T: Config and reference your types using the T:: syntax.
  4. Update all of your functions to use the T:: syntax.
  5. Update your test, creating a struct TestConfig, and implementing Config for it, and using it to instantiate your Pallet struct.
  6. Go to your main.rs file, and implement balances::Config for the Runtime struct.
  7. Update your Runtime definition to instantiate balances::Pallet with Self.

If you have made it this far, I think it is fair to say you have made it over the hardest part of this tutorial, and the hardest part of using Rust in Substrate.

It is important to take a step back and remember that while these abstractions make your code a bit more complicated to fully understand, it also makes your code extremely flexible, at zero cost to performance and safety thanks to the Rust compiler.

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/*
	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
*/

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<AccountId, Balance> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<AccountId, Balance>,
}

/*
	TODO: Update all of these functions to use your new configuration trait.
*/

impl<AccountId, Balance> Pallet<AccountId, Balance>
where
	AccountId: Ord + Clone,
	Balance: Zero + CheckedSub + CheckedAdd + Copy,
{
	/// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &AccountId) -> Balance {
		*self.balances.get(who).unwrap_or(&Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: AccountId,
		to: AccountId,
		amount: Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	/*
		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
		Use this struct to instantiate your `Pallet`.
	*/

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<String, u128>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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;
}

// 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<types::AccountId, types::Balance>,
}

impl system::Config for Runtime {
	type AccountId = types::AccountId;
	type BlockNumber = types::BlockNumber;
	type Nonce = types::Nonce;
}

/*
	TODO:
	Implement the `balances::Config` trait you created on your `Runtime`.
	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
*/

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);
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config {
	/// A type which can identify an account in our state machine.
	/// On a real blockchain, you would want this to be a cryptographic public key.
	type AccountId: Ord + Clone;
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;
	impl super::Config for TestConfig {
		type AccountId = String;
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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;
}

// 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 AccountId = types::AccountId;
	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/balances.rs b/src/balances.rs
index e333e0d9..9f5c4531 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,6 +1,11 @@
 use num::traits::{CheckedAdd, CheckedSub, Zero};
 use std::collections::BTreeMap;
 
+/*
+	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
+	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
+*/
+
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
@@ -10,6 +15,10 @@ pub struct Pallet<AccountId, Balance> {
 	balances: BTreeMap<AccountId, Balance>,
 }
 
+/*
+	TODO: Update all of these functions to use your new configuration trait.
+*/
+
 impl<AccountId, Balance> Pallet<AccountId, Balance>
 where
 	AccountId: Ord + Clone,
@@ -55,6 +64,11 @@ where
 
 #[cfg(test)]
 mod tests {
+	/*
+		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
+		Use this struct to instantiate your `Pallet`.
+	*/
+
 	#[test]
 	fn init_balances() {
 		let mut balances = super::Pallet::<String, u128>::new();
diff --git a/src/main.rs b/src/main.rs
index 40dc8ac5..343797ef 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,6 +25,12 @@ impl system::Config for Runtime {
 	type Nonce = types::Nonce;
 }
 
+/*
+	TODO:
+	Implement the `balances::Config` trait you created on your `Runtime`.
+	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
+*/
+
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
 	fn new() -> Self {
diff --git a/src/balances.rs b/src/balances.rs
index 9f5c4531..43b49262 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -1,43 +1,41 @@
 use num::traits::{CheckedAdd, CheckedSub, Zero};
 use std::collections::BTreeMap;
 
-/*
-	TODO: Combine all generic types and their trait bounds into a single `pub trait Config`.
-	When you are done, your `Pallet` can simply be defined with `Pallet<T: Config>`.
-*/
+/// The configuration trait for the Balances Module.
+/// Contains the basic types needed for handling balances.
+pub trait Config {
+	/// A type which can identify an account in our state machine.
+	/// On a real blockchain, you would want this to be a cryptographic public key.
+	type AccountId: Ord + Clone;
+	/// A type which can represent the balance of an account.
+	/// Usually this is a large unsigned integer.
+	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
+}
 
 /// This is the Balances Module.
 /// It is a simple module which keeps track of how much balance each account has in this state
 /// machine.
 #[derive(Debug)]
-pub struct Pallet<AccountId, Balance> {
+pub struct Pallet<T: Config> {
 	// A simple storage mapping from accounts to their balances.
-	balances: BTreeMap<AccountId, Balance>,
+	balances: BTreeMap<T::AccountId, T::Balance>,
 }
 
-/*
-	TODO: Update all of these functions to use your new configuration trait.
-*/
-
-impl<AccountId, Balance> Pallet<AccountId, Balance>
-where
-	AccountId: Ord + Clone,
-	Balance: Zero + CheckedSub + CheckedAdd + Copy,
-{
-	/// Create a new instance of the balances module.
+impl<T: Config> Pallet<T> {
+	// Create a new instance of the balances module.
 	pub fn new() -> Self {
 		Self { balances: BTreeMap::new() }
 	}
 
 	/// Set the balance of an account `who` to some `amount`.
-	pub fn set_balance(&mut self, who: &AccountId, amount: Balance) {
+	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
 		self.balances.insert(who.clone(), amount);
 	}
 
 	/// Get the balance of an account `who`.
 	/// If the account has no stored balance, we return zero.
-	pub fn balance(&self, who: &AccountId) -> Balance {
-		*self.balances.get(who).unwrap_or(&Balance::zero())
+	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
+		*self.balances.get(who).unwrap_or(&T::Balance::zero())
 	}
 
 	/// Transfer `amount` from one account to another.
@@ -45,9 +43,9 @@ where
 	/// and that no mathematical overflows occur.
 	pub fn transfer(
 		&mut self,
-		caller: AccountId,
-		to: AccountId,
-		amount: Balance,
+		caller: T::AccountId,
+		to: T::AccountId,
+		amount: T::Balance,
 	) -> Result<(), &'static str> {
 		let caller_balance = self.balance(&caller);
 		let to_balance = self.balance(&to);
@@ -64,14 +62,15 @@ where
 
 #[cfg(test)]
 mod tests {
-	/*
-		TODO: Create a `struct TestConfig`, and implement `super::Config` on it with concrete types.
-		Use this struct to instantiate your `Pallet`.
-	*/
+	struct TestConfig;
+	impl super::Config for TestConfig {
+		type AccountId = String;
+		type Balance = u128;
+	}
 
 	#[test]
 	fn init_balances() {
-		let mut balances = super::Pallet::<String, u128>::new();
+		let mut balances = super::Pallet::<TestConfig>::new();
 
 		assert_eq!(balances.balance(&"alice".to_string()), 0);
 		balances.set_balance(&"alice".to_string(), 100);
@@ -81,7 +80,7 @@ mod tests {
 
 	#[test]
 	fn transfer_balance() {
-		let mut balances = super::Pallet::<String, u128>::new();
+		let mut balances = super::Pallet::<TestConfig>::new();
 
 		assert_eq!(
 			balances.transfer("alice".to_string(), "bob".to_string(), 51),
diff --git a/src/main.rs b/src/main.rs
index 343797ef..fe677ae7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@ mod types {
 #[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet<Self>,
-	balances: balances::Pallet<types::AccountId, types::Balance>,
+	balances: balances::Pallet<Self>,
 }
 
 impl system::Config for Runtime {
@@ -25,11 +25,10 @@ impl system::Config for Runtime {
 	type Nonce = types::Nonce;
 }
 
-/*
-	TODO:
-	Implement the `balances::Config` trait you created on your `Runtime`.
-	Use `Self` to satisfy the generic parameter required for `balances::Pallet`.
-*/
+impl balances::Config for Runtime {
+	type AccountId = types::AccountId;
+	type Balance = types::Balance;
+}
 
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.

Tight Coupling

You might have noticed some redundancy when making our pallets generic and configurable. Both pallets defined an AccountId type, and technically we could define their concrete type differently!

We wouldn't want this on a real production blockchain. Instead, we would want to define common types in a single spot, and use that everywhere.

Trait Inheritance

Rust has the ability for traits to inherit from one another. That is, that for you to implement some trait, you also need to implement all traits that it inherits.

Let's look at some examples.

Trait Functions

We can extend our previous example to show what trait inheritance does with functions

#![allow(unused)]
fn main() {
pub trait GetName {
	// returns a string representing the object's name
	fn name() -> String;
}

pub trait SayName: GetName {
	// will print the name from `name()` to console
	fn say_name() {
		println!("{}", Self::name());
	}
}
}

Note how in the definition of trait SayName, we reference GetName after a colon. This SayName, your object must also implement GetName. Note that we could even program a "default" implementation of get_name by using the Self::name() function.

So when we implement these traits, it looks like:

#![allow(unused)]
fn main() {
struct Shawn;
impl GetName for Shawn {
	fn name() -> String {
		return "shawn".to_string();
	}
}

impl SayName for Shawn {}
}

We could choose to implement our own version of the SayName function, for example like:

#![allow(unused)]
fn main() {
impl SayName for Shawn {
	fn say_name() {
		println!("My name is {}!", Self::name());
	}
}
}

But we don't have to do this. What we do have to do is make sure that GetName is implemented for Shawn or you wont be able to use the SayName trait. Again, we won't be using this in our tutorial, but it is nice to see examples of how this can be used.

Associated Types

Rather than redefining type AccountId in each Pallet that needs it, what if we just defined it in system::Config, and inherit that type in other Pallet configs?

Let's see what that would look like:

#![allow(unused)]
fn main() {
pub trait Config: crate::system::Config {
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}
}

Here you can see our balances::Config trait is inheriting from our crate::system::Config trait. This means that all types defined by system::Config, including the AccountId, is accessible through the balances::Config trait. Because of this, we do not need to redefine the AccountId type in balances::Config.

In the Polkadot SDK ecosystem, we call this "tight coupling" because a runtime which contains the Balances Pallet must also contain the System Pallet. In a sense these two pallets are tightly coupled to one another. In fact, with Substrate, all pallets are tightly coupled to the System Pallet, because the System Pallet provides all the meta-types for your blockchain system.

Tightly Couple Balances To System

Let's remove the redundant AccountId definition from the Balances Pallet Config.

  1. Inherit the crate::system::Config trait in the balances::Config trait.
  2. Remove the AccountId type from your balances::Config definition.
  3. Implement crate::system::Config for TestConfig.
  4. In main.rs, simply remove type AccountId from balances::Config.
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
/*
	TODO:
	Tightly couple balances to the system pallet by inheriting the `system::Config` trait.
	After this, you won't need the `AccountId` type redefined here.
*/
pub trait Config {
	/// A type which can identify an account in our state machine.
	/// On a real blockchain, you would want this to be a cryptographic public key.
	type AccountId: Ord + Clone;
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	/* TODO: Implement `crate::system::Config` for `TestConfig` to make your tests work again. */

	impl super::Config for TestConfig {
		type AccountId = String;
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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;
}

// 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 {
	/* TODO: After inheriting from the `system::Config` trait, you won't need `AccountId` here. */
	type AccountId = types::AccountId;
	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);
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
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;
}

// 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/balances.rs b/src/balances.rs
index 43b49262..25256ba5 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -3,6 +3,11 @@ use std::collections::BTreeMap;
 
 /// The configuration trait for the Balances Module.
 /// Contains the basic types needed for handling balances.
+/*
+	TODO:
+	Tightly couple balances to the system pallet by inheriting the `system::Config` trait.
+	After this, you won't need the `AccountId` type redefined here.
+*/
 pub trait Config {
 	/// A type which can identify an account in our state machine.
 	/// On a real blockchain, you would want this to be a cryptographic public key.
@@ -63,6 +68,9 @@ impl<T: Config> Pallet<T> {
 #[cfg(test)]
 mod tests {
 	struct TestConfig;
+
+	/* TODO: Implement `crate::system::Config` for `TestConfig` to make your tests work again. */
+
 	impl super::Config for TestConfig {
 		type AccountId = String;
 		type Balance = u128;
diff --git a/src/main.rs b/src/main.rs
index fe677ae7..c5a98c4a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,7 @@ impl system::Config for Runtime {
 }
 
 impl balances::Config for Runtime {
+	/* TODO: After inheriting from the `system::Config` trait, you won't need `AccountId` here. */
 	type AccountId = types::AccountId;
 	type Balance = types::Balance;
 }
diff --git a/src/balances.rs b/src/balances.rs
index 25256ba5..989fa71d 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -3,15 +3,7 @@ use std::collections::BTreeMap;
 
 /// The configuration trait for the Balances Module.
 /// Contains the basic types needed for handling balances.
-/*
-	TODO:
-	Tightly couple balances to the system pallet by inheriting the `system::Config` trait.
-	After this, you won't need the `AccountId` type redefined here.
-*/
-pub trait Config {
-	/// A type which can identify an account in our state machine.
-	/// On a real blockchain, you would want this to be a cryptographic public key.
-	type AccountId: Ord + Clone;
+pub trait Config: crate::system::Config {
 	/// A type which can represent the balance of an account.
 	/// Usually this is a large unsigned integer.
 	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
@@ -69,10 +61,13 @@ impl<T: Config> Pallet<T> {
 mod tests {
 	struct TestConfig;
 
-	/* TODO: Implement `crate::system::Config` for `TestConfig` to make your tests work again. */
+	impl crate::system::Config for TestConfig {
+		type AccountId = String;
+		type BlockNumber = u32;
+		type Nonce = u32;
+	}
 
 	impl super::Config for TestConfig {
-		type AccountId = String;
 		type Balance = u128;
 	}
 
diff --git a/src/main.rs b/src/main.rs
index c5a98c4a..dd1d1f69 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,8 +26,6 @@ impl system::Config for Runtime {
 }
 
 impl balances::Config for Runtime {
-	/* TODO: After inheriting from the `system::Config` trait, you won't need `AccountId` here. */
-	type AccountId = types::AccountId;
 	type Balance = types::Balance;
 }
 

Executing Blocks and Dispatching Calls

In this next section, you will construct the core pipeline used to interact with your state machine.

We will create the block structure which contains the transactions for your state transition function, and then the function dispatch pipeline to route those transactions to the appropriate function calls.

The goal of this section is to make your existing state machine resemble a blockchain that can be extended and upgraded.

Add Our Support Module

In this step, we will introduce a support module to help bring in various types and traits that we will use to enhance our simple state machine.

This support module parallels something similar to the frame_support crate that you would find in the Polkadot SDK.

The reason the frame_support crate exists, is to allow multiple other crates use common types and trait, while avoiding cyclic dependencies, which is not allowed in Rust.

Our simple state machine will not experience this problem explicitly, since we are building everything in a single crate, but the structure of the project will still follow these best practices.

Constructing a Block

The first set of primitives provided by the support module are a set of structs that we need to construct a simple Block.

The Block

A block is basically broken up into two parts: the header and a vector of extrinsics.

You can see that we keep the Block completely generic over the Header and Extrinsic type. The exact contents and definitions of these sub-types may change, but the generic Block struct can always be used.

The Header

The block header contains metadata about the block which is used to verify that the block is valid. In our simple state machine, we only store the blocknumber in the header, but real blockchains like Polkadot have:

  • Parent Hash
  • Block Number
  • State Root
  • Extrinsics Root
  • Consensus Digests / Logs

The Extrinsic

In our simple state machine, extrinsics are synonymous with user transactions.

Thus our extrinsic type is composed of a Call (the function we will execute) and a Caller (the account that wants to execute that function).

The Polkadot SDK supports other kinds of extrinsics beyond a user transactions, which is why it is called an Extrinsic, but that is beyond the scope of this tutorial.

Dispatching Calls

The next key change we are going to make to our simple state machine is to handle function dispatching. Basically, you can imagine that there could be multiple different pallets in your system, each with different calls they want to expose.

Your runtime, acting as a single entrypoint for your whole state transition function needs to be able to route incoming calls to the appropriate functions. For this, we need the Dispatchable trait.

You will see how this is used near the end of this tutorial.

Dispatch Result

One last thing we added to the support module was a simple definition of the Result type that we want all dispatchable calls to return. This is exactly the type we already used for the fn transfer function, and allows us to return Ok(()) if everything went well, or Err("some error message") if something went wrong.

Create the Support Module

Now that you understand what is in the support module, add it to your project.

  1. Create the support.rs file:

    touch src/support.rs
    
  2. Copy and paste the content provided into your file.

  3. Import the support module at the top of your main.rs file.

  4. Finally, replace your Result<(), &'static str> with crate::support::DispatchResult in the fn transfer function in your Balances Pallet.

Introducing this new module will cause your compiler to emit lots of "never constructed" warnings. Everything should still compile, so that is okay. We will use these new types soon.

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	/* TODO: Update the function signature to return a `DispatchResult`. */
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> Result<(), &'static str> {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
/* TODO: Add the support module here. */
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;
}

// 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);
}
#![allow(unused)]
fn main() {
/// The most primitive representation of a Blockchain block.
pub struct Block<Header, Extrinsic> {
	/// The block header contains metadata about the block.
	pub header: Header,
	/// The extrinsics represent the state transitions to be executed in this block.
	pub extrinsics: Vec<Extrinsic>,
}

/// We are using an extremely simplified header which only contains the current block number.
/// On a real blockchain, you would expect to also find:
/// - parent block hash
/// - state root
/// - extrinsics root
/// - etc...
pub struct Header<BlockNumber> {
	pub block_number: BlockNumber,
}

/// This is an "extrinsic": literally an external message from outside of the blockchain.
/// This simplified version of an extrinsic tells us who is making the call, and which call they are
/// making.
pub struct Extrinsic<Caller, Call> {
	pub caller: Caller,
	pub call: Call,
}

/// The Result type for our runtime. When everything completes successfully, we return `Ok(())`,
/// otherwise return a static error message.
pub type DispatchResult = Result<(), &'static str>;

/// A trait which allows us to dispatch an incoming extrinsic to the appropriate state transition
/// function call.
pub trait Dispatch {
	/// The type used to identify the caller of the function.
	type Caller;
	/// The state transition function call the caller is trying to access.
	type Call;

	/// This function takes a `caller` and the `call` they want to make, and returns a `Result`
	/// based on the outcome of that function call.
	fn dispatch(&mut self, caller: Self::Caller, call: Self::Call) -> DispatchResult;
}
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> crate::support::DispatchResult {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
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;
}

// 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/balances.rs b/src/balances.rs
index 989fa71d..a86d8927 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -38,6 +38,7 @@ impl<T: Config> Pallet<T> {
 	/// Transfer `amount` from one account to another.
 	/// This function verifies that `from` has at least `amount` balance to transfer,
 	/// and that no mathematical overflows occur.
+	/* TODO: Update the function signature to return a `DispatchResult`. */
 	pub fn transfer(
 		&mut self,
 		caller: T::AccountId,
diff --git a/src/main.rs b/src/main.rs
index dd1d1f69..20811be3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
 mod balances;
+/* TODO: Add the support module here. */
 mod system;
 
 // These are the concrete types we will use in our simple state machine.
diff --git a/src/support.rs b/src/support.rs
new file mode 100644
index 00000000..08dc1eae
--- /dev/null
+++ b/src/support.rs
@@ -0,0 +1,42 @@
+/// The most primitive representation of a Blockchain block.
+pub struct Block<Header, Extrinsic> {
+	/// The block header contains metadata about the block.
+	pub header: Header,
+	/// The extrinsics represent the state transitions to be executed in this block.
+	pub extrinsics: Vec<Extrinsic>,
+}
+
+/// We are using an extremely simplified header which only contains the current block number.
+/// On a real blockchain, you would expect to also find:
+/// - parent block hash
+/// - state root
+/// - extrinsics root
+/// - etc...
+pub struct Header<BlockNumber> {
+	pub block_number: BlockNumber,
+}
+
+/// This is an "extrinsic": literally an external message from outside of the blockchain.
+/// This simplified version of an extrinsic tells us who is making the call, and which call they are
+/// making.
+pub struct Extrinsic<Caller, Call> {
+	pub caller: Caller,
+	pub call: Call,
+}
+
+/// The Result type for our runtime. When everything completes successfully, we return `Ok(())`,
+/// otherwise return a static error message.
+pub type DispatchResult = Result<(), &'static str>;
+
+/// A trait which allows us to dispatch an incoming extrinsic to the appropriate state transition
+/// function call.
+pub trait Dispatch {
+	/// The type used to identify the caller of the function.
+	type Caller;
+	/// The state transition function call the caller is trying to access.
+	type Call;
+
+	/// This function takes a `caller` and the `call` they want to make, and returns a `Result`
+	/// based on the outcome of that function call.
+	fn dispatch(&mut self, caller: Self::Caller, call: Self::Call) -> DispatchResult;
+}
diff --git a/src/balances.rs b/src/balances.rs
index a86d8927..74e6f43b 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -38,13 +38,12 @@ impl<T: Config> Pallet<T> {
 	/// Transfer `amount` from one account to another.
 	/// This function verifies that `from` has at least `amount` balance to transfer,
 	/// and that no mathematical overflows occur.
-	/* TODO: Update the function signature to return a `DispatchResult`. */
 	pub fn transfer(
 		&mut self,
 		caller: T::AccountId,
 		to: T::AccountId,
 		amount: T::Balance,
-	) -> Result<(), &'static str> {
+	) -> crate::support::DispatchResult {
 		let caller_balance = self.balance(&caller);
 		let to_balance = self.balance(&to);
 
diff --git a/src/main.rs b/src/main.rs
index 20811be3..597aca68 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
 mod balances;
-/* TODO: Add the support module here. */
+mod support;
 mod system;
 
 // These are the concrete types we will use in our simple state machine.

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.

  1. Using the RuntimeCall enum and the AccountId type, you can define a concrete Extrinsic type.
  2. Using the BlockNumber type, you can define a concrete Header type.
  3. Using the concrete Header and Extrinsic types, you can define a concrete Block 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.

Executing Blocks

We will now start the process to replace the simple block simulation in our main function with a proper block execution pipeline.

Execute Block

We have introduced a new function to our Runtime called fn execute_block.

The steps of this function is exactly the same as our current main function, but using the concrete Block type we defined to extract details like the expected block number and the extrinsics that we want to execute.

Iterating Over a Vector

In order to build our execute_block function, we will need to iterate over all the extrinsics in our block, and dispatch those calls. In rust, the common way to access the elements of a vector is to turn it into an iterator.

There are two functions used for turning a vector into an interator, iter and into_iter, and their difference lies in ownership:

  • iter: This method creates an iterator that borrows each element from the vector, allowing you to read the values without taking ownership. It's useful when you want to iterate over the vector while keeping it intact.

  • into_iter: This method consumes the vector, transferring ownership of each element to the iterator. It's handy when you want to move or transfer ownership of the vector's elements to another part of your code. After using into_iter, the original vector can't be used anymore, as ownership has been transferred.

In our context, we want to use into_iter(), so you will get something that looks like:

#![allow(unused)]
fn main() {
for support::Extrinsic { caller, call } in block.extrinsics.into_iter() {
	// do stuff with `caller` and `call`
}
}

Here you can see we also do a trick to separate out the fields of the Extrinsic in a single line, since ultimately we want to work with caller and call. You can of course break this process up into multiple lines if you want.

Dispatching a Call

Once we have the call and caller, what should we do with them?

This is where the Dispatch trait starts to come into play. You will see in our template, we included the shell of an unimplemented() fn dispatch. We will write this logic in the next step, but we need to already use the dispatch function in our execute_block logic.

Once we have the call and caller, we want to pass them to the dispatch logic, which you see is implemented on the Runtime.

That will look something like:

#![allow(unused)]
fn main() {
let _res = self.dispatch(caller, call).map_err(|e| eprintln!("{}", e));
}

Note that in Rust, if you want to access a function within a trait, like we do here with dispatch, you need to explicitly import that trait into your project.

We left a TODO at the top of main.rs where we ask you to import crate::support::Dispatch, which will allow you access to calling dispatch on Runtime.

Better Error Messages

Since this is a more permanent function of our project, it also makes sense to expand the message being printed when there are extrinsic errors. For example:

#![allow(unused)]
fn main() {
eprintln!(
	"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
	block.header.block_number, i, e
)
}

This allows you to see the block number, extrinsic number, and the error message whenever there is an extrinsic error. This can be very helpful when you have many blocks being imported each with potentially many extrinsics.

To get the extrinsic number i, use you chain the enumerate() function after the into_iter().

Build Your Execute Block Function

You should now have all the tools and information needed to successfully write your execute_block function.

Follow the TODOs provided by the template, and make sure to include the impl crate::support::Dispatch for Runtime that we provided for you, and that we will implement in the next steps.

Your code should still compile with some "never constructed/used" warnings.

mod balances;
mod support;
mod system;

/* TODO: Import `crate::support::Dispatch` so that you can access the `dispatch` function. */

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		/* TODO:
			- Increment the system's block number.
			- Check that the block number of the incoming block matches the current block number,
			  or return an error.
			- Iterate over the extrinsics in the block...
				- Increment the nonce of the caller.
				- Dispatch the extrinsic using the `caller` and the `call` contained in the extrinsic.
				- Handle errors from `dispatch` same as we did for individual calls: printing any
				  error and capturing the result.
				- You can extend the error message to include information like the block number and
				  extrinsic number.
		*/
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		unimplemented!();
	}
}

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;

use crate::support::Dispatch;

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected")
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		unimplemented!();
	}
}

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 5b6e139c..2d9c38bb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,6 +2,8 @@ mod balances;
 mod support;
 mod system;
 
+/* TODO: Import `crate::support::Dispatch` so that you can access the `dispatch` function. */
+
 // 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.
@@ -44,6 +46,40 @@ impl Runtime {
 	fn new() -> Self {
 		Self { system: system::Pallet::new(), balances: balances::Pallet::new() }
 	}
+
+	// Execute a block of extrinsics. Increments the block number.
+	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
+		/* TODO:
+			- Increment the system's block number.
+			- Check that the block number of the incoming block matches the current block number,
+			  or return an error.
+			- Iterate over the extrinsics in the block...
+				- Increment the nonce of the caller.
+				- Dispatch the extrinsic using the `caller` and the `call` contained in the extrinsic.
+				- Handle errors from `dispatch` same as we did for individual calls: printing any
+				  error and capturing the result.
+				- You can extend the error message to include information like the block number and
+				  extrinsic number.
+		*/
+		Ok(())
+	}
+}
+
+impl crate::support::Dispatch for Runtime {
+	type Caller = <Runtime as system::Config>::AccountId;
+	type Call = RuntimeCall;
+	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
+	//
+	// Dispatch allows us to identify which underlying module call we want to execute.
+	// Note that we extract the `caller` from the extrinsic, and use that information
+	// to determine who we are executing the call on behalf of.
+	fn dispatch(
+		&mut self,
+		caller: Self::Caller,
+		runtime_call: Self::Call,
+	) -> support::DispatchResult {
+		unimplemented!();
+	}
 }
 
 fn main() {
diff --git a/src/main.rs b/src/main.rs
index 2d9c38bb..537d6072 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,7 @@ mod balances;
 mod support;
 mod system;
 
-/* TODO: Import `crate::support::Dispatch` so that you can access the `dispatch` function. */
+use crate::support::Dispatch;
 
 // 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
@@ -49,18 +49,21 @@ impl Runtime {
 
 	// Execute a block of extrinsics. Increments the block number.
 	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
-		/* TODO:
-			- Increment the system's block number.
-			- Check that the block number of the incoming block matches the current block number,
-			  or return an error.
-			- Iterate over the extrinsics in the block...
-				- Increment the nonce of the caller.
-				- Dispatch the extrinsic using the `caller` and the `call` contained in the extrinsic.
-				- Handle errors from `dispatch` same as we did for individual calls: printing any
-				  error and capturing the result.
-				- You can extend the error message to include information like the block number and
-				  extrinsic number.
-		*/
+		self.system.inc_block_number();
+		if block.header.block_number != self.system.block_number() {
+			return Err("block number does not match what is expected")
+		}
+		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
+		// result, and emit an error message if one is emitted.
+		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
+			self.system.inc_nonce(&caller);
+			let _res = self.dispatch(caller, call).map_err(|e| {
+				eprintln!(
+					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
+					block.header.block_number, i, e
+				)
+			});
+		}
 		Ok(())
 	}
 }

Dispatching Calls

We have built our execute_block logic depending on the dispatch logic we have not implemented yet.

Let's do that.

Adding Our Calls

Dispatch logic is all about routing a user's extrinsic to the proper Pallet function. So far, the only user callable function we have created is the transfer function in the Balances Pallet.

So let's add that call to our RuntimeCall enum.

Our transfer function expects 3 inputs:

  • caller: The account calling the transfer function, and whose balance will be reduced.
  • to: The account where the funds will be sent.
  • amount: The amount of funds to transfer.

However, remember that our dispatch logic already has information about the caller which is coming from the Extrinsic in the Block. So we do not need this data again in the RuntimeCall.

In fact, every Call in our runtime should omit the caller, and know that it is being provided by our dispatch logic.

So when adding a new variant to RuntimeCall, it should look something like:

#![allow(unused)]
fn main() {
pub enum RuntimeCall {
	BalancesTransfer { to: types::AccountId, amount: types::Balance },
}
}

A user submitting an extrinsic to our state machine can use this enum variant to specify which function they want to call (transfer), and the parameters needed for that call.

Dispatch Logic

The core logic in the dispatch function is a simple match statement.

Basically, given some RuntimeCall, we need to match on the variant being provided to us, and then pass the appropriate parameters to the correct Pallet function. As mentioned before, dispatch already has access to the caller information, so the final logic is as simple as:

#![allow(unused)]
fn main() {
match runtime_call {
	RuntimeCall::BalancesTransfer { to, amount } => {
		self.balances.transfer(caller, to, amount)?;
	}
}
}

Dispatch logic really is that simple!

Note that we propagate up any errors returned by our function call with the ? operator. This is important if you want to see the error messages that we set up in the execute_block logic.

Write Your Dispatch Logic

Follow the TODOs provided in the template to build your RuntimeCall and complete your dispatch logic.

Your code should still compile with some "never constructed/used" warnings. Just one more step and we will get rid of all those warnings!

mod balances;
mod support;
mod system;

use crate::support::Dispatch;

// 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: Create an enum variant `BalancesTransfer` which contains named fields:
		- `to`: an `AccountId`
		- `amount`: a `Balance`
	*/
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected")
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		/*
			TODO:
			Use a match statement to route the `runtime_call` to call the appropriate function in
			our pallet. In this case, there is only `self.balances.transfer`.

			Your `runtime_call` won't contain the caller information which is needed to make the
			`transfer` call, but you have that information from the arguments to the `dispatch`
			function.

			You should propagate any errors from the call back up this function.
		*/
		Ok(())
	}
}

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;

use crate::support::Dispatch;

// 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 {
	BalancesTransfer { to: types::AccountId, amount: types::Balance },
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::BalancesTransfer { to, amount } => {
				self.balances.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

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 537d6072..ea8261d0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,7 +20,10 @@ mod types {
 // 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.
+	/* TODO: Create an enum variant `BalancesTransfer` which contains named fields:
+		- `to`: an `AccountId`
+		- `amount`: a `Balance`
+	*/
 }
 
 // This is our main Runtime.
@@ -81,7 +84,18 @@ impl crate::support::Dispatch for Runtime {
 		caller: Self::Caller,
 		runtime_call: Self::Call,
 	) -> support::DispatchResult {
-		unimplemented!();
+		/*
+			TODO:
+			Use a match statement to route the `runtime_call` to call the appropriate function in
+			our pallet. In this case, there is only `self.balances.transfer`.
+
+			Your `runtime_call` won't contain the caller information which is needed to make the
+			`transfer` call, but you have that information from the arguments to the `dispatch`
+			function.
+
+			You should propagate any errors from the call back up this function.
+		*/
+		Ok(())
 	}
 }
 
diff --git a/src/main.rs b/src/main.rs
index ea8261d0..d3cbb031 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,10 +20,7 @@ mod types {
 // 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: Create an enum variant `BalancesTransfer` which contains named fields:
-		- `to`: an `AccountId`
-		- `amount`: a `Balance`
-	*/
+	BalancesTransfer { to: types::AccountId, amount: types::Balance },
 }
 
 // This is our main Runtime.
@@ -54,7 +51,7 @@ impl Runtime {
 	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
 		self.system.inc_block_number();
 		if block.header.block_number != self.system.block_number() {
-			return Err("block number does not match what is expected")
+			return Err("block number does not match what is expected");
 		}
 		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
 		// result, and emit an error message if one is emitted.
@@ -84,17 +81,13 @@ impl crate::support::Dispatch for Runtime {
 		caller: Self::Caller,
 		runtime_call: Self::Call,
 	) -> support::DispatchResult {
-		/*
-			TODO:
-			Use a match statement to route the `runtime_call` to call the appropriate function in
-			our pallet. In this case, there is only `self.balances.transfer`.
-
-			Your `runtime_call` won't contain the caller information which is needed to make the
-			`transfer` call, but you have that information from the arguments to the `dispatch`
-			function.
-
-			You should propagate any errors from the call back up this function.
-		*/
+		// This match statement will allow us to correctly route `RuntimeCall`s
+		// to the appropriate pallet level function.
+		match runtime_call {
+			RuntimeCall::BalancesTransfer { to, amount } => {
+				self.balances.transfer(caller, to, amount)?;
+			},
+		}
 		Ok(())
 	}
 }

Using Execute Block

We have now successfully implemented the execute_block and dispatch logic needed to build and execute real Blocks.

Let's bring that logic into our main function.

Creating a Block

You can create a new Block by filling out all the fields of the struct and assigning it to a variable.

For example:

#![allow(unused)]
fn main() {
let block_1 = types::Block {
	header: support::Header { block_number: 1 },
	extrinsics: vec![
		support::Extrinsic {
			caller: &"alice",
			call: RuntimeCall::BalancesTransfer { to: &"bob", amount: 69 },
		},
	],
};
}

It is important that you set the block number correctly since we verify this in our execute_block function. The first block in our state machine will have the number 1.

Also remember that you can add multiple extrinsics in a single block by extending the vector.

Executing a Block

Once you have constructed your Block, you can pass it to the execute_block function implemented on your runtime.

#![allow(unused)]
fn main() {
runtime.execute_block(block_1).expect("invalid block");
}

Note how we panic with the message "invalid block" if the execute_block function returns an error. This should only happen when something is seriously wrong with your block, for example the block number is incorrect for what we expect.

This panic will NOT be triggered if there is an error in an extrinsic, as we "swallow" those errors in the execute_block function. This is the behavior we want.

Update Your Main Function

Go ahead and use the Block type and execute_block function to update the logic of your main function.

Follow the TODOs provided in the template to complete this step

By the end of this step, your code should compile, test, and run successfully, all without compiler warnings!

mod balances;
mod support;
mod system;

use crate::support::Dispatch;

// 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 {
	BalancesTransfer { to: types::AccountId, amount: types::Balance },
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::BalancesTransfer { to, amount } => {
				self.balances.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	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));

	/*
		TODO: Replace the logic above with a new `Block`.
			- Set the block number to 1 in the `Header`.
			- Move your existing transactions into extrinsic format, using the
			  `Extrinsic` and `RuntimeCall`.
	*/

	/*
		TODO:
		Use your `runtime` to call the `execute_block` function with your new block.
		If the `execute_block` function returns an error, you should panic!
		We `expect` that all the blocks being executed must be valid.
	*/

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
mod balances;
mod support;
mod system;

use crate::support::Dispatch;

// 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 {
	BalancesTransfer { to: types::AccountId, amount: types::Balance },
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::BalancesTransfer { to, amount } => {
				self.balances.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::BalancesTransfer { to: bob, amount: 30 },
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::BalancesTransfer { to: charlie, amount: 20 },
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/main.rs b/src/main.rs
index d3cbb031..c1203d12 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -93,11 +93,14 @@ impl crate::support::Dispatch for Runtime {
 }
 
 fn main() {
+	// Create a new instance of the Runtime.
+	// It will instantiate with it all the modules it uses.
 	let mut runtime = Runtime::new();
 	let alice = "alice".to_string();
 	let bob = "bob".to_string();
 	let charlie = "charlie".to_string();
 
+	// Initialize the system with some initial balance.
 	runtime.balances.set_balance(&alice, 100);
 
 	// start emulating a block
@@ -115,5 +118,20 @@ fn main() {
 	runtime.system.inc_nonce(&alice);
 	let _res = runtime.balances.transfer(alice, charlie, 20).map_err(|e| eprintln!("{}", e));
 
+	/*
+		TODO: Replace the logic above with a new `Block`.
+			- Set the block number to 1 in the `Header`.
+			- Move your existing transactions into extrinsic format, using the
+			  `Extrinsic` and `RuntimeCall`.
+	*/
+
+	/*
+		TODO:
+		Use your `runtime` to call the `execute_block` function with your new block.
+		If the `execute_block` function returns an error, you should panic!
+		We `expect` that all the blocks being executed must be valid.
+	*/
+
+	// Simply print the debug format of our runtime state.
 	println!("{:#?}", runtime);
 }
diff --git a/src/main.rs b/src/main.rs
index c1203d12..170ad380 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -103,34 +103,25 @@ fn main() {
 	// Initialize the system with some initial balance.
 	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));
-
-	/*
-		TODO: Replace the logic above with a new `Block`.
-			- Set the block number to 1 in the `Header`.
-			- Move your existing transactions into extrinsic format, using the
-			  `Extrinsic` and `RuntimeCall`.
-	*/
+	// Here are the extrinsics in our block.
+	// You can add or remove these based on the modules and calls you have set up.
+	let block_1 = types::Block {
+		header: support::Header { block_number: 1 },
+		extrinsics: vec![
+			support::Extrinsic {
+				caller: alice.clone(),
+				call: RuntimeCall::BalancesTransfer { to: bob, amount: 30 },
+			},
+			support::Extrinsic {
+				caller: alice,
+				call: RuntimeCall::BalancesTransfer { to: charlie, amount: 20 },
+			},
+		],
+	};
 
-	/*
-		TODO:
-		Use your `runtime` to call the `execute_block` function with your new block.
-		If the `execute_block` function returns an error, you should panic!
-		We `expect` that all the blocks being executed must be valid.
-	*/
+	// Execute the extrinsics which make up our block.
+	// If there are any errors, our system panics, since we should not execute invalid blocks.
+	runtime.execute_block(block_1).expect("invalid block");
 
 	// Simply print the debug format of our runtime state.
 	println!("{:#?}", runtime);

Pallet Level Dispatch

We want to make our code more modular and extensible.

Currently, all dispatch happens through the RuntimeCall, which is hardcoding dispatch logic for each of the Pallets in our system.

What we would prefer is for Pallet level dispatch logic to live in the Pallet itself, and our Runtime taking advantage of that. We have already seen end to end what it takes to set up call dispatch, so let's do it again at the Pallet level.

Pallet Call

To make our system more extensible, we want to keep all the calls for a pallet defined at the pallet level.

For this, we define an enum Call in our Balances pallet, and just like before, we introduce a new enum variant representing the function that we want to call.

Note that this enum needs to be generic over T: Config because we need access to the types defined by our configuration trait!

Pallet Dispatch

You will also notice in the template, we have included the shell for you to implement Pallet level dispatch.

Everything should look the same as the Runtime level dispatch, except the type Call is the Pallet level call we just created.

Just like before, you simply need to match the Call variant with the appropriate function, and pass the parameters needed by the function.

Create Your Pallet Level Dispatch

Follow the TODOs in the template to complete the logic for Pallet level dispatch.

The "never constructed" warning for the Transfer variant is okay.

In the next step, we will use this logic to improve our dispatch logic in our Runtime.

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> crate::support::DispatchResult {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
pub enum Call<T: Config> {
	/* TODO: Create an enum variant `Transfer` which contains named fields:
		- `to`: a `T::AccountId`
		- `amount`: a `T::Balance`
	*/
	/* TODO: Remove the `RemoveMe` placeholder. */
	RemoveMe(core::marker::PhantomData<T>),
}

/// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
/// function we want to execute.
impl<T: Config> crate::support::Dispatch for Pallet<T> {
	type Caller = T::AccountId;
	type Call = Call<T>;

	fn dispatch(
		&mut self,
		caller: Self::Caller,
		call: Self::Call,
	) -> crate::support::DispatchResult {
		/* TODO: use a `match` statement to route the `Call` to the appropriate pallet function. */
		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}

	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> crate::support::DispatchResult {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
pub enum Call<T: Config> {
	Transfer { to: T::AccountId, amount: T::Balance },
}

/// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
/// function we want to execute.
impl<T: Config> crate::support::Dispatch for Pallet<T> {
	type Caller = T::AccountId;
	type Call = Call<T>;

	fn dispatch(
		&mut self,
		caller: Self::Caller,
		call: Self::Call,
	) -> crate::support::DispatchResult {
		match call {
			Call::Transfer { to, amount } => {
				self.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
diff --git a/src/balances.rs b/src/balances.rs
index 74e6f43b..39704461 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -57,6 +57,34 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+// A public enum which describes the calls we want to expose to the dispatcher.
+// We should expect that the caller of each call will be provided by the dispatcher,
+// and not included as a parameter of the call.
+pub enum Call<T: Config> {
+	/* TODO: Create an enum variant `Transfer` which contains named fields:
+		- `to`: a `T::AccountId`
+		- `amount`: a `T::Balance`
+	*/
+	/* TODO: Remove the `RemoveMe` placeholder. */
+	RemoveMe(core::marker::PhantomData<T>),
+}
+
+/// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
+/// function we want to execute.
+impl<T: Config> crate::support::Dispatch for Pallet<T> {
+	type Caller = T::AccountId;
+	type Call = Call<T>;
+
+	fn dispatch(
+		&mut self,
+		caller: Self::Caller,
+		call: Self::Call,
+	) -> crate::support::DispatchResult {
+		/* TODO: use a `match` statement to route the `Call` to the appropriate pallet function. */
+		Ok(())
+	}
+}
+
 #[cfg(test)]
 mod tests {
 	struct TestConfig;
diff --git a/src/balances.rs b/src/balances.rs
index 39704461..947ad847 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -61,12 +61,7 @@ impl<T: Config> Pallet<T> {
 // We should expect that the caller of each call will be provided by the dispatcher,
 // and not included as a parameter of the call.
 pub enum Call<T: Config> {
-	/* TODO: Create an enum variant `Transfer` which contains named fields:
-		- `to`: a `T::AccountId`
-		- `amount`: a `T::Balance`
-	*/
-	/* TODO: Remove the `RemoveMe` placeholder. */
-	RemoveMe(core::marker::PhantomData<T>),
+	Transfer { to: T::AccountId, amount: T::Balance },
 }
 
 /// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
@@ -80,7 +75,11 @@ impl<T: Config> crate::support::Dispatch for Pallet<T> {
 		caller: Self::Caller,
 		call: Self::Call,
 	) -> crate::support::DispatchResult {
-		/* TODO: use a `match` statement to route the `Call` to the appropriate pallet function. */
+		match call {
+			Call::Transfer { to, amount } => {
+				self.transfer(caller, to, amount)?;
+			},
+		}
 		Ok(())
 	}
 }

Nested Dispatch

Now that we have defined Pallet level dispatch logic in the Pallet, we should update our Runtime to take advantage of that logic.

After this, whenever the Pallet logic is updated, the Runtime dispatch logic will also automatically get updated and route calls directly. This makes our code easier to manage, and prevent potential errors or maintenance in the future.

Nested Calls

The Balances Pallet now exposes its own list of calls in balances::Call. Rather than list them all again in the Runtime, we can use a nested enum to route our calls correctly.

Imagine the following construction:

#![allow(unused)]
fn main() {
pub enum RuntimeCall {
	Balances(balances::Call<Runtime>),
}
}

In this case, we have a variant RuntimeCall::Balances, which itself contains a type balances::Call. This means we can access all the calls exposed by balances:Call under this variant. As we create more pallets or extend our calls, this nested structure will scale very well.

We call the RuntimeCall an "outer enum", and the balances::Call an "inter enum". This construction of using outer and inter enums is very common in the Polkadot SDK.

Re-Dispatching to Pallet

Our current dispatch logic directly calls the functions in the Pallet. As we mentioned, having this logic live outside of the Pallet can increase the burden of maintenance or errors.

But now that we have defined Pallet level dispatch logic in the Pallet itself, we can use this to make the Runtime dispatch more extensible.

To do this, rather than calling the Pallet function directly, we can extract the inner call from the RuntimeCall, and then use the balances::Pallet to dispatch that call to the appropriate logic.

That would look something like:

#![allow(unused)]
fn main() {
match runtime_call {
	RuntimeCall::Balances(call) => {
		self.balances.dispatch(caller, call)?;
	},
}
}

Here you can see that the first thing we do is check that the call is a Balances variant, then we extract from it the call which is a balances::Call type, and then we use self.balances which is a balances::Pallet to dispatch the balances::Call.

Updating Your Block

Since we have updated the construction of the RuntimeCall enum, we will also need to update our Block construction in fn main. Nothing magical here, just needing to construct a nested enum using both RuntimeCall::Balances and balances::Call::Transfer.

Enable Nested Dispatch

Now is the time to complete this step and glue together Pallet level dispatch with the Runtime level dispatch logic.

Follow the TODOs provided in the template to get your full end to end dispatch logic running. By the end of this step there should be no compiler warnings.

mod balances;
mod support;
mod system;

use crate::support::Dispatch;

// 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: Turn this into a nested enum where variant `Balances` contains a `balances::Call`. */
	BalancesTransfer { to: types::AccountId, amount: types::Balance },
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			/*
				TODO:
				Adjust this logic to handle the nested enums, and simply call the `dispatch` logic
				on the balances call, rather than the function directly.
			*/
			RuntimeCall::BalancesTransfer { to, amount } => {
				self.balances.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			/* TODO: Update your extrinsics to use the nested enum. */
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::BalancesTransfer { to: bob, amount: 30 },
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::BalancesTransfer { to: charlie, amount: 20 },
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
mod balances;
mod support;
mod system;

use crate::support::Dispatch;

// 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 {
	Balances(balances::Call<Runtime>),
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/main.rs b/src/main.rs
index 170ad380..2c32a801 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,6 +20,7 @@ mod types {
 // 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: Turn this into a nested enum where variant `Balances` contains a `balances::Call`. */
 	BalancesTransfer { to: types::AccountId, amount: types::Balance },
 }
 
@@ -84,6 +85,11 @@ impl crate::support::Dispatch for Runtime {
 		// This match statement will allow us to correctly route `RuntimeCall`s
 		// to the appropriate pallet level function.
 		match runtime_call {
+			/*
+				TODO:
+				Adjust this logic to handle the nested enums, and simply call the `dispatch` logic
+				on the balances call, rather than the function directly.
+			*/
 			RuntimeCall::BalancesTransfer { to, amount } => {
 				self.balances.transfer(caller, to, amount)?;
 			},
@@ -108,6 +114,7 @@ fn main() {
 	let block_1 = types::Block {
 		header: support::Header { block_number: 1 },
 		extrinsics: vec![
+			/* TODO: Update your extrinsics to use the nested enum. */
 			support::Extrinsic {
 				caller: alice.clone(),
 				call: RuntimeCall::BalancesTransfer { to: bob, amount: 30 },
diff --git a/src/main.rs b/src/main.rs
index 2c32a801..8a874e18 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,8 +20,7 @@ mod types {
 // 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: Turn this into a nested enum where variant `Balances` contains a `balances::Call`. */
-	BalancesTransfer { to: types::AccountId, amount: types::Balance },
+	Balances(balances::Call<Runtime>),
 }
 
 // This is our main Runtime.
@@ -85,13 +84,8 @@ impl crate::support::Dispatch for Runtime {
 		// This match statement will allow us to correctly route `RuntimeCall`s
 		// to the appropriate pallet level function.
 		match runtime_call {
-			/*
-				TODO:
-				Adjust this logic to handle the nested enums, and simply call the `dispatch` logic
-				on the balances call, rather than the function directly.
-			*/
-			RuntimeCall::BalancesTransfer { to, amount } => {
-				self.balances.transfer(caller, to, amount)?;
+			RuntimeCall::Balances(call) => {
+				self.balances.dispatch(caller, call)?;
 			},
 		}
 		Ok(())
@@ -114,14 +108,13 @@ fn main() {
 	let block_1 = types::Block {
 		header: support::Header { block_number: 1 },
 		extrinsics: vec![
-			/* TODO: Update your extrinsics to use the nested enum. */
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::BalancesTransfer { to: bob, amount: 30 },
+				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
 			},
 			support::Extrinsic {
 				caller: alice,
-				call: RuntimeCall::BalancesTransfer { to: charlie, amount: 20 },
+				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
 			},
 		],
 	};

The Proof of Existence Pallet

In this section, we will create a Proof of Existence Pallet.

We will take advantage of all the refactoring we have done so far to make it very simple to integrate this new Pallet into our existing Runtime.

There are no new concepts to learn in this section, however it will test that you understand and can reproduce all the steps and concepts learned in the previous sections.

Proof of Existence Pallet

We have gone a long way since we built our very first Balances Pallet.

The structure of our Runtime and Pallets have evolved quite a bit since.

  • Generic Types
  • Config Trait
  • Nested Dispatch
  • and more...

This will be the last pallet we build for this tutorial, but we will build it knowing all of the tips and tricks we have learned so far.

The goal here is for you to ensure that all of the intricacies of Pallet development is well understood and that you are able to navigate all of the Rust code.

What is Proof of Existence?

The Proof of Existence Pallet uses the blockchain to provide a secure and immutable ledger that can be used to verify the existence of a particular document, file, or piece of data at a specific point in time.

Because the blockchain acts as an immutable ledger whose history cannot be changed, when some data is placed on the blockchain, it can be referenced at a future time to show that some data already existed in the past.

For example, imagine you discovered a cure to cancer, but before you reveal it, you want to make sure that you can prove when you had made the discovery. To do this, you could put some sort of data on the blockchain which represents the cure. At a later date, when you get your research published and reviewed, you would be able to use the blockchain as verifiable evidence of when you first made the discovery.

Normally, you would not put the raw contents of your claim on the blockchain but a hash of the data, which is both smaller and obfuscates the data in your claim before you are ready to reveal it.

However, for the purposes of this tutorial, we won't introduce hash functions yet.

Pallet Structure

The BTreeMap is again the best tool to use for storing data in this Pallet. However, you will notice that the construction of the storage is a bit different than before. Rather than having a map from accounts to some data, we will actually map the content we want to claim to the user who owns it.

This construction of content -> account allows an account to be the owner of multiple different claims, but having each claim only be owned by one user.

Create Your Pallet

Let's start to create this pallet:

  1. Create a new file for your Proof of Existence Pallet.

    touch src/proof_of_existence.rs
    
  2. Copy the contents from the template into your new file.

  3. Complete the TODOs to add a storage to your new pallet and allow it to be initialized.

  4. In your main.rs file, import the proof_of_existence module.

Make sure that everything compiles after you complete these steps.

Compiler warnings about "never read/used" are okay.

mod balances;
/* TODO: Import the `proof_of_existence` module. */
mod support;
mod system;

use crate::support::Dispatch;

// 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 {
	Balances(balances::Call<Runtime>),
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	/* TODO: Add a field `claims` which is a `BTreeMap` fom `T::Content` to `T::AccountId`. */
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		/* TODO: Return a new instance of the `Pallet` struct. */
	}
}
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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 {
	Balances(balances::Call<Runtime>),
}

// 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() }
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}
}
}
diff --git a/src/main.rs b/src/main.rs
index 8a874e18..e15cf4f3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
 mod balances;
+/* TODO: Import the `proof_of_existence` module. */
 mod support;
 mod system;
 
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
new file mode 100644
index 00000000..87ea242e
--- /dev/null
+++ b/src/proof_of_existence.rs
@@ -0,0 +1,25 @@
+use core::fmt::Debug;
+use std::collections::BTreeMap;
+
+pub trait Config: crate::system::Config {
+	/// The type which represents the content that can be claimed using this pallet.
+	/// Could be the content directly as bytes, or better yet the hash of that content.
+	/// We leave that decision to the runtime developer.
+	type Content: Debug + Ord;
+}
+
+/// This is the Proof of Existence Module.
+/// It is a simple module that allows accounts to claim existence of some data.
+#[derive(Debug)]
+pub struct Pallet<T: Config> {
+	/// A simple storage map from content to the owner of that content.
+	/// Accounts can make multiple different claims, but each claim can only have one owner.
+	/* TODO: Add a field `claims` which is a `BTreeMap` fom `T::Content` to `T::AccountId`. */
+}
+
+impl<T: Config> Pallet<T> {
+	/// Create a new instance of the Proof of Existence Module.
+	pub fn new() -> Self {
+		/* TODO: Return a new instance of the `Pallet` struct. */
+	}
+}
diff --git a/src/main.rs b/src/main.rs
index e15cf4f3..6dd23260 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
 mod balances;
-/* TODO: Import the `proof_of_existence` module. */
+mod proof_of_existence;
 mod support;
 mod system;
 
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index 87ea242e..5e7de2a7 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -14,12 +14,12 @@ pub trait Config: crate::system::Config {
 pub struct Pallet<T: Config> {
 	/// A simple storage map from content to the owner of that content.
 	/// Accounts can make multiple different claims, but each claim can only have one owner.
-	/* TODO: Add a field `claims` which is a `BTreeMap` fom `T::Content` to `T::AccountId`. */
+	claims: BTreeMap<T::Content, T::AccountId>,
 }
 
 impl<T: Config> Pallet<T> {
 	/// Create a new instance of the Proof of Existence Module.
 	pub fn new() -> Self {
-		/* TODO: Return a new instance of the `Pallet` struct. */
+		Self { claims: BTreeMap::new() }
 	}
 }

Proof Of Existence Functions

The Proof of Existence Pallet is quite simple, so let's build out the logic needed.

Get Claim

Our Pallet has a simple storage map from some claim content to the owner of that claim.

The get_claim function should act as a simple read function returning the T::AccountId of the owner, if there is any. In the case we query a claim which has no owner, we should return None.

This is not a function that a user would call from an extrinsic, but is useful for other parts of your state machine to access the data in this Pallet.

Create Claim

Any user can add a new claim to the Proof of Existence Pallet.

The only thing that is important is that we check that the claim has not already been made by another user.

Each claim should only have one owner, and whoever makes the claim first gets priority.

You can check if some claim is already in the claims storage using the contains_key api:

#![allow(unused)]
fn main() {
if self.claims.contains_key(&claim) {
	return Err(&"this content is already claimed");
}
}

Revoke Claim

Data on the blockchain is not free, and in fact is very expensive to maintain. Giving users the ability to clean up their data is not only good, but encouraged. If a user no longer has a need to store their claim on chain, they should clean it up.

Furthermore, the history of the blockchain is immutable. Even if the data about a claim does not exist in the "current state", it can be shown to have existed in the past.

Keeping things in the current state just makes querying for information easier.

To revoke a claim, we need to check two things:

  1. The the claim exists.
  2. That the person who wants to revoke the claim is the owner of that claim.

You should be able to handle all of this logic by calling the get_claim function and using ok_or to return an error when the claim does not exist. If the claim does exist, you should be able to directly extract the owner from the state query.

Build Your Functions

Complete the TODOs outlined in the template.

Afterward, create a basic_proof_of_existence test to check that all your functions are working as expected.

This includes both the success and possible error conditions of your Pallet.

#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		/* TODO: `get` the `claim` */
		unimplemented!()
	}

	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		/* TODO: Check that a `claim` does not already exist. If so, return an error. */
		/* TODO: `insert` the claim on behalf of `caller`. */
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		/* TODO: Get the owner of the `claim` to be revoked. */
		/* TODO: Check that the `owner` matches the `caller`. */
		/* TODO: If all checks pass, then `remove` the `claim`. */
		Ok(())
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		/*
			TODO:
			Create an end to end test verifying the basic functionality of this pallet.
				- Check the initial state is as you expect.
				- Check that all functions work successfully.
				- Check that all error conditions error as expected.
		*/
	}
}
}
#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		self.claims.get(claim)
	}

	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		if self.claims.contains_key(&claim) {
			return Err("this content is already claimed");
		}
		self.claims.insert(claim, caller);
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
		if caller != *owner {
			return Err("this content is owned by someone else");
		}
		self.claims.remove(&claim);
		Ok(())
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		let mut poe = super::Pallet::<TestConfig>::new();
		assert_eq!(poe.get_claim(&"Hello, world!"), None);
		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
		assert_eq!(
			poe.create_claim("bob", "Hello, world!"),
			Err("this content is already claimed")
		);
		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
	}
}
}
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index 5e7de2a7..b85acdf7 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -1,3 +1,4 @@
+use crate::support::DispatchResult;
 use core::fmt::Debug;
 use std::collections::BTreeMap;
 
@@ -22,4 +23,54 @@ impl<T: Config> Pallet<T> {
 	pub fn new() -> Self {
 		Self { claims: BTreeMap::new() }
 	}
+
+	/// Get the owner (if any) of a claim.
+	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
+		/* TODO: `get` the `claim` */
+		unimplemented!()
+	}
+
+	/// Create a new claim on behalf of the `caller`.
+	/// This function will return an error if someone already has claimed that content.
+	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
+		/* TODO: Check that a `claim` does not already exist. If so, return an error. */
+		/* TODO: `insert` the claim on behalf of `caller`. */
+		Ok(())
+	}
+
+	/// Revoke an existing claim on some content.
+	/// This function should only succeed if the caller is the owner of an existing claim.
+	/// It will return an error if the claim does not exist, or if the caller is not the owner.
+	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
+		/* TODO: Get the owner of the `claim` to be revoked. */
+		/* TODO: Check that the `owner` matches the `caller`. */
+		/* TODO: If all checks pass, then `remove` the `claim`. */
+		Ok(())
+	}
+}
+
+#[cfg(test)]
+mod test {
+	struct TestConfig;
+
+	impl super::Config for TestConfig {
+		type Content = &'static str;
+	}
+
+	impl crate::system::Config for TestConfig {
+		type AccountId = &'static str;
+		type BlockNumber = u32;
+		type Nonce = u32;
+	}
+
+	#[test]
+	fn basic_proof_of_existence() {
+		/*
+			TODO:
+			Create an end to end test verifying the basic functionality of this pallet.
+				- Check the initial state is as you expect.
+				- Check that all functions work successfully.
+				- Check that all error conditions error as expected.
+		*/
+	}
 }
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index b85acdf7..cd75fa24 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -26,15 +26,16 @@ impl<T: Config> Pallet<T> {
 
 	/// Get the owner (if any) of a claim.
 	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
-		/* TODO: `get` the `claim` */
-		unimplemented!()
+		self.claims.get(claim)
 	}
 
 	/// Create a new claim on behalf of the `caller`.
 	/// This function will return an error if someone already has claimed that content.
 	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
-		/* TODO: Check that a `claim` does not already exist. If so, return an error. */
-		/* TODO: `insert` the claim on behalf of `caller`. */
+		if self.claims.contains_key(&claim) {
+			return Err("this content is already claimed");
+		}
+		self.claims.insert(claim, caller);
 		Ok(())
 	}
 
@@ -42,9 +43,11 @@ impl<T: Config> Pallet<T> {
 	/// This function should only succeed if the caller is the owner of an existing claim.
 	/// It will return an error if the claim does not exist, or if the caller is not the owner.
 	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
-		/* TODO: Get the owner of the `claim` to be revoked. */
-		/* TODO: Check that the `owner` matches the `caller`. */
-		/* TODO: If all checks pass, then `remove` the `claim`. */
+		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
+		if caller != *owner {
+			return Err("this content is owned by someone else");
+		}
+		self.claims.remove(&claim);
 		Ok(())
 	}
 }
@@ -65,12 +68,15 @@ mod test {
 
 	#[test]
 	fn basic_proof_of_existence() {
-		/*
-			TODO:
-			Create an end to end test verifying the basic functionality of this pallet.
-				- Check the initial state is as you expect.
-				- Check that all functions work successfully.
-				- Check that all error conditions error as expected.
-		*/
+		let mut poe = super::Pallet::<TestConfig>::new();
+		assert_eq!(poe.get_claim(&"Hello, world!"), None);
+		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
+		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
+		assert_eq!(
+			poe.create_claim("bob", "Hello, world!"),
+			Err("this content is already claimed")
+		);
+		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
+		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
 	}
 }

Add Proof of Existence Dispatch

We have already established the nested dispatch pipeline for Pallets in the Runtime.

Let's build Pallet level dispatch logic for the Proof of Existence to take advantage of that.

Create Pallet Level Dispatch

There is nothing new here, but we have left more for you to fill out than before.

  1. Create the variants for CreateClaim and RevokeClaim for your Call enum.
  2. Implement the Dispatch trait for your Pallet.

If you get stuck, try not to look at the solution provided here, but instead look at what you did in the Balances Pallet. Everything we have done here, we have already done in the past. This is an opportunity to catch where you may have outstanding questions or misunderstandings.

Don't worry about compiler warnings like "never used/constructed".

#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		self.claims.get(claim)
	}

	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		if self.claims.contains_key(&claim) {
			return Err("this content is already claimed");
		}
		self.claims.insert(claim, caller);
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
		if caller != *owner {
			return Err("this content is owned by someone else");
		}
		self.claims.remove(&claim);
		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
pub enum Call<T: Config> {
	/*
		TODO:
		Create variants for:
		- `CreateClaim`
		- `RevokeClaim`

		Remember that you only need to pass in the `claim` data, as `caller` information is passed
		in through the `dispatch` logic.
	*/
	RemoveMe(core::marker::PhantomData<T>),
}

/// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
/// function we want to execute.
/*
	TODO:
	Implement `crate::support::Dispatch` for `Pallet<T>`.

	In your `dispatch` logic, match on `call` and forward the `caller` and `claim` data to the
	appropriate function.
*/

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		let mut poe = super::Pallet::<TestConfig>::new();
		assert_eq!(poe.get_claim(&"Hello, world!"), None);
		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
		assert_eq!(
			poe.create_claim("bob", "Hello, world!"),
			Err("this content is already claimed")
		);
		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
	}
}
}
#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		self.claims.get(claim)
	}

	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		if self.claims.contains_key(&claim) {
			return Err("this content is already claimed");
		}
		self.claims.insert(claim, caller);
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
		if caller != *owner {
			return Err("this content is owned by someone else");
		}
		self.claims.remove(&claim);
		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
pub enum Call<T: Config> {
	CreateClaim { claim: T::Content },
	RevokeClaim { claim: T::Content },
}

/// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
/// function we want to execute.
impl<T: Config> crate::support::Dispatch for Pallet<T> {
	type Caller = T::AccountId;
	type Call = Call<T>;

	fn dispatch(
		&mut self,
		caller: Self::Caller,
		call: Self::Call,
	) -> crate::support::DispatchResult {
		match call {
			Call::CreateClaim { claim } => {
				self.create_claim(caller, claim)?;
			},
			Call::RevokeClaim { claim } => {
				self.revoke_claim(caller, claim)?;
			},
		}
		Ok(())
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		let mut poe = super::Pallet::<TestConfig>::new();
		assert_eq!(poe.get_claim(&"Hello, world!"), None);
		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
		assert_eq!(
			poe.create_claim("bob", "Hello, world!"),
			Err("this content is already claimed")
		);
		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
	}
}
}
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index cd75fa24..a1755b34 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -52,6 +52,32 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+// A public enum which describes the calls we want to expose to the dispatcher.
+// We should expect that the caller of each call will be provided by the dispatcher,
+// and not included as a parameter of the call.
+pub enum Call<T: Config> {
+	/*
+		TODO:
+		Create variants for:
+		- `CreateClaim`
+		- `RevokeClaim`
+
+		Remember that you only need to pass in the `claim` data, as `caller` information is passed
+		in through the `dispatch` logic.
+	*/
+	RemoveMe(core::marker::PhantomData<T>),
+}
+
+/// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
+/// function we want to execute.
+/*
+	TODO:
+	Implement `crate::support::Dispatch` for `Pallet<T>`.
+
+	In your `dispatch` logic, match on `call` and forward the `caller` and `claim` data to the
+	appropriate function.
+*/
+
 #[cfg(test)]
 mod test {
 	struct TestConfig;
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index a1755b34..4e2e0ac7 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -56,27 +56,32 @@ impl<T: Config> Pallet<T> {
 // We should expect that the caller of each call will be provided by the dispatcher,
 // and not included as a parameter of the call.
 pub enum Call<T: Config> {
-	/*
-		TODO:
-		Create variants for:
-		- `CreateClaim`
-		- `RevokeClaim`
-
-		Remember that you only need to pass in the `claim` data, as `caller` information is passed
-		in through the `dispatch` logic.
-	*/
-	RemoveMe(core::marker::PhantomData<T>),
+	CreateClaim { claim: T::Content },
+	RevokeClaim { claim: T::Content },
 }
 
 /// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
 /// function we want to execute.
-/*
-	TODO:
-	Implement `crate::support::Dispatch` for `Pallet<T>`.
+impl<T: Config> crate::support::Dispatch for Pallet<T> {
+	type Caller = T::AccountId;
+	type Call = Call<T>;
 
-	In your `dispatch` logic, match on `call` and forward the `caller` and `claim` data to the
-	appropriate function.
-*/
+	fn dispatch(
+		&mut self,
+		caller: Self::Caller,
+		call: Self::Call,
+	) -> crate::support::DispatchResult {
+		match call {
+			Call::CreateClaim { claim } => {
+				self.create_claim(caller, claim)?;
+			},
+			Call::RevokeClaim { claim } => {
+				self.revoke_claim(caller, claim)?;
+			},
+		}
+		Ok(())
+	}
+}
 
 #[cfg(test)]
 mod test {

Integrate PoE Into Your Runtime

The Proof of Existence pallet is done, but we still need to integrate it into your Runtime.

Let's take a look at that process.

Integration Steps

  1. The first place to start is adding the proof_of_existence field to your struct Runtime.

  2. Next you need to update your fn new() to also initialize proof_of_existence.

  3. After, create a new concrete type Content which is a &'static str. As mentioned, normally this would be a hash, but for simplicity we are once again a simple static string.

    If you want to use a hash now or in the future, it would be as simple as updating this one line to change all the types in your Runtime and Pallet. That is the kind of flexibility we have been working toward!

  4. Then, implement proof_of_existence::Config for Runtime, using your types::Content.

  5. At this point, things should already compile successfully, so use this as a checkpoint.

  6. Introduce a new variant ProofOfExistence for the RuntimeCall.

  7. Finally, update your fn dispatch logic to handle re-dispatching ProofOfExistence calls to the proof_of_existence::Pallet.

Hopefully from this process, you can see how all of the abstractions we have introduced has made integrating new Pallets into your runtime quite easy.

We will make this process even easier in the near future using macros!

By the end of this step, everything should compile without warnings.

mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	/* TODO: Add the concrete `Content` type for your runtime. */
}

// 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 {
	Balances(balances::Call<Runtime>),
	/* TODO: Add a `ProofOfExistence` variant to access `proof_of_existence::Call`. */
}

// 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>,
	/* TODO: Add `proof_of_existence` field to your `Runtime`. */
}

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;
}

/* TODO: Implement proof_of_existence::Config` for `Runtime`. */

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(),
			/* TODO: Initialize the `proof_of_existence` pallet. */
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			/* TODO: Dispatch `calls` to the `ProofOfExistence` pallet. */
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/main.rs b/src/main.rs
index 6dd23260..a86c9ee4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,12 +16,14 @@ mod types {
 	pub type Extrinsic = crate::support::Extrinsic<AccountId, crate::RuntimeCall>;
 	pub type Header = crate::support::Header<BlockNumber>;
 	pub type Block = crate::support::Block<Header, Extrinsic>;
+	/* TODO: Add the concrete `Content` type for your runtime. */
 }
 
 // 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 {
 	Balances(balances::Call<Runtime>),
+	/* TODO: Add a `ProofOfExistence` variant to access `proof_of_existence::Call`. */
 }
 
 // This is our main Runtime.
@@ -30,6 +32,7 @@ pub enum RuntimeCall {
 pub struct Runtime {
 	system: system::Pallet<Self>,
 	balances: balances::Pallet<Self>,
+	/* TODO: Add `proof_of_existence` field to your `Runtime`. */
 }
 
 impl system::Config for Runtime {
@@ -42,10 +45,16 @@ impl balances::Config for Runtime {
 	type Balance = types::Balance;
 }
 
+/* TODO: Implement proof_of_existence::Config` for `Runtime`. */
+
 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() }
+		Self {
+			system: system::Pallet::new(),
+			balances: balances::Pallet::new(),
+			/* TODO: Initialize the `proof_of_existence` pallet. */
+		}
 	}
 
 	// Execute a block of extrinsics. Increments the block number.
@@ -88,6 +97,7 @@ impl crate::support::Dispatch for Runtime {
 			RuntimeCall::Balances(call) => {
 				self.balances.dispatch(caller, call)?;
 			},
+			/* TODO: Dispatch `calls` to the `ProofOfExistence` pallet. */
 		}
 		Ok(())
 	}
diff --git a/src/main.rs b/src/main.rs
index a86c9ee4..868309a7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,14 +16,14 @@ mod types {
 	pub type Extrinsic = crate::support::Extrinsic<AccountId, crate::RuntimeCall>;
 	pub type Header = crate::support::Header<BlockNumber>;
 	pub type Block = crate::support::Block<Header, Extrinsic>;
-	/* TODO: Add the concrete `Content` type for your runtime. */
+	pub type Content = &'static str;
 }
 
 // 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 {
 	Balances(balances::Call<Runtime>),
-	/* TODO: Add a `ProofOfExistence` variant to access `proof_of_existence::Call`. */
+	ProofOfExistence(proof_of_existence::Call<Runtime>),
 }
 
 // This is our main Runtime.
@@ -32,7 +32,7 @@ pub enum RuntimeCall {
 pub struct Runtime {
 	system: system::Pallet<Self>,
 	balances: balances::Pallet<Self>,
-	/* TODO: Add `proof_of_existence` field to your `Runtime`. */
+	proof_of_existence: proof_of_existence::Pallet<Self>,
 }
 
 impl system::Config for Runtime {
@@ -45,7 +45,9 @@ impl balances::Config for Runtime {
 	type Balance = types::Balance;
 }
 
-/* TODO: Implement proof_of_existence::Config` for `Runtime`. */
+impl proof_of_existence::Config for Runtime {
+	type Content = types::Content;
+}
 
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
@@ -53,7 +55,7 @@ impl Runtime {
 		Self {
 			system: system::Pallet::new(),
 			balances: balances::Pallet::new(),
-			/* TODO: Initialize the `proof_of_existence` pallet. */
+			proof_of_existence: proof_of_existence::Pallet::new(),
 		}
 	}
 
@@ -97,7 +99,9 @@ impl crate::support::Dispatch for Runtime {
 			RuntimeCall::Balances(call) => {
 				self.balances.dispatch(caller, call)?;
 			},
-			/* TODO: Dispatch `calls` to the `ProofOfExistence` pallet. */
+			RuntimeCall::ProofOfExistence(call) => {
+				self.proof_of_existence.dispatch(caller, call)?;
+			},
 		}
 		Ok(())
 	}

Add PoE Extrinsics to Blocks

The Proof Of Existence Pallet is fully integrated into your runtime at this point, but we aren't really using it.

Create some new Blocks in your fn main() to test out the functionality of the Proof of Existence Pallet.

Be creative, and even feel free to introduce some extrinsics which will trigger errors based on the logic of your pallets.

Don't forget to increment your block number and actually call execute_block for each of those blocks.

Take a look at the final output and check that the state of your machine makes sense!

mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
			},
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	/*
		TODO:
		Create new block(s) which execute extrinsics for the new `ProofOfExistence` pallet.
			- Make sure to set the block number correctly.
			- Feel free to allow some extrinsics to fail, and see the errors appear.
	*/

	// Execute the extrinsics which make up our block.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	/* TODO: Execute your new block(s). */

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/main.rs b/src/main.rs
index 868309a7..73b69ef4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -134,9 +134,17 @@ fn main() {
 		],
 	};
 
+	/*
+		TODO:
+		Create new block(s) which execute extrinsics for the new `ProofOfExistence` pallet.
+			- Make sure to set the block number correctly.
+			- Feel free to allow some extrinsics to fail, and see the errors appear.
+	*/
+
 	// Execute the extrinsics which make up our block.
 	// If there are any errors, our system panics, since we should not execute invalid blocks.
 	runtime.execute_block(block_1).expect("invalid block");
+	/* TODO: Execute your new block(s). */
 
 	// Simply print the debug format of our runtime state.
 	println!("{:#?}", runtime);
diff --git a/src/main.rs b/src/main.rs
index 73b69ef4..d2e384e3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -125,26 +125,59 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::Balances(balances::Call::Transfer { to: bob, amount: 30 }),
+				call: RuntimeCall::Balances(balances::Call::Transfer {
+					to: bob.clone(),
+					amount: 30,
+				}),
 			},
 			support::Extrinsic {
-				caller: alice,
+				caller: alice.clone(),
 				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
 			},
 		],
 	};
 
-	/*
-		TODO:
-		Create new block(s) which execute extrinsics for the new `ProofOfExistence` pallet.
-			- Make sure to set the block number correctly.
-			- Feel free to allow some extrinsics to fail, and see the errors appear.
-	*/
+	let block_2 = types::Block {
+		header: support::Header { block_number: 2 },
+		extrinsics: vec![
+			support::Extrinsic {
+				caller: alice.clone(),
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+					claim: "Hello, world!",
+				}),
+			},
+			support::Extrinsic {
+				caller: bob.clone(),
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+					claim: "Hello, world!",
+				}),
+			},
+		],
+	};
+
+	let block_3 = types::Block {
+		header: support::Header { block_number: 3 },
+		extrinsics: vec![
+			support::Extrinsic {
+				caller: alice,
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
+					claim: "Hello, world!",
+				}),
+			},
+			support::Extrinsic {
+				caller: bob,
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+					claim: "Hello, world!",
+				}),
+			},
+		],
+	};
 
-	// Execute the extrinsics which make up our block.
+	// Execute the extrinsics which make up our blocks.
 	// If there are any errors, our system panics, since we should not execute invalid blocks.
 	runtime.execute_block(block_1).expect("invalid block");
-	/* TODO: Execute your new block(s). */
+	runtime.execute_block(block_2).expect("invalid block");
+	runtime.execute_block(block_3).expect("invalid block");
 
 	// Simply print the debug format of our runtime state.
 	println!("{:#?}", runtime);

Rust Macros

In this section, we will introduce Rust Macros to our project to reduce boilerplate code and automate implementations.

You can imagine that continuing to add new Pallets to our runtime would lead to a lot of similar or redundant code.

By the end of this section, you will see how Rust Macros can automatically generate the code we have been writing, and why the Polkadot SDK uses this technique to improve developer experience and output.

Introducing Macros

If you have made it this far, then you have finished designing your simple state machine.

At this point, our goal is to see if we can use the power of Rust macros to make future development even easier.

All of this is in preparation for you to work with the Polkadot SDK, which heavily relies on macros like the ones you will see here.

Auto Generated Code

As mentioned earlier, Rust macros are basically code which can generate more code.

As you can see from our simple state machine, there is a lot of boiler plate code that we could generate, following the simple patterns and structures we have designed.

For example:

  • We expect that each Pallet will expose some callable functions with Call.
  • We know that each Call will have all the same parameters of the underlying Pallet function, except the caller.
  • We know that each Pallet will implement Dispatch logic on the Pallet struct.
  • We know that the Runtime will accumulate all the pallet::Calls into the RuntimeCall outer enum.
  • We know that the Runtime will have logic to re-dispatch runtime level calls to the pallet level.
  • and so on...

The more we abstract our Pallet and Runtime into consistent and and extensible pieces, the more we can automate, and ultimately this can provide a better developer experience.

This tutorial is not attempting to teach you how to write these macros. That information would take a whole tutorial itself.

Instead, we are providing you with macros which should work directly with your existing code, and replace a lot of code that you have already written.

Macros in general are "magical". If you have not written the macro yourself, there can be very little insight into what is happening underneath. In this context, the macros we are providing to you will directly replace code you have already written, so you should completely understand what is being generated, and how they work.

The macros folder contains a lib.rs, which exposes the two attribute macros built for this tutorial:

  1. #[macros::call]
  2. #[macros::runtime]

You can find the code for these two macros in their respective call and runtime folders.

In each of these folders there are 3 files:

  1. mod.rs - The entry point for the macro, where code is parsed, and then generated.
  2. parse.rs - The parsing logic for the macro, extracting the information we need to generate code.
  3. expand.rs - The expansion / generation code, which will write new code for us with the data provided.

We will go through each of these more deeply as we include the macros into our code.

Adding the Macros to Our Project

All of the macros are contained within their own crate which will be a folder in your project.

Download the folder contents for the macros here: download

If that link does not work, you can extract the macros folder however is best for you from the source repository for this tutorial: https://github.com/shawntabrizi/rust-state-machine/tree/gitorial/

Once you have the contents of the macros folder:

  1. Copy the contents into a macros folder in the root of your project.

  2. Update your cargo.toml file to include this crate into your project:

    [dependencies]
    num = "0.4.1"
    macros = { path = "./macros/" }
    

Recompile your project, and you should see this new create and its sub-dependencies being compiled.

In the next step we will actually start integrating these macros into your simple state machine.

[package]
name = "rust-state-machine"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num = "0.4.1"
# TODO: Import the `macros` crate from the path `./macros/`.
#![allow(unused)]
fn main() {
/* TODO: Download the provided `macros` folder, and copy the content into your project. */
}
[package]
name = "rust-state-machine"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num = "0.4.1"
macros = { path = "./macros/" }
[package]
name = "macros"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.69"
quote = "1.0.33"
syn = { version = "2.0.39", features = ["full", "extra-traits"] }
#![allow(unused)]
fn main() {
use super::parse::CallDef;
use quote::quote;

/// See the `fn call` docs at the `lib.rs` of this crate for a high level definition.
pub fn expand_call(def: CallDef) -> proc_macro2::TokenStream {
	let CallDef { pallet_struct, methods } = def;

	// This is a vector of all the callable function names.
	let fn_name = methods.iter().map(|method| &method.name).collect::<Vec<_>>();

	// This is a nested vector of all the arguments for each of the functions in `fn_name`. It does
	// not include the `self` or `caller: T::AccountId` parameter, which we always assume are the
	// first two parameters to these calls.
	let args_name = methods
		.iter()
		.map(|method| method.args.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>())
		.collect::<Vec<_>>();

	// This is a nested vector of all the types for all the arguments for each of the functions in
	// `fn_name`. It has the same assumptions as `args_name`.
	let args_type = methods
		.iter()
		.map(|method| method.args.iter().map(|(_, type_)| type_.clone()).collect::<Vec<_>>())
		.collect::<Vec<_>>();

	// This quote block creates an `enum Call` which contains all the calls exposed by our pallet,
	// and the `Dispatch` trait logic to route a `caller` to access those functions.
	let dispatch_impl = quote! {
		// The callable functions exposed by this pallet.
		//
		// The parsed function names will be `snake_case`, and that will show up in the enum.
		#[allow(non_camel_case_types)]
		pub enum Call<T: Config> {
			(
				fn_name { #( #args_name: #args_type),* },
			)*
		}

		// Dispatch logic at the pallet level, mapping each of the items in the `Call` enum to the
		// appropriate function call with all arguments, including the `caller`.
		impl<T: Config> crate::support::Dispatch for #pallet_struct<T> {
			type Caller = T::AccountId;
			type Call = Call<T>;

			fn dispatch(&mut self, caller: Self::Caller, call: Self::Call) -> crate::support::DispatchResult {
				match call {
					(
						Call::#fn_name { #( #args_name ),* } => {
							self.#fn_name(
								// Note that we assume the first argument of every call is the `caller`.
								caller,
								( #args_name ),*
							)?;
						},
					)*
				}
				Ok(())
			}
		}
	};

	// Return the generated code.
	dispatch_impl.into()
}
}
#![allow(unused)]
fn main() {
pub mod expand;
pub mod parse;

/// See the `fn call` docs at the `lib.rs` of this crate for a high level definition.
pub fn call(
	_attr: proc_macro::TokenStream,
	item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
	// The final expanded code will be placed here.
	// Since our macro only adds new code, our final product will contain all of our old code too,
	// hence we clone `item`.
	let mut finished = item.clone();
	let item_mod = syn::parse_macro_input!(item as syn::Item);

	// First we parse the call functions implemented for the pallet...
	let generated: proc_macro::TokenStream = match parse::CallDef::try_from(item_mod.clone()) {
		// ..then we generate our new code.
		Ok(def) => expand::expand_call(def).into(),
		Err(e) => e.to_compile_error().into(),
	};

	// Add our generated code to the end, and return the final result.
	finished.extend(generated);
	return finished;
}
}
#![allow(unused)]
fn main() {
use quote::ToTokens;
use syn::spanned::Spanned;

// Custom keywords we match to when parsing the calls in a pallet.
mod keyword {
	syn::custom_keyword!(T);
	syn::custom_keyword!(AccountId);
}

/// This object will collect all the information we need to keep while parsing the callable
/// functions.
#[derive(Debug)]
pub struct CallDef {
	/// This is the name of the pallet struct where the callable functions are implemented. We
	/// mostly assume it is `Pallet`.
	pub pallet_struct: syn::Ident,
	/// This is a list of the callable functions exposed by this pallet. See `CallVariantDef`.
	pub methods: Vec<CallVariantDef>,
}

/// This is the metadata we keep about each callable function in our pallet.
#[derive(Debug)]
pub struct CallVariantDef {
	/// The function name.
	pub name: syn::Ident,
	/// Information on args of the function: `(name, type)`.
	pub args: Vec<(syn::Ident, Box<syn::Type>)>,
}

impl CallDef {
	pub fn try_from(item: syn::Item) -> syn::Result<Self> {
		// First we check that we are parsing an `impl`.
		let item_impl = if let syn::Item::Impl(item) = item {
			item
		} else {
			return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl"))
		};

		// Extract the name of the struct. We mostly assume it is `Pallet`, but we can handle it
		// when it isn't.
		let pallet_struct = match &*item_impl.self_ty {
			syn::Type::Path(tp) => tp.path.segments.first().unwrap().ident.clone(),
			_ => panic!("not supported tokens"),
		};

		// Here is where we will store all the callable functions.
		let mut methods = vec![];
		for item in item_impl.items {
			if let syn::ImplItem::Fn(method) = item {
				// Here is where we will store all the args for each callable functions.
				let mut args = vec![];

				// First argument should be some variant of `self`.
				match method.sig.inputs.first() {
					Some(syn::FnArg::Receiver(_)) => {},
					_ => {
						let msg = "Invalid call, first argument must be a variant of self";
						return Err(syn::Error::new(method.sig.span(), msg))
					},
				}

				// The second argument should be the `caller: T::AccountId` argument.
				match method.sig.inputs.iter().skip(1).next() {
					Some(syn::FnArg::Typed(arg)) => {
						// Here we specifically check that this argument is as we expect for
						// `caller: T::AccountId`.
						check_caller_arg(arg)?;
					},
					_ => {
						let msg = "Invalid call, second argument should be `caller: T::AccountId`";
						return Err(syn::Error::new(method.sig.span(), msg))
					},
				}

				let fn_name = method.sig.ident.clone();

				// Parsing the rest of the args. Skipping 2 for `self` and `caller`.
				for arg in method.sig.inputs.iter().skip(2) {
					// All arguments should be typed.
					let arg = if let syn::FnArg::Typed(arg) = arg {
						arg
					} else {
						unreachable!("All args should be typed.");
					};

					// Extract the name of the argument.
					let arg_ident = if let syn::Pat::Ident(pat) = &*arg.pat {
						pat.ident.clone()
					} else {
						let msg = "Invalid pallet::call, argument must be ident";
						return Err(syn::Error::new(arg.pat.span(), msg))
					};

					// Store the argument name and the argument type for generating code.
					args.push((arg_ident, arg.ty.clone()));
				}

				// Store all the function name and the arg data for the function.
				methods.push(CallVariantDef { name: fn_name, args });
			}
		}

		// Return all callable functions for this pallet.
		Ok(Self { pallet_struct, methods })
	}
}

/// Check caller arg is exactly: `caller: T::AccountId`.
///
/// This is kept strict to keep the code simple.
pub fn check_caller_arg(arg: &syn::PatType) -> syn::Result<()> {
	pub struct CheckDispatchableFirstArg;
	impl syn::parse::Parse for CheckDispatchableFirstArg {
		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
			input.parse::<keyword::T>()?;
			input.parse::<syn::Token![::]>()?;
			input.parse::<keyword::AccountId>()?;
			Ok(Self)
		}
	}

	// This checks the arg name is `caller` or `_caller`.
	if let syn::Pat::Ident(ident) = &*arg.pat {
		// We also support the name as `_caller` for when the variable is unused.
		if &ident.ident != "caller" && &ident.ident != "_caller" {
			let msg = "Invalid name for second parameter: expected `caller: T::AccountId`";
			return Err(syn::Error::new(ident.span(), msg))
		}
	}

	// This checks the type is `T::AccountId` with `CheckDispatchableFirstArg`
	let ty = &arg.ty;
	syn::parse2::<CheckDispatchableFirstArg>(ty.to_token_stream()).map_err(|e| {
		let msg = "Invalid type for second parameter: expected `caller: T::AccountId`";
		let mut err = syn::Error::new(ty.span(), msg);
		err.combine(e);
		err
	})?;

	Ok(())
}
}
#![allow(unused)]
fn main() {
mod call;
mod runtime;

#[proc_macro_attribute]
pub fn call(
	attr: proc_macro::TokenStream,
	item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
	call::call(attr, item)
}

/// Expand the `Runtime` definition.
///
/// This generates function implementations on `Runtime`:
/// - `fn new()` - which generates a new instance of the runtime, by instantiating all the pallets
///   included in the runtime.
/// - `fn execute_block()` - which handles basic logic for executing a block of extrinsics. It does
///   basic actions like incrementing the block number and checking the block to be executed has a
///   valid block number.
///
/// This also generates code needed for dispatching calls to the pallets:
/// - Note: For simplicity, we assume that the system pallet is not callable.
/// - `enum RuntimeCall` - an "outer"-enum representing the accumulation of all possible calls to
///   all pallets. The system pallet is not included.
/// - implements the trait `support::Dispatch` to dispatch calls to the appropriate pallet. Basic
///   logic like incrementing the nonce of the user is included in the generated code. The system
///   pallet is not included.
#[proc_macro_attribute]
pub fn runtime(
	attr: proc_macro::TokenStream,
	item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
	runtime::runtime(attr, item)
}
}
#![allow(unused)]
fn main() {
use super::parse::RuntimeDef;
use quote::quote;

/// See the `fn runtime` docs at the `lib.rs` of this crate for a high level definition.
pub fn expand_runtime(def: RuntimeDef) -> proc_macro2::TokenStream {
	let RuntimeDef { runtime_struct, pallets } = def;

	// This is a vector of all the pallet names, not including system.
	let pallet_names = pallets.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>();
	// This is a vector of all the pallet types, not including system.
	let pallet_types = pallets.iter().map(|(_, type_)| type_.clone()).collect::<Vec<_>>();

	// This quote block implements functions on the `Runtime` struct.
	let runtime_impl = quote! {
		impl #runtime_struct {
			// Create a new instance of the main Runtime, by creating a new instance of each pallet.
			fn new() -> Self {
				Self {
					// Since system is not included in the list of pallets, we manually add it here.
					system: <system::Pallet::<Self>>::new(),
					(
						pallet_names: <#pallet_types>::new()
					),*
				}
			}

			// Execute a block of extrinsics. Increments the block number.
			fn execute_block(&mut self, block: types::Block) -> crate::support::DispatchResult {
				self.system.inc_block_number();
				if block.header.block_number != self.system.block_number() {
					return Err(&"block number does not match what is expected")
				}
				for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
					self.system.inc_nonce(&caller);
					let _res = self.dispatch(caller, call).map_err(|e| {
						eprintln!(
							"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
							block.header.block_number, i, e
						)
					});
				}
				Ok(())
			}
		}
	};

	// This quote block implements the `RuntimeCall` enum and implements the `Dispatch` trait.
	let dispatch_impl = quote! {
		// These are all the calls which are exposed to the world.
		// Note that it is just an accumulation of the calls exposed by each pallet.
		//
		// The parsed function names will be `snake_case`, and that will show up in the enum.
		#[allow(non_camel_case_types)]
		pub enum RuntimeCall {
			( #pallet_names(#pallet_names::Call<#runtime_struct>) ),*
		}

		impl crate::support::Dispatch for #runtime_struct {
			type Caller = <Runtime as system::Config>::AccountId;
			type Call = RuntimeCall;
			// Dispatch a call on behalf of a caller. Increments the caller's nonce.
			//
			// Dispatch allows us to identify which underlying pallet call we want to execute.
			// Note that we extract the `caller` from the extrinsic, and use that information
			// to determine who we are executing the call on behalf of.
			fn dispatch(
				&mut self,
				caller: Self::Caller,
				runtime_call: Self::Call,
			) -> crate::support::DispatchResult {
				// This match statement will allow us to correctly route `RuntimeCall`s
				// to the appropriate pallet level call.
				match runtime_call {
					(
						RuntimeCall::#pallet_names(call) => {
							self.#pallet_names.dispatch(caller, call)?;
						}
					),*
				}
				Ok(())
			}
		}
	};

	// We combine and return all the generated code.
	quote! {
		dispatch_impl
		runtime_impl
	}
	.into()
}
}
#![allow(unused)]
fn main() {
pub mod expand;
pub mod parse;

/// See the `fn runtime` docs at the `lib.rs` of this crate for a high level definition.
pub fn runtime(
	_attr: proc_macro::TokenStream,
	item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
	// The final expanded code will be placed here.
	// Since our macro only adds new code, our final product will contain all of our old code too,
	// hence we clone `item`.
	let mut finished = item.clone();
	let item_mod = syn::parse_macro_input!(item as syn::Item);

	// First we parse the `Runtime` struct...
	let generated: proc_macro::TokenStream = match parse::RuntimeDef::try_from(item_mod.clone()) {
		// ..then we generate our new code.
		Ok(def) => expand::expand_runtime(def).into(),
		Err(e) => e.to_compile_error().into(),
	};

	// Add our generated code to the end, and return the final result.
	finished.extend(generated);
	return finished;
}
}
#![allow(unused)]
fn main() {
use syn::spanned::Spanned;

/// This object will collect all the information we need to keep while parsing the `Runtime` struct.
#[derive(Debug)]
pub struct RuntimeDef {
	/// This is the name of the struct used by the user. We mostly assume it is `Runtime`.
	pub runtime_struct: syn::Ident,
	/// This is the list of pallets included in the `Runtime` struct. We omit `system` from this
	/// list, but during parsing we check that system exists.
	pub pallets: Vec<(syn::Ident, syn::Type)>,
}

impl RuntimeDef {
	pub fn try_from(item: syn::Item) -> syn::Result<Self> {
		// First we check that we are parsing a `struct`.
		let item_struct = if let syn::Item::Struct(item) = item {
			item
		} else {
			return Err(syn::Error::new(item.span(), "Invalid runtime, expected item struct"))
		};

		// We check that the `Runtime` includes the `system` pallet as the first item.
		check_system(&item_struct)?;

		let runtime_struct = item_struct.ident;

		// Here is where we will store a list of all the pallets.
		let mut pallets = vec![];
		// We skip `system`, which we ensure is the first field in `check_system`.
		for field in item_struct.fields.into_iter().skip(1) {
			if let Some(ident) = field.ident {
				pallets.push((ident, field.ty))
			}
		}

		Ok(Self { runtime_struct, pallets })
	}
}

/// This function checks that the `system` pallet is the first pallet included in the `Runtime`
/// struct. We make many assumptions about the `system` pallet in order to keep these macros simple.
/// For example, we assume that the system pallet has no callable functions, and that it contains
/// specific functions like incrementing the block number and a user's nonce.
///
/// You can consider these macros to be tightly coupled to the logic of the `system` pallet.
fn check_system(item_struct: &syn::ItemStruct) -> syn::Result<()> {
	// Extract the name of the first field in the `Runtime` struct.
	let first_field_name = if let Some(first_field) = item_struct.fields.iter().next() {
		if let Some(field_name) = &first_field.ident {
			field_name.to_string()
		} else {
			let msg = "first field is expected to have the name system";
			return Err(syn::Error::new(item_struct.span(), msg))
		}
	} else {
		let msg = "runtime struct is expected to have fields";
		return Err(syn::Error::new(item_struct.span(), msg))
	};

	// Check if the first field is named "system"
	if first_field_name != "system" {
		let msg = "first field is expected to be named system";
		return Err(syn::Error::new(item_struct.span(), msg))
	}

	Ok(())
}
}
diff --git a/Cargo.toml b/Cargo.toml
index 42b80bf8..e8026e22 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2021"
 
 [dependencies]
 num = "0.4.1"
+# TODO: Import the `macros` crate from the path `./macros/`.
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
new file mode 100644
index 00000000..1091d4ca
--- /dev/null
+++ b/macros/src/lib.rs
@@ -0,0 +1 @@
+/* TODO: Download the provided `macros` folder, and copy the content into your project. */
diff --git a/Cargo.lock b/Cargo.lock
index 10ded84b..42a43aff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,6 +8,15 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "num"
 version = "0.4.1"
@@ -84,9 +93,45 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "proc-macro2"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
 [[package]]
 name = "rust-state-machine"
 version = "0.1.0"
 dependencies = [
+ "macros",
  "num",
 ]
+
+[[package]]
+name = "syn"
+version = "2.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/Cargo.toml b/Cargo.toml
index e8026e22..dae8475c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
 
 [dependencies]
 num = "0.4.1"
-# TODO: Import the `macros` crate from the path `./macros/`.
+macros = { path = "./macros/" }
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
new file mode 100644
index 00000000..12bf2a98
--- /dev/null
+++ b/macros/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "macros"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0.69"
+quote = "1.0.33"
+syn = { version = "2.0.39", features = ["full", "extra-traits"] }
diff --git a/macros/src/call/expand.rs b/macros/src/call/expand.rs
new file mode 100644
index 00000000..64355274
--- /dev/null
+++ b/macros/src/call/expand.rs
@@ -0,0 +1,64 @@
+use super::parse::CallDef;
+use quote::quote;
+
+/// See the `fn call` docs at the `lib.rs` of this crate for a high level definition.
+pub fn expand_call(def: CallDef) -> proc_macro2::TokenStream {
+	let CallDef { pallet_struct, methods } = def;
+
+	// This is a vector of all the callable function names.
+	let fn_name = methods.iter().map(|method| &method.name).collect::<Vec<_>>();
+
+	// This is a nested vector of all the arguments for each of the functions in `fn_name`. It does
+	// not include the `self` or `caller: T::AccountId` parameter, which we always assume are the
+	// first two parameters to these calls.
+	let args_name = methods
+		.iter()
+		.map(|method| method.args.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>())
+		.collect::<Vec<_>>();
+
+	// This is a nested vector of all the types for all the arguments for each of the functions in
+	// `fn_name`. It has the same assumptions as `args_name`.
+	let args_type = methods
+		.iter()
+		.map(|method| method.args.iter().map(|(_, type_)| type_.clone()).collect::<Vec<_>>())
+		.collect::<Vec<_>>();
+
+	// This quote block creates an `enum Call` which contains all the calls exposed by our pallet,
+	// and the `Dispatch` trait logic to route a `caller` to access those functions.
+	let dispatch_impl = quote! {
+		// The callable functions exposed by this pallet.
+		//
+		// The parsed function names will be `snake_case`, and that will show up in the enum.
+		#[allow(non_camel_case_types)]
+		pub enum Call<T: Config> {
+			#(
+				#fn_name { #( #args_name: #args_type),* },
+			)*
+		}
+
+		// Dispatch logic at the pallet level, mapping each of the items in the `Call` enum to the
+		// appropriate function call with all arguments, including the `caller`.
+		impl<T: Config> crate::support::Dispatch for #pallet_struct<T> {
+			type Caller = T::AccountId;
+			type Call = Call<T>;
+
+			fn dispatch(&mut self, caller: Self::Caller, call: Self::Call) -> crate::support::DispatchResult {
+				match call {
+					#(
+						Call::#fn_name { #( #args_name ),* } => {
+							self.#fn_name(
+								// Note that we assume the first argument of every call is the `caller`.
+								caller,
+								#( #args_name ),*
+							)?;
+						},
+					)*
+				}
+				Ok(())
+			}
+		}
+	};
+
+	// Return the generated code.
+	dispatch_impl.into()
+}
diff --git a/macros/src/call/mod.rs b/macros/src/call/mod.rs
new file mode 100644
index 00000000..ad18b179
--- /dev/null
+++ b/macros/src/call/mod.rs
@@ -0,0 +1,25 @@
+pub mod expand;
+pub mod parse;
+
+/// See the `fn call` docs at the `lib.rs` of this crate for a high level definition.
+pub fn call(
+	_attr: proc_macro::TokenStream,
+	item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+	// The final expanded code will be placed here.
+	// Since our macro only adds new code, our final product will contain all of our old code too,
+	// hence we clone `item`.
+	let mut finished = item.clone();
+	let item_mod = syn::parse_macro_input!(item as syn::Item);
+
+	// First we parse the call functions implemented for the pallet...
+	let generated: proc_macro::TokenStream = match parse::CallDef::try_from(item_mod.clone()) {
+		// ..then we generate our new code.
+		Ok(def) => expand::expand_call(def).into(),
+		Err(e) => e.to_compile_error().into(),
+	};
+
+	// Add our generated code to the end, and return the final result.
+	finished.extend(generated);
+	return finished;
+}
diff --git a/macros/src/call/parse.rs b/macros/src/call/parse.rs
new file mode 100644
index 00000000..6ab3d192
--- /dev/null
+++ b/macros/src/call/parse.rs
@@ -0,0 +1,141 @@
+use quote::ToTokens;
+use syn::spanned::Spanned;
+
+// Custom keywords we match to when parsing the calls in a pallet.
+mod keyword {
+	syn::custom_keyword!(T);
+	syn::custom_keyword!(AccountId);
+}
+
+/// This object will collect all the information we need to keep while parsing the callable
+/// functions.
+#[derive(Debug)]
+pub struct CallDef {
+	/// This is the name of the pallet struct where the callable functions are implemented. We
+	/// mostly assume it is `Pallet`.
+	pub pallet_struct: syn::Ident,
+	/// This is a list of the callable functions exposed by this pallet. See `CallVariantDef`.
+	pub methods: Vec<CallVariantDef>,
+}
+
+/// This is the metadata we keep about each callable function in our pallet.
+#[derive(Debug)]
+pub struct CallVariantDef {
+	/// The function name.
+	pub name: syn::Ident,
+	/// Information on args of the function: `(name, type)`.
+	pub args: Vec<(syn::Ident, Box<syn::Type>)>,
+}
+
+impl CallDef {
+	pub fn try_from(item: syn::Item) -> syn::Result<Self> {
+		// First we check that we are parsing an `impl`.
+		let item_impl = if let syn::Item::Impl(item) = item {
+			item
+		} else {
+			return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl"))
+		};
+
+		// Extract the name of the struct. We mostly assume it is `Pallet`, but we can handle it
+		// when it isn't.
+		let pallet_struct = match &*item_impl.self_ty {
+			syn::Type::Path(tp) => tp.path.segments.first().unwrap().ident.clone(),
+			_ => panic!("not supported tokens"),
+		};
+
+		// Here is where we will store all the callable functions.
+		let mut methods = vec![];
+		for item in item_impl.items {
+			if let syn::ImplItem::Fn(method) = item {
+				// Here is where we will store all the args for each callable functions.
+				let mut args = vec![];
+
+				// First argument should be some variant of `self`.
+				match method.sig.inputs.first() {
+					Some(syn::FnArg::Receiver(_)) => {},
+					_ => {
+						let msg = "Invalid call, first argument must be a variant of self";
+						return Err(syn::Error::new(method.sig.span(), msg))
+					},
+				}
+
+				// The second argument should be the `caller: T::AccountId` argument.
+				match method.sig.inputs.iter().skip(1).next() {
+					Some(syn::FnArg::Typed(arg)) => {
+						// Here we specifically check that this argument is as we expect for
+						// `caller: T::AccountId`.
+						check_caller_arg(arg)?;
+					},
+					_ => {
+						let msg = "Invalid call, second argument should be `caller: T::AccountId`";
+						return Err(syn::Error::new(method.sig.span(), msg))
+					},
+				}
+
+				let fn_name = method.sig.ident.clone();
+
+				// Parsing the rest of the args. Skipping 2 for `self` and `caller`.
+				for arg in method.sig.inputs.iter().skip(2) {
+					// All arguments should be typed.
+					let arg = if let syn::FnArg::Typed(arg) = arg {
+						arg
+					} else {
+						unreachable!("All args should be typed.");
+					};
+
+					// Extract the name of the argument.
+					let arg_ident = if let syn::Pat::Ident(pat) = &*arg.pat {
+						pat.ident.clone()
+					} else {
+						let msg = "Invalid pallet::call, argument must be ident";
+						return Err(syn::Error::new(arg.pat.span(), msg))
+					};
+
+					// Store the argument name and the argument type for generating code.
+					args.push((arg_ident, arg.ty.clone()));
+				}
+
+				// Store all the function name and the arg data for the function.
+				methods.push(CallVariantDef { name: fn_name, args });
+			}
+		}
+
+		// Return all callable functions for this pallet.
+		Ok(Self { pallet_struct, methods })
+	}
+}
+
+/// Check caller arg is exactly: `caller: T::AccountId`.
+///
+/// This is kept strict to keep the code simple.
+pub fn check_caller_arg(arg: &syn::PatType) -> syn::Result<()> {
+	pub struct CheckDispatchableFirstArg;
+	impl syn::parse::Parse for CheckDispatchableFirstArg {
+		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+			input.parse::<keyword::T>()?;
+			input.parse::<syn::Token![::]>()?;
+			input.parse::<keyword::AccountId>()?;
+			Ok(Self)
+		}
+	}
+
+	// This checks the arg name is `caller` or `_caller`.
+	if let syn::Pat::Ident(ident) = &*arg.pat {
+		// We also support the name as `_caller` for when the variable is unused.
+		if &ident.ident != "caller" && &ident.ident != "_caller" {
+			let msg = "Invalid name for second parameter: expected `caller: T::AccountId`";
+			return Err(syn::Error::new(ident.span(), msg))
+		}
+	}
+
+	// This checks the type is `T::AccountId` with `CheckDispatchableFirstArg`
+	let ty = &arg.ty;
+	syn::parse2::<CheckDispatchableFirstArg>(ty.to_token_stream()).map_err(|e| {
+		let msg = "Invalid type for second parameter: expected `caller: T::AccountId`";
+		let mut err = syn::Error::new(ty.span(), msg);
+		err.combine(e);
+		err
+	})?;
+
+	Ok(())
+}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 1091d4ca..56a1bcf9 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -1 +1,34 @@
-/* TODO: Download the provided `macros` folder, and copy the content into your project. */
+mod call;
+mod runtime;
+
+#[proc_macro_attribute]
+pub fn call(
+	attr: proc_macro::TokenStream,
+	item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+	call::call(attr, item)
+}
+
+/// Expand the `Runtime` definition.
+///
+/// This generates function implementations on `Runtime`:
+/// - `fn new()` - which generates a new instance of the runtime, by instantiating all the pallets
+///   included in the runtime.
+/// - `fn execute_block()` - which handles basic logic for executing a block of extrinsics. It does
+///   basic actions like incrementing the block number and checking the block to be executed has a
+///   valid block number.
+///
+/// This also generates code needed for dispatching calls to the pallets:
+/// - Note: For simplicity, we assume that the system pallet is not callable.
+/// - `enum RuntimeCall` - an "outer"-enum representing the accumulation of all possible calls to
+///   all pallets. The system pallet is not included.
+/// - implements the trait `support::Dispatch` to dispatch calls to the appropriate pallet. Basic
+///   logic like incrementing the nonce of the user is included in the generated code. The system
+///   pallet is not included.
+#[proc_macro_attribute]
+pub fn runtime(
+	attr: proc_macro::TokenStream,
+	item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+	runtime::runtime(attr, item)
+}
diff --git a/macros/src/runtime/expand.rs b/macros/src/runtime/expand.rs
new file mode 100644
index 00000000..71ab3054
--- /dev/null
+++ b/macros/src/runtime/expand.rs
@@ -0,0 +1,91 @@
+use super::parse::RuntimeDef;
+use quote::quote;
+
+/// See the `fn runtime` docs at the `lib.rs` of this crate for a high level definition.
+pub fn expand_runtime(def: RuntimeDef) -> proc_macro2::TokenStream {
+	let RuntimeDef { runtime_struct, pallets } = def;
+
+	// This is a vector of all the pallet names, not including system.
+	let pallet_names = pallets.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>();
+	// This is a vector of all the pallet types, not including system.
+	let pallet_types = pallets.iter().map(|(_, type_)| type_.clone()).collect::<Vec<_>>();
+
+	// This quote block implements functions on the `Runtime` struct.
+	let runtime_impl = quote! {
+		impl #runtime_struct {
+			// Create a new instance of the main Runtime, by creating a new instance of each pallet.
+			fn new() -> Self {
+				Self {
+					// Since system is not included in the list of pallets, we manually add it here.
+					system: <system::Pallet::<Self>>::new(),
+					#(
+						#pallet_names: <#pallet_types>::new()
+					),*
+				}
+			}
+
+			// Execute a block of extrinsics. Increments the block number.
+			fn execute_block(&mut self, block: types::Block) -> crate::support::DispatchResult {
+				self.system.inc_block_number();
+				if block.header.block_number != self.system.block_number() {
+					return Err(&"block number does not match what is expected")
+				}
+				for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
+					self.system.inc_nonce(&caller);
+					let _res = self.dispatch(caller, call).map_err(|e| {
+						eprintln!(
+							"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
+							block.header.block_number, i, e
+						)
+					});
+				}
+				Ok(())
+			}
+		}
+	};
+
+	// This quote block implements the `RuntimeCall` enum and implements the `Dispatch` trait.
+	let dispatch_impl = quote! {
+		// These are all the calls which are exposed to the world.
+		// Note that it is just an accumulation of the calls exposed by each pallet.
+		//
+		// The parsed function names will be `snake_case`, and that will show up in the enum.
+		#[allow(non_camel_case_types)]
+		pub enum RuntimeCall {
+			#( #pallet_names(#pallet_names::Call<#runtime_struct>) ),*
+		}
+
+		impl crate::support::Dispatch for #runtime_struct {
+			type Caller = <Runtime as system::Config>::AccountId;
+			type Call = RuntimeCall;
+			// Dispatch a call on behalf of a caller. Increments the caller's nonce.
+			//
+			// Dispatch allows us to identify which underlying pallet call we want to execute.
+			// Note that we extract the `caller` from the extrinsic, and use that information
+			// to determine who we are executing the call on behalf of.
+			fn dispatch(
+				&mut self,
+				caller: Self::Caller,
+				runtime_call: Self::Call,
+			) -> crate::support::DispatchResult {
+				// This match statement will allow us to correctly route `RuntimeCall`s
+				// to the appropriate pallet level call.
+				match runtime_call {
+					#(
+						RuntimeCall::#pallet_names(call) => {
+							self.#pallet_names.dispatch(caller, call)?;
+						}
+					),*
+				}
+				Ok(())
+			}
+		}
+	};
+
+	// We combine and return all the generated code.
+	quote! {
+		#dispatch_impl
+		#runtime_impl
+	}
+	.into()
+}
diff --git a/macros/src/runtime/mod.rs b/macros/src/runtime/mod.rs
new file mode 100644
index 00000000..214c4dfe
--- /dev/null
+++ b/macros/src/runtime/mod.rs
@@ -0,0 +1,25 @@
+pub mod expand;
+pub mod parse;
+
+/// See the `fn runtime` docs at the `lib.rs` of this crate for a high level definition.
+pub fn runtime(
+	_attr: proc_macro::TokenStream,
+	item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+	// The final expanded code will be placed here.
+	// Since our macro only adds new code, our final product will contain all of our old code too,
+	// hence we clone `item`.
+	let mut finished = item.clone();
+	let item_mod = syn::parse_macro_input!(item as syn::Item);
+
+	// First we parse the `Runtime` struct...
+	let generated: proc_macro::TokenStream = match parse::RuntimeDef::try_from(item_mod.clone()) {
+		// ..then we generate our new code.
+		Ok(def) => expand::expand_runtime(def).into(),
+		Err(e) => e.to_compile_error().into(),
+	};
+
+	// Add our generated code to the end, and return the final result.
+	finished.extend(generated);
+	return finished;
+}
diff --git a/macros/src/runtime/parse.rs b/macros/src/runtime/parse.rs
new file mode 100644
index 00000000..9f1db8f2
--- /dev/null
+++ b/macros/src/runtime/parse.rs
@@ -0,0 +1,67 @@
+use syn::spanned::Spanned;
+
+/// This object will collect all the information we need to keep while parsing the `Runtime` struct.
+#[derive(Debug)]
+pub struct RuntimeDef {
+	/// This is the name of the struct used by the user. We mostly assume it is `Runtime`.
+	pub runtime_struct: syn::Ident,
+	/// This is the list of pallets included in the `Runtime` struct. We omit `system` from this
+	/// list, but during parsing we check that system exists.
+	pub pallets: Vec<(syn::Ident, syn::Type)>,
+}
+
+impl RuntimeDef {
+	pub fn try_from(item: syn::Item) -> syn::Result<Self> {
+		// First we check that we are parsing a `struct`.
+		let item_struct = if let syn::Item::Struct(item) = item {
+			item
+		} else {
+			return Err(syn::Error::new(item.span(), "Invalid runtime, expected item struct"))
+		};
+
+		// We check that the `Runtime` includes the `system` pallet as the first item.
+		check_system(&item_struct)?;
+
+		let runtime_struct = item_struct.ident;
+
+		// Here is where we will store a list of all the pallets.
+		let mut pallets = vec![];
+		// We skip `system`, which we ensure is the first field in `check_system`.
+		for field in item_struct.fields.into_iter().skip(1) {
+			if let Some(ident) = field.ident {
+				pallets.push((ident, field.ty))
+			}
+		}
+
+		Ok(Self { runtime_struct, pallets })
+	}
+}
+
+/// This function checks that the `system` pallet is the first pallet included in the `Runtime`
+/// struct. We make many assumptions about the `system` pallet in order to keep these macros simple.
+/// For example, we assume that the system pallet has no callable functions, and that it contains
+/// specific functions like incrementing the block number and a user's nonce.
+///
+/// You can consider these macros to be tightly coupled to the logic of the `system` pallet.
+fn check_system(item_struct: &syn::ItemStruct) -> syn::Result<()> {
+	// Extract the name of the first field in the `Runtime` struct.
+	let first_field_name = if let Some(first_field) = item_struct.fields.iter().next() {
+		if let Some(field_name) = &first_field.ident {
+			field_name.to_string()
+		} else {
+			let msg = "first field is expected to have the name system";
+			return Err(syn::Error::new(item_struct.span(), msg))
+		}
+	} else {
+		let msg = "runtime struct is expected to have fields";
+		return Err(syn::Error::new(item_struct.span(), msg))
+	};
+
+	// Check if the first field is named "system"
+	if first_field_name != "system" {
+		let msg = "first field is expected to be named system";
+		return Err(syn::Error::new(item_struct.span(), msg))
+	}
+
+	Ok(())
+}

Adding Call Macro to Balances

Let's start by adding the #[macros::call] macro to our Balances Pallet.

The Call Macro

The purpose of the #[macros::call] macro is to automatically generate the enum Call from the functions of the pallet and the pallet level Dispatch logic found in each Pallet.

We can place the #[macros::call] attribute over our impl<T: Config> Pallet<T> where the callable functions are implemented. From there, the macro can parse the whole object, and extract the data it needs. Not all of your functions are intended to be callable, so you can isolate the functions which should be in their own impl<T: Config> Pallet<T> as the template does.

Parse

In order to generate the code that we want, we need to keep track of:

  1. Each callable function that the developer wants to expose through the Runtime.
    1. The name of that function.
    2. The argument names and types of that function.
  2. The name of the struct where those functions are implemented. Normally this is Pallet, but we can allow the developer flexibility in their naming.

These things are tracked with CallDef and CallVariantDef.

Also, during the parsing process, we might want to check for certain consistencies in the code being parsed. In this case, we require that every callable function muse have caller as their first parameter with type T::AccountId. This should make sense to you since you have designed a number of different callable functions, and they all follow this pattern.

This checking logic is handled by fn check_caller_arg.

Expand

Once we have parsed all the data we need, generating the code is pretty straight forward.

If you jump down to let dispatch_impl = quote! you will see a bunch of code that looks like the templates we used earlier in the tutorial. We just left markers where the macro generation logic should place all the information to write the code we need.

Macro Quirks

Macros are often very "quirky" when you use them. Since all of the input going into the macro is other code, sometimes the format of that code might not match what you expect.

For example, the original Call enum we have constructed looks like:

#![allow(unused)]
fn main() {
pub enum Call<T: Config> {
	Transfer { to: T::AccountId, amount: T::Balance },
}
}

The variant is called Transfer because the function it represents is named fn transfer.

However, if we want to generate the Call enum, and we only have fn transfer, where will we get the specific string Transfer with a capital T?

It is possible to do string manipulation and adjust everything to make it consistent to what Rust expects, but in this case it is better for our macros to make minimal modifications to user written code.

What does this mean?

When the #[macros::call] macro generates our enum Call, it will actually look like this:

#![allow(unused)]
fn main() {
#[allow(non_camel_case_types)]
pub enum Call<T: Config> {
	transfer { to: T::AccountId, amount: T::Balance },
}
}

Here you see that transfer is exactly the string which comes from the name of the function. Normally all enum variants should be CamelCase, but since rust functions are snake_case, our enum will have variants which are also snake_case. We won't see any warnings about this because we enabled #[allow(non_camel_case_types)].

Ultimately, this has no significant impact on your underlying code. It is just ergonomics and expectations.

Indeed, macros can be quirky, but the amount of time they save you makes them worth it.

Time to Add Your Call Macro

  1. If you haven't, move your transfer function into its own impl<T: Config> Pallet<T>. We only want to apply the macro to this one function, so we need to isolate it from the other functions which are not meant to be callable.
  2. Add the #[macros::call] attribute over this new impl<T: Config> Pallet<T>.
  3. Delete your existing enum Call.
  4. Delete your existing implementation of Dispatch for Pallet.
  5. Then, in your main.rs file, change instances of balances::Call::Transfer to balances::Call::transfer with a lowercase t.

At this point, everything should compile just like before! We are witnessing the power of macros to generate code for us auto-magically!

#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}
}

/* TODO: Add the `#[macros::call]` attribute right here. */
impl<T: Config> Pallet<T> {
	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> crate::support::DispatchResult {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
/* TODO: Remove `enum Call`, this is being generated automatically by `#[macros::call]`. */
pub enum Call<T: Config> {
	Transfer { to: T::AccountId, amount: T::Balance },
}

/// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
/// function we want to execute.
/* TODO: Remove this `Dispatch` impl, this is also being generated by `#[macros::call]`. */
impl<T: Config> crate::support::Dispatch for Pallet<T> {
	type Caller = T::AccountId;
	type Call = Call<T>;

	fn dispatch(
		&mut self,
		caller: Self::Caller,
		call: Self::Call,
	) -> crate::support::DispatchResult {
		match call {
			Call::Transfer { to, amount } => {
				self.transfer(caller, to, amount)?;
			},
		}
		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				/* TODO: Update the enum name to match what is generated with the macro. */
				call: RuntimeCall::Balances(balances::Call::Transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use num::traits::{CheckedAdd, CheckedSub, Zero};
use std::collections::BTreeMap;

/// The configuration trait for the Balances Module.
/// Contains the basic types needed for handling balances.
pub trait Config: crate::system::Config {
	/// A type which can represent the balance of an account.
	/// Usually this is a large unsigned integer.
	type Balance: Zero + CheckedSub + CheckedAdd + Copy;
}

/// This is the Balances Module.
/// It is a simple module which keeps track of how much balance each account has in this state
/// machine.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	// A simple storage mapping from accounts to their balances.
	balances: BTreeMap<T::AccountId, T::Balance>,
}

impl<T: Config> Pallet<T> {
	// Create a new instance of the balances module.
	pub fn new() -> Self {
		Self { balances: BTreeMap::new() }
	}

	/// Set the balance of an account `who` to some `amount`.
	pub fn set_balance(&mut self, who: &T::AccountId, amount: T::Balance) {
		self.balances.insert(who.clone(), amount);
	}

	/// Get the balance of an account `who`.
	/// If the account has no stored balance, we return zero.
	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
		*self.balances.get(who).unwrap_or(&T::Balance::zero())
	}
}

#[macros::call]
impl<T: Config> Pallet<T> {
	/// Transfer `amount` from one account to another.
	/// This function verifies that `from` has at least `amount` balance to transfer,
	/// and that no mathematical overflows occur.
	pub fn transfer(
		&mut self,
		caller: T::AccountId,
		to: T::AccountId,
		amount: T::Balance,
	) -> crate::support::DispatchResult {
		let caller_balance = self.balance(&caller);
		let to_balance = self.balance(&to);

		let new_caller_balance = caller_balance.checked_sub(&amount).ok_or("Not enough funds.")?;
		let new_to_balance = to_balance.checked_add(&amount).ok_or("Overflow")?;

		self.balances.insert(caller, new_caller_balance);
		self.balances.insert(to, new_to_balance);

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	struct TestConfig;

	impl crate::system::Config for TestConfig {
		type AccountId = String;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	impl super::Config for TestConfig {
		type Balance = u128;
	}

	#[test]
	fn init_balances() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(balances.balance(&"alice".to_string()), 0);
		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.balance(&"alice".to_string()), 100);
		assert_eq!(balances.balance(&"bob".to_string()), 0);
	}

	#[test]
	fn transfer_balance() {
		let mut balances = super::Pallet::<TestConfig>::new();

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);

		balances.set_balance(&"alice".to_string(), 100);
		assert_eq!(balances.transfer("alice".to_string(), "bob".to_string(), 51), Ok(()));
		assert_eq!(balances.balance(&"alice".to_string()), 49);
		assert_eq!(balances.balance(&"bob".to_string()), 51);

		assert_eq!(
			balances.transfer("alice".to_string(), "bob".to_string(), 51),
			Err("Not enough funds.")
		);
	}
}
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/balances.rs b/src/balances.rs
index 947ad847..42d66d0f 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -34,7 +34,10 @@ impl<T: Config> Pallet<T> {
 	pub fn balance(&self, who: &T::AccountId) -> T::Balance {
 		*self.balances.get(who).unwrap_or(&T::Balance::zero())
 	}
+}
 
+/* TODO: Add the `#[macros::call]` attribute right here. */
+impl<T: Config> Pallet<T> {
 	/// Transfer `amount` from one account to another.
 	/// This function verifies that `from` has at least `amount` balance to transfer,
 	/// and that no mathematical overflows occur.
@@ -60,12 +63,14 @@ impl<T: Config> Pallet<T> {
 // A public enum which describes the calls we want to expose to the dispatcher.
 // We should expect that the caller of each call will be provided by the dispatcher,
 // and not included as a parameter of the call.
+/* TODO: Remove `enum Call`, this is being generated automatically by `#[macros::call]`. */
 pub enum Call<T: Config> {
 	Transfer { to: T::AccountId, amount: T::Balance },
 }
 
 /// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
 /// function we want to execute.
+/* TODO: Remove this `Dispatch` impl, this is also being generated by `#[macros::call]`. */
 impl<T: Config> crate::support::Dispatch for Pallet<T> {
 	type Caller = T::AccountId;
 	type Call = Call<T>;
diff --git a/src/main.rs b/src/main.rs
index d2e384e3..69ba65b5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -125,6 +125,7 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
+				/* TODO: Update the enum name to match what is generated with the macro. */
 				call: RuntimeCall::Balances(balances::Call::Transfer {
 					to: bob.clone(),
 					amount: 30,
diff --git a/src/balances.rs b/src/balances.rs
index 42d66d0f..68b2bb3a 100644
--- a/src/balances.rs
+++ b/src/balances.rs
@@ -36,7 +36,7 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
-/* TODO: Add the `#[macros::call]` attribute right here. */
+#[macros::call]
 impl<T: Config> Pallet<T> {
 	/// Transfer `amount` from one account to another.
 	/// This function verifies that `from` has at least `amount` balance to transfer,
@@ -60,35 +60,6 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
-// A public enum which describes the calls we want to expose to the dispatcher.
-// We should expect that the caller of each call will be provided by the dispatcher,
-// and not included as a parameter of the call.
-/* TODO: Remove `enum Call`, this is being generated automatically by `#[macros::call]`. */
-pub enum Call<T: Config> {
-	Transfer { to: T::AccountId, amount: T::Balance },
-}
-
-/// Implementation of the dispatch logic, mapping from `BalancesCall` to the appropriate underlying
-/// function we want to execute.
-/* TODO: Remove this `Dispatch` impl, this is also being generated by `#[macros::call]`. */
-impl<T: Config> crate::support::Dispatch for Pallet<T> {
-	type Caller = T::AccountId;
-	type Call = Call<T>;
-
-	fn dispatch(
-		&mut self,
-		caller: Self::Caller,
-		call: Self::Call,
-	) -> crate::support::DispatchResult {
-		match call {
-			Call::Transfer { to, amount } => {
-				self.transfer(caller, to, amount)?;
-			},
-		}
-		Ok(())
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	struct TestConfig;
diff --git a/src/main.rs b/src/main.rs
index 69ba65b5..eb1e404d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -125,15 +125,14 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
-				/* TODO: Update the enum name to match what is generated with the macro. */
-				call: RuntimeCall::Balances(balances::Call::Transfer {
+				call: RuntimeCall::Balances(balances::Call::transfer {
 					to: bob.clone(),
 					amount: 30,
 				}),
 			},
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::Balances(balances::Call::Transfer { to: charlie, amount: 20 }),
+				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
 			},
 		],
 	};

Adding Call Macro to PoE

We have already seen the #[macros::call] macro help clean up the Balances Pallet.

Let's also add it to the Proof of Existence Pallet, where there is even more code that can be eliminated.

Add Your Call Macro

We basically need to repeat the steps that we did for the Balances Pallet here:

  1. Move your create_claim and revoke_claim functions into its own impl<T: Config> Pallet<T>.
  2. Add the #[macros::call] attribute over this new impl<T: Config> Pallet<T>.
  3. Delete your existing enum Call.
  4. Delete your existing implementation of Dispatch for Pallet.
  5. Then, in your main.rs file, change instances of:
    • proof_of_existence::Call::CreateClaim to proof_of_existence::Call::create_claim using snake_case.
    • proof_of_existence::Call::RevokeClaim to proof_of_existence::Call::revoke_claim using snake_case.

Check that everything is compiling and running just as before.

Expand your Rust Code

Let's take the opportunity to show you how you can peek deeper into what the macros are doing.

Rust provides the command cargo expand which allows you to output the generated rust code after all macros have been applied to your project.

To install cargo expand:

cargo install cargo-expand

Then, run the following command:

cargo expand > out.rs

This will output your project's generated code into a file out.rs.

Then take a look at that file.

Here are some things you should notice:

  • All of your different mod files have been combined together into a single file with your main.rs.

  • You will see that our final Pallet code has all of the Call and Dispatch logic generated!

  • You might notice that the very first #[derive(Debug)] macro has generated code

    #![allow(unused)]
    fn main() {
    #[automatically_derived]
    impl<T: ::core::fmt::Debug + Config> ::core::fmt::Debug for Pallet<T>
    where
        T::Content: ::core::fmt::Debug,
        T::AccountId: ::core::fmt::Debug,
    {
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::debug_struct_field1_finish(f, "Pallet", "claims", &&self.claims)
        }
    }
    }
  • You might even notice that other smaller macros like vec![] have changed:

    #![allow(unused)]
    fn main() {
    extrinsics: <[_]>::into_vec(
    	#[rustc_box]
    	::alloc::boxed::Box::new([
    		// stuff
    	])
    )
    }
  • And println!() :

    #![allow(unused)]
    fn main() {
    {
    	::std::io::_print(format_args!("{0:#?}\n", runtime));
    };
    }
  • etc...

There are two main takeaways for you:

  1. Macros ultimately follow all the same rules as regular Rust code, because it does generate regular Rust code. They feel magical, but there is really nothing magic about them.
  2. Macros are an important part of the Rust ecosystem, and heavily used to improve developer experience and code quality.

If you ever use externally developed macros, and you want to look closer at what is going on, cargo expand can be a useful tool for you to better understand some of the hidden architectural details of a project. As you jump into the Polkadot SDK, I recommend you continue to use this tool to enhance your learning and understanding.

mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
			},
		],
	};

	/* TODO: Update the extrinsics below for the updated format after the macros. */
	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

/* TODO: Add the `#[macros::call]` attribute here too. Make the changes needed to this pallet. */
impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		self.claims.get(claim)
	}

	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		if self.claims.contains_key(&claim) {
			return Err("this content is already claimed");
		}
		self.claims.insert(claim, caller);
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
		if caller != *owner {
			return Err("this content is owned by someone else");
		}
		self.claims.remove(&claim);
		Ok(())
	}
}

// A public enum which describes the calls we want to expose to the dispatcher.
// We should expect that the caller of each call will be provided by the dispatcher,
// and not included as a parameter of the call.
pub enum Call<T: Config> {
	CreateClaim { claim: T::Content },
	RevokeClaim { claim: T::Content },
}

/// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
/// function we want to execute.
impl<T: Config> crate::support::Dispatch for Pallet<T> {
	type Caller = T::AccountId;
	type Call = Call<T>;

	fn dispatch(
		&mut self,
		caller: Self::Caller,
		call: Self::Call,
	) -> crate::support::DispatchResult {
		match call {
			Call::CreateClaim { claim } => {
				self.create_claim(caller, claim)?;
			},
			Call::RevokeClaim { claim } => {
				self.revoke_claim(caller, claim)?;
			},
		}
		Ok(())
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		let mut poe = super::Pallet::<TestConfig>::new();
		assert_eq!(poe.get_claim(&"Hello, world!"), None);
		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
		assert_eq!(
			poe.create_claim("bob", "Hello, world!"),
			Err("this content is already claimed")
		);
		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
	}
}
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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 {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// 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>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::revoke_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
#![allow(unused)]
fn main() {
use crate::support::DispatchResult;
use core::fmt::Debug;
use std::collections::BTreeMap;

pub trait Config: crate::system::Config {
	/// The type which represents the content that can be claimed using this pallet.
	/// Could be the content directly as bytes, or better yet the hash of that content.
	/// We leave that decision to the runtime developer.
	type Content: Debug + Ord;
}

/// This is the Proof of Existence Module.
/// It is a simple module that allows accounts to claim existence of some data.
#[derive(Debug)]
pub struct Pallet<T: Config> {
	/// A simple storage map from content to the owner of that content.
	/// Accounts can make multiple different claims, but each claim can only have one owner.
	claims: BTreeMap<T::Content, T::AccountId>,
}

impl<T: Config> Pallet<T> {
	/// Create a new instance of the Proof of Existence Module.
	pub fn new() -> Self {
		Self { claims: BTreeMap::new() }
	}

	/// Get the owner (if any) of a claim.
	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
		self.claims.get(claim)
	}
}

#[macros::call]
impl<T: Config> Pallet<T> {
	/// Create a new claim on behalf of the `caller`.
	/// This function will return an error if someone already has claimed that content.
	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		if self.claims.contains_key(&claim) {
			return Err("this content is already claimed");
		}
		self.claims.insert(claim, caller);
		Ok(())
	}

	/// Revoke an existing claim on some content.
	/// This function should only succeed if the caller is the owner of an existing claim.
	/// It will return an error if the claim does not exist, or if the caller is not the owner.
	pub fn revoke_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
		let owner = self.get_claim(&claim).ok_or("claim does not exist")?;
		if caller != *owner {
			return Err("this content is owned by someone else");
		}
		self.claims.remove(&claim);
		Ok(())
	}
}

#[cfg(test)]
mod test {
	struct TestConfig;

	impl super::Config for TestConfig {
		type Content = &'static str;
	}

	impl crate::system::Config for TestConfig {
		type AccountId = &'static str;
		type BlockNumber = u32;
		type Nonce = u32;
	}

	#[test]
	fn basic_proof_of_existence() {
		let mut poe = super::Pallet::<TestConfig>::new();
		assert_eq!(poe.get_claim(&"Hello, world!"), None);
		assert_eq!(poe.create_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.get_claim(&"Hello, world!"), Some(&"alice"));
		assert_eq!(
			poe.create_claim("bob", "Hello, world!"),
			Err("this content is already claimed")
		);
		assert_eq!(poe.revoke_claim("alice", "Hello, world!"), Ok(()));
		assert_eq!(poe.create_claim("bob", "Hello, world!"), Ok(()));
	}
}
}
diff --git a/src/main.rs b/src/main.rs
index eb1e404d..902eb9ac 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -137,6 +137,7 @@ fn main() {
 		],
 	};
 
+	/* TODO: Update the extrinsics below for the updated format after the macros. */
 	let block_2 = types::Block {
 		header: support::Header { block_number: 2 },
 		extrinsics: vec![
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index 4e2e0ac7..f88d4398 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -18,6 +18,7 @@ pub struct Pallet<T: Config> {
 	claims: BTreeMap<T::Content, T::AccountId>,
 }
 
+/* TODO: Add the `#[macros::call]` attribute here too. Make the changes needed to this pallet. */
 impl<T: Config> Pallet<T> {
 	/// Create a new instance of the Proof of Existence Module.
 	pub fn new() -> Self {
diff --git a/src/main.rs b/src/main.rs
index 902eb9ac..9e1570c6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -137,19 +137,18 @@ fn main() {
 		],
 	};
 
-	/* TODO: Update the extrinsics below for the updated format after the macros. */
 	let block_2 = types::Block {
 		header: support::Header { block_number: 2 },
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},
 			support::Extrinsic {
 				caller: bob.clone(),
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},
@@ -161,13 +160,13 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice,
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::RevokeClaim {
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::revoke_claim {
 					claim: "Hello, world!",
 				}),
 			},
 			support::Extrinsic {
 				caller: bob,
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::CreateClaim {
+				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},
diff --git a/src/proof_of_existence.rs b/src/proof_of_existence.rs
index f88d4398..10aa7af7 100644
--- a/src/proof_of_existence.rs
+++ b/src/proof_of_existence.rs
@@ -18,7 +18,6 @@ pub struct Pallet<T: Config> {
 	claims: BTreeMap<T::Content, T::AccountId>,
 }
 
-/* TODO: Add the `#[macros::call]` attribute here too. Make the changes needed to this pallet. */
 impl<T: Config> Pallet<T> {
 	/// Create a new instance of the Proof of Existence Module.
 	pub fn new() -> Self {
@@ -29,7 +28,10 @@ impl<T: Config> Pallet<T> {
 	pub fn get_claim(&self, claim: &T::Content) -> Option<&T::AccountId> {
 		self.claims.get(claim)
 	}
+}
 
+#[macros::call]
+impl<T: Config> Pallet<T> {
 	/// Create a new claim on behalf of the `caller`.
 	/// This function will return an error if someone already has claimed that content.
 	pub fn create_claim(&mut self, caller: T::AccountId, claim: T::Content) -> DispatchResult {
@@ -53,37 +55,6 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
-// A public enum which describes the calls we want to expose to the dispatcher.
-// We should expect that the caller of each call will be provided by the dispatcher,
-// and not included as a parameter of the call.
-pub enum Call<T: Config> {
-	CreateClaim { claim: T::Content },
-	RevokeClaim { claim: T::Content },
-}
-
-/// Implementation of the dispatch logic, mapping from `POECall` to the appropriate underlying
-/// function we want to execute.
-impl<T: Config> crate::support::Dispatch for Pallet<T> {
-	type Caller = T::AccountId;
-	type Call = Call<T>;
-
-	fn dispatch(
-		&mut self,
-		caller: Self::Caller,
-		call: Self::Call,
-	) -> crate::support::DispatchResult {
-		match call {
-			Call::CreateClaim { claim } => {
-				self.create_claim(caller, claim)?;
-			},
-			Call::RevokeClaim { claim } => {
-				self.revoke_claim(caller, claim)?;
-			},
-		}
-		Ok(())
-	}
-}
-
 #[cfg(test)]
 mod test {
 	struct TestConfig;

Use the Runtime Macro

Finally, let's add the #[macros::runtime] macro to our main.rs file, and really clean up a ton of boilerplate code.

Runtime Macro

The purpose of the #[macros::runtime] macro is to get rid of all of the boilerplate function we implemented for the Runtime, including fn new() and fn execute_block(). Similar to the Call macro, it also generates the enum RuntimeCall and all the dispatch logic for re-dispatching to pallets.

We apply the #[macros::runtime] attribute on top of the main struct Runtime object.

Parse

In order to generate the code we want, we need to keep track of:

  1. The name of the struct representing our Runtime. Usually this is Runtime, but we provide flexibility to the developer.
  2. The list of Pallets included in our Runtime
    1. Their name, as specified by the user.
    2. The specific type for their Pallet, for example balances::Pallet vs proof_of_existence::Pallet.

All of this information is tracked in the RuntimeDef struct.

We are also checking that our Runtime definition always contains the System Pallet, and does so as the first pallet in our Runtime definition. We will explain more about the assumption of the macros below.

Expand

Once we have parsed all the data we need, we just need to generate the code that we expect.

Starting with let runtime_impl = quote!, you will see the entire impl Runtime code block has been swallowed into the macro. Since we know all the pallets in your Runtime, we can automatically implement functions like new(). The execute_block function does not take advantage of any of the parsed data, but the code is completely boilerplate, so we hide it away.

Then we have another code block being generated with let dispatch_impl = quote! which is the enum RuntimeCall and the implementation of Dispatch for Runtime.

Again, due to the quirks of using macros, our RuntimeCall enum will have snake_case variants which exactly match the name of the fields in the Runtime struct.

Macro Assumptions

One of the assumptions programmed into these macros is the existence of the System Pallet. For example, in the execute_block logic, we need access to both system.inc_block_number and system.inc_nonce.

Some macro level assumptions are intentional, and actually define the architectural decisions of the framework designing those macros. This is the case with the System Pallet, since so much of a blockchain framework depends on a consistent meta-layer.

Other assumptions exist just because it is easier to write the macro if the assumption is made.

The main takeaway here is that macros can almost always continue to improve, providing better and better user experiences for developers. It just needs someone to identify what improvements need to be made, and someone else to program those improvements into the low level macro code.

Add the Runtime Macro

Let's finally go through the steps to add the #[macros::runtime] attribute to your Runtime.

  1. In main.rs, add #[macros::runtime] on top of your pub struct Runtime.
  2. Remove the entire impl Runtime code block.
  3. Remove the entire enum RuntimeCall.
  4. Remove the entire implementation of Dispatch for Runtime.
  5. Update instances of the RuntimeCall enum to use snake_case:
    • Change RuntimeCall::Balances to RuntimeCall::balances.
    • Change RuntimeCall::ProofOfExistence to RuntimeCall::proof_of_existence.

And that's it! You have now completed the full tutorial for building a simple rust state machine. 🎉

mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// 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.
/* TODO: Remove the `RuntimeCall`. This is now generated by the `#[macros::runtime]`. */
pub enum RuntimeCall {
	Balances(balances::Call<Runtime>),
	ProofOfExistence(proof_of_existence::Call<Runtime>),
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use.
/* TODO: Add the `#[macros::runtime]` attribute here and remove duplicate code listed by TODOs. */
#[derive(Debug)]
pub struct Runtime {
	system: system::Pallet<Self>,
	balances: balances::Pallet<Self>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

/* TODO: Remove all this. It is now generated by the `#[macros::runtime]` attribute. */
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(),
			proof_of_existence: proof_of_existence::Pallet::new(),
		}
	}

	// Execute a block of extrinsics. Increments the block number.
	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
		self.system.inc_block_number();
		if block.header.block_number != self.system.block_number() {
			return Err("block number does not match what is expected");
		}
		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
		// result, and emit an error message if one is emitted.
		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
			self.system.inc_nonce(&caller);
			let _res = self.dispatch(caller, call).map_err(|e| {
				eprintln!(
					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
					block.header.block_number, i, e
				)
			});
		}
		Ok(())
	}
}

/* TODO: Remove all this too. Dispatch logic is auto-generated. */
impl crate::support::Dispatch for Runtime {
	type Caller = <Runtime as system::Config>::AccountId;
	type Call = RuntimeCall;
	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
	//
	// Dispatch allows us to identify which underlying module call we want to execute.
	// Note that we extract the `caller` from the extrinsic, and use that information
	// to determine who we are executing the call on behalf of.
	fn dispatch(
		&mut self,
		caller: Self::Caller,
		runtime_call: Self::Call,
	) -> support::DispatchResult {
		// This match statement will allow us to correctly route `RuntimeCall`s
		// to the appropriate pallet level function.
		match runtime_call {
			RuntimeCall::Balances(call) => {
				self.balances.dispatch(caller, call)?;
			},
			RuntimeCall::ProofOfExistence(call) => {
				self.proof_of_existence.dispatch(caller, call)?;
			},
		}
		Ok(())
	}
}

/* TODO: Update the extrinsics to match the automatically generated `RuntimeCall`. */
fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::revoke_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
mod balances;
mod proof_of_existence;
mod support;
mod system;

use crate::support::Dispatch;

// 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>;
	pub type Content = &'static str;
}

// This is our main Runtime.
// It accumulates all of the different pallets we want to use,
// functions implemented on the Runtime allow us to access those pallets and execute blocks of
// transactions.
#[derive(Debug)]
#[macros::runtime]
pub struct Runtime {
	system: system::Pallet<Self>,
	balances: balances::Pallet<Self>,
	proof_of_existence: proof_of_existence::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 proof_of_existence::Config for Runtime {
	type Content = types::Content;
}

// The main entry point for our simple state machine.
fn main() {
	// Create a new instance of the Runtime.
	// It will instantiate with it all the modules it uses.
	let mut runtime = Runtime::new();
	let alice = "alice".to_string();
	let bob = "bob".to_string();
	let charlie = "charlie".to_string();

	// Initialize the system with some initial balance.
	runtime.balances.set_balance(&alice, 100);

	// Here are the extrinsics in our block.
	// You can add or remove these based on the modules and calls you have set up.
	let block_1 = types::Block {
		header: support::Header { block_number: 1 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::balances(balances::Call::transfer {
					to: bob.clone(),
					amount: 30,
				}),
			},
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::balances(balances::Call::transfer { to: charlie, amount: 20 }),
			},
		],
	};

	let block_2 = types::Block {
		header: support::Header { block_number: 2 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice.clone(),
				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob.clone(),
				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	let block_3 = types::Block {
		header: support::Header { block_number: 3 },
		extrinsics: vec![
			support::Extrinsic {
				caller: alice,
				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::revoke_claim {
					claim: "Hello, world!",
				}),
			},
			support::Extrinsic {
				caller: bob,
				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
					claim: "Hello, world!",
				}),
			},
		],
	};

	// Execute the extrinsics which make up our blocks.
	// If there are any errors, our system panics, since we should not execute invalid blocks.
	runtime.execute_block(block_1).expect("invalid block");
	runtime.execute_block(block_2).expect("invalid block");
	runtime.execute_block(block_3).expect("invalid block");

	// Simply print the debug format of our runtime state.
	println!("{:#?}", runtime);
}
diff --git a/src/main.rs b/src/main.rs
index 9e1570c6..ab632aab 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,6 +21,7 @@ mod types {
 
 // 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.
+/* TODO: Remove the `RuntimeCall`. This is now generated by the `#[macros::runtime]`. */
 pub enum RuntimeCall {
 	Balances(balances::Call<Runtime>),
 	ProofOfExistence(proof_of_existence::Call<Runtime>),
@@ -28,6 +29,7 @@ pub enum RuntimeCall {
 
 // This is our main Runtime.
 // It accumulates all of the different pallets we want to use.
+/* TODO: Add the `#[macros::runtime]` attribute here and remove duplicate code listed by TODOs. */
 #[derive(Debug)]
 pub struct Runtime {
 	system: system::Pallet<Self>,
@@ -49,6 +51,7 @@ impl proof_of_existence::Config for Runtime {
 	type Content = types::Content;
 }
 
+/* TODO: Remove all this. It is now generated by the `#[macros::runtime]` attribute. */
 impl Runtime {
 	// Create a new instance of the main Runtime, by creating a new instance of each pallet.
 	fn new() -> Self {
@@ -80,6 +83,7 @@ impl Runtime {
 	}
 }
 
+/* TODO: Remove all this too. Dispatch logic is auto-generated. */
 impl crate::support::Dispatch for Runtime {
 	type Caller = <Runtime as system::Config>::AccountId;
 	type Call = RuntimeCall;
@@ -107,6 +111,7 @@ impl crate::support::Dispatch for Runtime {
 	}
 }
 
+/* TODO: Update the extrinsics to match the automatically generated `RuntimeCall`. */
 fn main() {
 	// Create a new instance of the Runtime.
 	// It will instantiate with it all the modules it uses.
diff --git a/src/main.rs b/src/main.rs
index ab632aab..6bb6513c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -19,18 +19,12 @@ mod types {
 	pub type Content = &'static str;
 }
 
-// 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.
-/* TODO: Remove the `RuntimeCall`. This is now generated by the `#[macros::runtime]`. */
-pub enum RuntimeCall {
-	Balances(balances::Call<Runtime>),
-	ProofOfExistence(proof_of_existence::Call<Runtime>),
-}
-
 // This is our main Runtime.
-// It accumulates all of the different pallets we want to use.
-/* TODO: Add the `#[macros::runtime]` attribute here and remove duplicate code listed by TODOs. */
+// It accumulates all of the different pallets we want to use,
+// functions implemented on the Runtime allow us to access those pallets and execute blocks of
+// transactions.
 #[derive(Debug)]
+#[macros::runtime]
 pub struct Runtime {
 	system: system::Pallet<Self>,
 	balances: balances::Pallet<Self>,
@@ -51,67 +45,7 @@ impl proof_of_existence::Config for Runtime {
 	type Content = types::Content;
 }
 
-/* TODO: Remove all this. It is now generated by the `#[macros::runtime]` attribute. */
-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(),
-			proof_of_existence: proof_of_existence::Pallet::new(),
-		}
-	}
-
-	// Execute a block of extrinsics. Increments the block number.
-	fn execute_block(&mut self, block: types::Block) -> support::DispatchResult {
-		self.system.inc_block_number();
-		if block.header.block_number != self.system.block_number() {
-			return Err("block number does not match what is expected");
-		}
-		// An extrinsic error is not enough to trigger the block to be invalid. We capture the
-		// result, and emit an error message if one is emitted.
-		for (i, support::Extrinsic { caller, call }) in block.extrinsics.into_iter().enumerate() {
-			self.system.inc_nonce(&caller);
-			let _res = self.dispatch(caller, call).map_err(|e| {
-				eprintln!(
-					"Extrinsic Error\n\tBlock Number: {}\n\tExtrinsic Number: {}\n\tError: {}",
-					block.header.block_number, i, e
-				)
-			});
-		}
-		Ok(())
-	}
-}
-
-/* TODO: Remove all this too. Dispatch logic is auto-generated. */
-impl crate::support::Dispatch for Runtime {
-	type Caller = <Runtime as system::Config>::AccountId;
-	type Call = RuntimeCall;
-	// Dispatch a call on behalf of a caller. Increments the caller's nonce.
-	//
-	// Dispatch allows us to identify which underlying module call we want to execute.
-	// Note that we extract the `caller` from the extrinsic, and use that information
-	// to determine who we are executing the call on behalf of.
-	fn dispatch(
-		&mut self,
-		caller: Self::Caller,
-		runtime_call: Self::Call,
-	) -> support::DispatchResult {
-		// This match statement will allow us to correctly route `RuntimeCall`s
-		// to the appropriate pallet level function.
-		match runtime_call {
-			RuntimeCall::Balances(call) => {
-				self.balances.dispatch(caller, call)?;
-			},
-			RuntimeCall::ProofOfExistence(call) => {
-				self.proof_of_existence.dispatch(caller, call)?;
-			},
-		}
-		Ok(())
-	}
-}
-
-/* TODO: Update the extrinsics to match the automatically generated `RuntimeCall`. */
+// The main entry point for our simple state machine.
 fn main() {
 	// Create a new instance of the Runtime.
 	// It will instantiate with it all the modules it uses.
@@ -130,14 +64,14 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::Balances(balances::Call::transfer {
+				call: RuntimeCall::balances(balances::Call::transfer {
 					to: bob.clone(),
 					amount: 30,
 				}),
 			},
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::Balances(balances::Call::transfer { to: charlie, amount: 20 }),
+				call: RuntimeCall::balances(balances::Call::transfer { to: charlie, amount: 20 }),
 			},
 		],
 	};
@@ -147,13 +81,13 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice.clone(),
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
+				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},
 			support::Extrinsic {
 				caller: bob.clone(),
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
+				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},
@@ -165,13 +99,13 @@ fn main() {
 		extrinsics: vec![
 			support::Extrinsic {
 				caller: alice,
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::revoke_claim {
+				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::revoke_claim {
 					claim: "Hello, world!",
 				}),
 			},
 			support::Extrinsic {
 				caller: bob,
-				call: RuntimeCall::ProofOfExistence(proof_of_existence::Call::create_claim {
+				call: RuntimeCall::proof_of_existence(proof_of_existence::Call::create_claim {
 					claim: "Hello, world!",
 				}),
 			},