# Gavin Wood's Substrate Demo at Web3 Summit **This tutorial officially lives here:** **---> https://substrate.readme.io/docs/creating-a-custom-substrate-chain <---** **Contents on this hackmd.io page may be out of date, so reference above.** ``` // initialise with: // post({sender: runtime.indices.ss58Decode('F7Gh'), call: calls.demo.setPayment(1000)}).tie(console.log) use parity_codec::Encode; use support::{StorageValue, dispatch::Result, decl_module, decl_storage}; use runtime_primitives::traits::{Zero, Hash, CheckedAdd, CheckedSub}; use system::ensure_signed; pub trait Trait: balances::Trait {} decl_storage! { trait Store for Module<T: Trait> as Demo { Payment get(payment): Option<T::Balance>; Pot get(pot): T::Balance; Nonce get(nonce): u64; } } decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { fn play(origin) -> Result { let sender = ensure_signed(origin)?; let payment = Self::payment().ok_or("Must have payment amount set")?; let mut nonce = Self::nonce(); let mut pot = Self::pot(); let mut sender_free_balance = <balances::Module<T>>::free_balance(&sender); sender_free_balance = sender_free_balance.checked_sub(&payment).ok_or("User does not have enough funds to play the game")?; if (<system::Module<T>>::random_seed(), &sender, nonce) .using_encoded(<T as system::Trait>::Hashing::hash) .using_encoded(|e| e[0] < 128) { sender_free_balance = sender_free_balance.checked_add(&pot).ok_or("Overflow when adding funds to user account")?; pot = Zero::zero(); } pot = pot.checked_add(&payment).ok_or("Overflow when adding funds to pot")?; nonce = nonce.wrapping_add(1); <balances::Module<T>>::set_free_balance(&sender, sender_free_balance); <Pot<T>>::put(pot); <Nonce<T>>::put(nonce); Ok(()) } fn set_payment(origin, value: T::Balance) -> Result { let _sender = ensure_signed(origin)?; if Self::payment().is_none() { <Payment<T>>::put(value); <Pot<T>>::put(value); } Ok(()) } } } ``` > Note: Substrate is a rapidly evolving project, which means that breaking changes may cause you problems when trying to follow the instructions below. Feel free to [contact us](https://www.parity.io/contact/) with any problems you encounter. This document will walk you through the steps required to duplicate the demo that [Gavin Wood presented at the 2018 Web3 Summit](https://youtu.be/0IoUZdDi5Is), showing off how you can build a Runtime Library for a Substrate Blockchain in less than 30 min. This tutorial will be written for a Mac OS X machine, and may require some finessing to get working on other operating systems. ## Prerequisites To start, we need to make sure you are able to run Substrate, which means installing Rust and other dependencies. This can be done with this simple one-liner (it may take a little while, so grab some tea): curl https://getsubstrate.io -sSf | sh You will also need to set up a few more repositories into your working folder which were used in the demo: * [Substrate Node Template](https://github.com/paritytech/substrate-node-template) * [Substrate UI](https://github.com/paritytech/substrate-ui) You can do that with some script aliases that were loaded on your machine: substrate-node-new substrate-node-template <author-name> substrate-ui-new substrate This will create a folder called `substrate-node-template` and `substrate-ui` with the corresponding repositories cloned in them. You can of course rename your projects in these commands, but for the sake of the clarity, we will continue with these folder names. ## Step 1: Launch a Blockchain If you have set up everything correctly, you can now start a substrate dev chain! In `substrate-node-template` run: ./target/release/substrate-node-template --dev > **Note:** If you run into an error like `Error: UnknownBlock: Unknown block Hash(...)`, you will need to purge the chain files on your computer. > > You can do that with: > > rm -rf ~/Library/Application\ Support/Substrate/chains/development/ > If everything is working it should start producing blocks! To interact with the blockchain, you need to start the Substrate UI. Navigate to the `substrate-ui` folder and run: npm run dev Finally, if open your browser to http://localhost:8000, you should be able to interact with your new chain! ## Step 2: Add Alice to your network Alice is a hard-coded account in the substrate system, which is pre-funded to make your life easier. Open a new terminal, and using the installed `substrate/subkey` package, you can retrieve the seed for this pre-funded account: subkey restore Alice > Seed > 0x416c696365202020202020202020202020202020202020202020202020202020 is account: > SS58: 5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ Hex: 0xd172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f Then in the Substrate UI, you can go into the `Wallet` section and add Alice using her `seed` and `name`. ![An image of adding Alice to your wallet](https://i.imgur.com/34xZZLL.png) If all is working correctly, you can now go into the `Send Funds` section and send funds from `Alice` to `Default`. You will see that Alice has a bunch of `units` pre-funded in her account, so send some and wait for the green checkmark and an updated balance for `Default` to show that the transfer has been successfully recorded on the blockchain. ![An image of sending funds from alice to your default account](https://i.imgur.com/8IIg292.png) ## Step 3: Create a new runtime module Now it's time to create our own runtime. Open up the `substrate-node-template` folder and create a new file: ./runtime/src/demo.rs This is where our new runtime module will live. Inline comments will hopefully give you insight to what the code is doing. First, we will need to import a few libraries at the top of our file: // Encoding library use parity_codec::Encode; // Enables access to the runtime storage use srml_support::{StorageValue, dispatch::Result}; // Enables us to do hashing use runtime_primitives::traits::Hash; // Enables access to account balances use {balances, system::{self, ensure_signed}}; All modules have a configuration trait, and we will specify that it requires the balances module (TODO: Add more details here) pub trait Trait: balances::Trait {} In this example, we will create a simple coin flip game. Users will pay an entry fee to play the game and then "flip a coin". If they win they will get the contents of the pot. If they don't win, they will get nothing. No matter the outcome, their fee will be placed into the pot after the game resolves for the next user to try and win. To build this game, we will need to create the module declaration. These are the entry points that we handle, and the macro below takes care of the marshalling of arguments and dispatch. You can learn more about `decl_module!` [here](TODO: Add link of new wiki page once committed). This game will have two entry points: one that lets us play the game, and one that lets us set the payment. decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { fn play(origin) -> Result { // Logic for playing the game } fn set_payment(_origin, value: T::Balance) -> Result { // Logic for setting the game payment } } } Now that we have established our module structure, we can add the logic which powers these functions. First, we will write the logic for playing our game: fn play(origin) -> Result { // Ensure we have a signed message, and derive the sender's account id from the signature let sender = ensure_signed(origin)?; // Here we grab the payment, and put it into a local variable. // We are able to use Self::payment() because we defined it in our decl_storage! macro above // If there is no payment, exit with an error message let payment = Self::payment().ok_or("Must have payment amount set")?; // First, we decrease the balance of the sender by the payment amount using the balances module <balances::Module<T>>::decrease_free_balance(&sender, payment)?; // Then we flip a coin by generating a random seed // We pass the seed with our sender's account id into a hash algorithm // Then we check if the first byte of the hash is less than 128 if (<system::Module<T>>::random_seed(), &sender) .using_encoded(<T as system::Trait>::Hashing::hash) .using_encoded(|e| e[0] < 128) { // If the sender wins the coin flip, we increase the sender's balance by the pot amount // `::take()` will also remove the pot amount from storage, which by default will give it a value of 0 <balances::Module<T>>::increase_free_balance_creating(&sender, <Pot<T>>::take()); } // No matter the outcome, we will add the original sender's payment back into the pot <Pot<T>>::mutate(|pot| *pot += payment); Ok(()) } Next we will set up logic for initializing the game with the initial payment: fn set_payment(_origin, value: T::Balance) -> Result { //If the payment has not been set... if Self::payment().is_none() { // ... we will set it to the value we passed in. <Payment<T>>::put(value); // We will also put that initial value into the pot for someone to win <Pot<T>>::put(value); } Ok(()) } Then we will create the storage declaration. Using the `decl_storage!` macro, we can define the module specific data entries to be stored on-chain. Learn more about this macro [here](https://github.com/paritytech/wiki/blob/master/decl_storage.md). decl_storage! { trait Store for Module<T: Trait> as Demo { Payment get(payment) config(): Option<T::Balance>; Pot get(pot): T::Balance; } } And that's it! This is how easy it can be to build new runtime modules. You can find a complete version of this file [here](https://github.com/paritytech/substrate-node-template/blob/gav-demo/runtime/src/demo.rs) to check your work. ## Step 4: Integrate our new module into our runtime To actually use our module, we need to tell our runtime that it exists. To do this we will be modifying the `./runtime/src/lib.rs` file: First, we need to declare that we are using the new demo module: ... extern crate srml_upgrade_key as upgrade_key; mod demo; // Add this line To keep track of this version of the blockchain, we can update our `spec_name` and `impl_name`: ... pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: ver_str!("demo"), // Update name to "demo" impl_name: ver_str!("demo-node"), // Update name to "demo-node" Next, we need to implement our configuration trait, which we can do at the end of all the other `impl` statements: ... impl upgrade_key::Trait for Runtime { type Event = Event; } impl demo::Trait for Runtime {} // Add this line Finally, we put our new module into the runtime construction macro, `construct_runtime!`: construct_runtime!( pub enum Runtime with Log(InternalLog: DigestItem<Hash, AuthorityId>) where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic { System: system::{default, Log(ChangesTrieRoot)}, Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent}, Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent}, Balances: balances, UpgradeKey: upgrade_key, Demo: demo::{Module, Call, Storage, Config<T>}, // Add this line } ); Again, you can find a complete version of this file [here](https://github.com/paritytech/substrate-node-template/blob/gav-demo/runtime/src/lib.rs). ## Step 5: Upgrade our chain Now that we have created a new runtime module, it's time for us to upgrade our blockchain. To do this, first we will need to build our new runtime. Go into `substrate-node-template` and run: ./build.sh If this completes successfully, it will update the following file: ./runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm You can go back to the Substrate UI, and in the `Runtime Upgrade` section, you can select this file and press `upgrade`. ![An image of a successful chain upgrade](https://i.imgur.com/c0O2Pnf.png) If all went well, you can see at the top of the Substrate UI that the `Runtime` will have our updated name! ![An image of an updated runtime name](https://i.imgur.com/PLe219L.png) ## Step 6: Interacting with our new module Finally, we can try and play the game we created. We will begin our interaction through the browser console. On the page with the Substrate UI, press *F12* to open your developer console. We will take advantage of some of the JavaScript libraries loaded on this page. Before we can play the game, we need to initialize the `set_payment` from an account. We will call the function on behalf of Alice, who will generously initialize the pot with a signed message. post({sender: runtime.balances.ss58Decode('F7Gh'), call: calls.demo.setPayment(1000)}).tie(console.log) ![An image of the setting the payment in the developer console](https://i.imgur.com/nl0h2Ei.png) When this call completed, you should see `{finalized: "..."}`, showing that it has been added to the chain. We can check this by reading the balance in the pot: runtime.demo.pot.then(console.log) Which should return `Number {1000}` ## Step 7: Updating our Substrate UI Now that we see things are working in the background, it's time to give our UI some new legs. Let's add an interface so that someone can play our game. To do this we will need to modify the `substrate-ui` repository. Open the `./src/app.jsx` file, and in the `readyRender()` function, you will see the code which generates all the different UX components. For example, this code snippet controls the Runtime Upgrade UX that we most recently interacted with: <Divider hidden /> <Segment style={{margin: '1em'}} padded> <Header as='h2'> <Icon name='search' /> <Header.Content> Runtime Upgrade <Header.Subheader>Upgrade the runtime using the UpgradeKey module</Header.Subheader> </Header.Content> </Header> <div style={{paddingBottom: '1em'}}></div> <FileUploadBond bond={this.runtime} content='Select Runtime' /> <TransactButton content="Upgrade" icon='warning' tx={{ sender: runtime.upgrade_key.key, call: calls.upgrade_key.upgrade(this.runtime) }} /> </Segment> We can use this as a template for how we should add our game's UX. After the last `</Segment>`, create a new one with the following code: ... </Segment> <Divider hidden /> <Segment style={{margin: '1em'}} padded> <Header as='h2'> <Icon name='game' /> <Header.Content> Play the game <Header.Subheader>Play the game here!</Header.Subheader> </Header.Content> </Header> <div style={{paddingBottom: '1em'}}> <div style={{fontSize: 'small'}}>player</div> <SignerBond bond={this.player}/> <If condition={this.player.ready()} then={<span> <Label>Balance <Label.Detail> <Pretty value={runtime.balances.balance(this.player)}/> </Label.Detail> </Label> </span>}/> </div> <TransactButton content="Play" icon='game' tx={{ sender: this.player, call: calls.demo.play() }} /> <Label>Pot Balance <Label.Detail> <Pretty value={runtime.demo.pot}/> </Label.Detail> </Label> </Segment> Beyond the updated text, you can see we are accessing a new `this.player` bond, which represents the user context playing the game. Using this, we can get details like the user's balance: runtime.balances.balance(this.player) And submit transactions on behalf of this user: tx={{ sender: this.player, call: calls.demo.play() }} Also notice that we are able to dynamically show content like the current balance of the pot in a similar way to how we retrieved it in the developer console: <Label>Pot Balance <Label.Detail> <Pretty value={runtime.demo.pot}/> </Label.Detail> </Label> The only thing left for us to do, is to create the new `player` bond in our `constructor()` function at the top of the same file: ... this.runtime = new Bond; this.player = new Bond; // Add this line If you save your changes and reload the page, you should see your new UX! You can now try playing the game with the `Default` user: ![An image of the player losing the game](https://i.imgur.com/sIspIKE.png) Here you can see the player lost the game, which means that their 1000 units got added to the pot, and an additional 1 unit transaction fee was taken from their balance. If we try a few more times, eventually the player will win the game, and the pot will be reset back to its starting amount for the next player: ![An image of the player winning the game](https://i.imgur.com/kqQIF3p.png) ## Final Notes That's all folks! While you can't actually make a profit playing this game, hopefully you see just how simple Substrate can make it to develop your next blockchain. In summary, we showed you how to: - Download and install `substrate` to your machine in a single command - Set up a fresh `substrate-node-template` and `substrate-ui` so that you can start hacking right away - Program a new runtime for your blockchain - Upgrade your runtime, in real time and without forking, via the `substrate-ui` - Update the `substrate-ui` to reflect your new runtime features and functionality Substrate is a rapidly developing technology, and we would love to get your feedback, answer questions, and learn more about what you want to build! Feel free to contact us using the details provided [here](https://www.parity.io/contact/).