In this tutorial, you'll see how to launch your own private local blockchain with trusted participants.
What you will learn:
- generate the keys required to authorize a node to participate in the network
- how to configure and share information about the network with other authorized accounts
- how to launch the network with an approved set of validators
Prerequisites:
- Install Rust
- Clone the substrate node template repository
Start basic nodes with default accounts (optional)
If you are familiar with substrate and running nodes using default accounts like alice
, you can skip to the next section.
Start a local node using the alice
account by running the following command:
./target/release/node-template \
--base-path /tmp/alice \
--chain local \
--alice \
--port 30333 \
--ws-port 9945 \
--rpc-port 9933 \
--node-key 0000000000000000000000000000000000000000000000000000000000000001 \
--telemetry-url "wss://telemetry.polkadot.io/submit/ 0" \
--validator
Start a second local node using the bob
account to connect to the local network:
./target/release/node-template \
--base-path /tmp/bob \
--chain local \
--bob \
--port 30334 \
--ws-port 9946 \
--rpc-port 9934 \
--telemetry-url "wss://telemetry.polkadot.io/submit/ 0" \
--validator \
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
The --bootnodes
option specifies the following information:
-
ip4
indicates that the IP address for the node uses the IPv4 format -
127.0.0.1
specifies the IP address for the running node -
tcp
specifies TCP as the protocol used for peer-to-peer communication -
30333
specifies the port number used for peer-to-peer communication -
12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
identifies the running node to communicate with for this network
You can validate that both nodes are now on the same network by:
- verifying the genesis block hash is the same for both node outputs
- the first local node discovered the second one
2023-01-09 17:21:08 discovered: 12D3KooWCzPnRRYHyVh2TQy2VaqmqxCkaFKGXhcscUhvJotrZsAE /ip4/10.0.0.144/tcp/30334
2023-01-09 17:21:08 discovered: 12D3KooWCzPnRRYHyVh2TQy2VaqmqxCkaFKGXhcscUhvJotrZsAE /ip4/10.1.43.0/tcp/30334
To purge local chain data, run the following command.
./target/release/node-template purge-chain --base-path /tmp/bob --chain local -y
Note that the base path will be different depending on which account was used to start the local node.
Launching private network blockchain
Adding trusted nodes
Adding trusted nodes to our network requires us to generate an account with keys for each node.
To generate a key using the node-template
, run the following command.
./target/debug/node-template key generate --scheme Sr25519 --password-interactive
Once you input your password, you should have a similar output:
Secret phrase: hen corn install jaguar spring pink neck squeeze account enough ahead bounce
Network ID: substrate
Secret seed: 0xd4883e547610a9543e1f68db1100833f3f57586b0e7a70437c84cb558ecd7cbe
Public key (hex): 0x42e88babfc903a7f3c12e576f52288144487f019ff9d2605df0f558c617a6909
Account ID: 0x42e88babfc903a7f3c12e576f52288144487f019ff9d2605df0f558c617a6909
Public key (SS58): 5DaS6dzomvqS3MpKcKgxz54GgEJje5Y11L1PHjyeMVniBrEM
SS58 Address: 5DaS6dzomvqS3MpKcKgxz54GgEJje5Y11L1PHjyeMVniBrEM
Polkadot uses sr25519 for its key derivation and signing algorithm.
The aura
consensus protocol (proof of authority) will use the sr25519
public key 5DaS6dzomvqS3MpKcKgxz54GgEJje5Y11L1PHjyeMVniBrEM
Note: The Substrate node template uses a proof of authority consensus model also referred to as authority round or Aura consensus. The **Aura consensus protocol* limits block production to a rotating list of authorized accounts. The authorized accounts—authorities—create blocks in a round robin fashion and are generally considered to be trusted participants in the network.*
Since grandpa
uses Ed25519 as its key format, we will also derive the public key using the following command:
Use the secret phrase that was generated for you in the previous command.
./target/debug/node-template key inspect --password-interactive --scheme Ed25519 "hen corn install jaguar spring pink neck squeeze account enough ahead bounce"
Output:
Secret phrase: hen corn install jaguar spring pink neck squeeze account enough ahead bounce
Network ID: substrate
Secret seed: 0xd4883e547610a9543e1f68db1100833f3f57586b0e7a70437c84cb558ecd7cbe
Public key (hex): 0x128ea392292f8be6682543ee87e4b595e23c72015e848205f986e2d714fd68bf
Account ID: 0x128ea392292f8be6682543ee87e4b595e23c72015e848205f986e2d714fd68bf
Public key (SS58): 5CV36Gk8ckF66wjQCdZshY7wzJyZ84MZso6DmTJWYcriCzoG
SS58 Address: 5CV36Gk8ckF66wjQCdZshY7wzJyZ84MZso6DmTJWYcriCzoG
We have now the ed25519
public key 5CV36Gk8ckF66wjQCdZshY7wzJyZ84MZso6DmTJWYcriCzoG
from the output.
Make sure to save the output somewhere for later use from both commands.
Repeat this process for each node we would like to add to our network.
Now to trust these accounts as validators we need to create our chain specification. Instead of creating one from scratch, we will modify the existing one.
Generate the chain specification using the following command:
./target/debug/node-template build-spec --disable-default-bootnode --chain local > customSpec.json
Let's open up our chain specification and add our nodes as trusted participants for the network.
We need to modify the aura
configuration to have our sr25519
keys to specify that these nodes are block producers.
"aura": {
"authorities": [
"5DaS6dzomvqS3MpKcKgxz54GgEJje5Y11L1PHjyeMVniBrEM",
"5E4pr85gYVTc6kk4fQTa9keXaPh3Gnj5y9MWHQ4FN5ubxUv4"
]
},
Now we need to modify the grandpa
configuration to have our ed25519
keys to specify that these nodes have the authority to finalize blocks.
"grandpa": {
"authorities": [
["5CV36Gk8ckF66wjQCdZshY7wzJyZ84MZso6DmTJWYcriCzoG", 1],
["5CCr8YMJercfhvFaQ2z9pS3r6Pyf48mx9XFbuvFDamkfG524", 1]
]
},
The second value 1
we precise for each node is the vote weight. Each validator in this example has a weight of 1 vote.
Convert the chain specification to raw format
The raw chain specification includes the same information as the unconverted specification. However, the raw chain specification also contains encoded storage keys that the node uses to reference the data in its local storage. Distributing a raw chain specification ensures that each node stores the data using the proper storage keys.
./target/debug/node-template build-spec --chain=customSpec.json --raw --disable-default-bootnode > customSpecRaw.json
When creating a private blockchain network, only one person should be generating and sharing the raw chain specification file so all nodes are running using the same wasm.
Preparing to launch the private network
To continue, verify the following:
- You have generated or collected the account keys for at least two authority nodes/accounts.
- You have updated your custom chain specification to include the keys for block production (aura) and block finalization (grandpa).
- You have converted your custom chain specification to raw format and distributed the raw chain specification to the nodes participating in the private network.
Starting the first node
We need to begin by starting the first node otherwise known as the bootnode.
Start the first node using the custom raw chain specification we generated earlier:
./target/debug/node-template \
--base-path /tmp/node01 \
--chain ./customSpecRaw.json \
--port 30333 \
--ws-port 9945 \
--rpc-port 9933 \
--telemetry-url "wss://telemetry.polkadot.io/submit/ 0" \
--validator \
--rpc-methods Unsafe \
--name MyNode01 \
--password-interactive
Output:
2023-01-09 23:06:50 Substrate Node
2023-01-09 23:06:50 ✌️ version 4.0.0-dev-4ae6e26d2fc
2023-01-09 23:06:50 ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2023
2023-01-09 23:06:50 📋 Chain specification: iam Local Testnet
2023-01-09 23:06:50 🏷 Node name: MyNode01
2023-01-09 23:06:50 👤 Role: AUTHORITY
2023-01-09 23:06:50 💾 Database: RocksDb at /tmp/node01/chains/local_testnet/db/full
2023-01-09 23:06:50 ⛓ Native runtime: node-template-100 (node-template-1.tx1.au1)
2023-01-09 23:06:51 🔨 Initializing Genesis block/state (state: 0x0e5a…205a, header-hash: 0xd977…d9a1)
2023-01-09 23:06:51 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-01-09 23:06:52 Using default protocol ID "sup" because none is configured in the chain specs
2023-01-09 23:06:52 🏷 Local node identity is: 12D3KooWDFcrrRui3J9JJGXX92dBtUqqFhZZzViDJy4QJD6DCJPG
2023-01-09 23:06:52 💻 Operating system: macos
2023-01-09 23:06:52 💻 CPU architecture: aarch64
2023-01-09 23:06:52 📦 Highest known block at #0
2023-01-09 23:06:52 〽️ Prometheus exporter started at 127.0.0.1:9615
2023-01-09 23:06:52 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]
2023-01-09 23:06:52 Running JSON-RPC WS server: addr=127.0.0.1:9945, allowed origins=["http://localhost:*", "http://127.0.0.1:*", "https://localhost:*", "https://127.0.0.1:*", "https://polkadot.js.org"]
2023-01-09 23:06:58 💤 Idle (0 peers), best: #0 (0xd977…d9a1), finalized #0 (0xd977…d9a1), ⬇ 0 ⬆ 0
Some notable observations from the output:
- the chain specification being used is the custom chain specification you created and specified using the
--chain
command-line option. - the node is an authority because you started the node using the
--validator
command-line option. - the genesis block being initialized with the block hash
(state: 0x0e5a…205a, header-hash: 0xd977…d9a1)
. - the Local node identity for your node. In this example, the node identity is
12D3KooWDFcrrRui3J9JJGXX92dBtUqqFhZZzViDJy4QJD6DCJPG
.
Insert keys in node keystore
The node will not produce any blocks after starting the first node. We need to two types of keys to each of our nodes in the network.
For each node:
- Add the
aura
authority keys to enable block production. - Add the
grandpa
authority keys to enable block finalization.
Insert the aura
and grandpa
secret keys into the nodes keystore:
Make sure:
-
--base-path
matches the same path used for starting the node. In this example, the path is/tmp/node01
-
--chain
points to the raw chain specification file we generated earlier -
--suri
value can be either the secret phrase or the secret seed created for each node
./target/debug/node-template key insert \
--base-path /tmp/node01 \
--chain customSpecRaw.json \
--scheme Sr25519 \
--suri 0xd4883e547610a9543e1f68db1100833f3f57586b0e7a70437c84cb558ecd7cbe \
--password-interactive \
--key-type aura
./target/debug/node-template key insert \
--base-path /tmp/node01 \
--chain customSpecRaw.json \
--scheme Ed25519 \
--suri 0xd4883e547610a9543e1f68db1100833f3f57586b0e7a70437c84cb558ecd7cbe \
--password-interactive \
--key-type gran
Verify that the keys are in the keystore for node01
ls /tmp/node01/chains/local_testnet/keystore
Output:
6175726142e88babfc903a7f3c12e576f52288144487f019ff9d2605df0f558c617a6909
6772616e128ea392292f8be6682543ee87e4b595e23c72015e848205f986e2d714fd68bf
Now restart the node.
Start the second node
Run the following command to start the second node using the same raw chain specification:
./target/debug/node-template \
--base-path /tmp/node02 \
--chain ./customSpecRaw.json \
--port 30334 \
--ws-port 9946 \
--rpc-port 9934 \
--telemetry-url "wss://telemetry.polkadot.io/submit/ 0" \
--validator \
--rpc-methods Unsafe \
--name MyNode02 \
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWDFcrrRui3J9JJGXX92dBtUqqFhZZzViDJy4QJD6DCJPG \
--password-interactive
Make sure to replace the --bootnodes
node identity with the one you have running
Insert the secret keys like we did with the first node but this time in /tmp/node02
.
Follow the same steps here to configure the second node
Finally, Substrate nodes require a restart after inserting a grandpa
key, so you must shut down and restart nodes before you see blocks being finalized.
Restart both nodes in the right order and you should also see that each node has one peer (1 peers)
, and they have produced a block proposal (best: #2 (0xe111…c084))
. After a few seconds, you should see new blocks being finalized on both nodes finalized #1 (0x45a4…52d1)
Congratulations, you made it to the end!
Top comments (0)