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