DEV Community

Cover image for 105 polkadot substrate : permissioned network
565.ee
565.ee

Posted on • Edited on

105 polkadot substrate : permissioned network

Introduction

Learning outcomes

Build the node template

Add the node-authorization pallet

Add genesis storage for our pallet

Obtaining Node Keys and PeerIDs

Alice and Bob Start the Network

Add charlie Node

Add Dave as a Sub-Node to Charlie

Substrate Tutorials , Substrate 教程

Contact 联系方式

• Introduction

In this tutorial, you will learn how to build a permissioned network with Substrate by using the node-authorization pallet. This tutorial should take you about 1 hour to complete.

You are probably already familiar with public or permissionless blockchain, where everyone is free to join the network by running a node. In a permissioned network, only authorized nodes are allowed to perform specific activities, like validate blocks and propagate transactions. Some examples of where permissioned blockchains may be desired:

• Private (or consortium) networks
• Highly regulated data environments (healthcare, B2B ledgers, etc.)
• Testing pre-public networks at scale

Before you start, we expect that:

• You have completed the Build a PoE Decentralized Application Tutorial.
• You are conceptually familiar with P2P Networking in Substrate. We recommend completing the Private Network Tutorial to get experience with this first.

• Learning outcomes

• Learn how to use the node-authorization pallet in your runtime
• Learn how to create a permissioned network consisting of multiple nodes

• Build the node template

• Clone the node template.

git clone https://github.com/substrate-developer-hub/substrate-node-template
# We want to use the `latest` tag throughout all of this tutorial
git checkout latest
Enter fullscreen mode Exit fullscreen mode

• Build the node template.

cd substrate-node-template/
cargo build --release
Enter fullscreen mode Exit fullscreen mode

• Add the node-authorization pallet

• First we must add the pallet to our runtime dependencies:
runtime/Cargo.toml

pallet-node-authorization = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.23" }

#--snip--
[features]
default = ['std']
std = [
    #--snip--
    'pallet-node-authorization/std',
    #--snip--
]
Enter fullscreen mode Exit fullscreen mode

• We need to simulate the governance in our simple blockchain, so we just let a sudo admin rule, configuring the pallet's interface to EnsureRoot. In a production environment we should want to have governance based checking implemented here.
runtime/src/lib.rs


/* --snip-- */

use frame_system::EnsureRoot;

/* --snip-- */

parameter_types! {
    pub const MaxWellKnownNodes: u32 = 8;
    pub const MaxPeerIdLength: u32 = 128;
}

impl pallet_node_authorization::Config for Runtime {
    type Event = Event;
    type MaxWellKnownNodes = MaxWellKnownNodes;
    type MaxPeerIdLength = MaxPeerIdLength;
    type AddOrigin = EnsureRoot<AccountId>;
    type RemoveOrigin = EnsureRoot<AccountId>;
    type SwapOrigin = EnsureRoot<AccountId>;
    type ResetOrigin = EnsureRoot<AccountId>;
    type WeightInfo = ();
}

/* --snip-- */
Enter fullscreen mode Exit fullscreen mode

• Finally, we are ready to put our pallet in construct_runtime macro with following extra line of code:
runtime/src/lib.rs

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        /* --snip-- */
        NodeAuthorization: pallet_node_authorization, // <-- add this line
        /* --snip-- */
    }
);
Enter fullscreen mode Exit fullscreen mode

• Add genesis storage for our pallet

• PeerId is encoded in bs58 format, so we need a new library bs58 in node/Cargo.toml to decode it to get its bytes.
node/cargo.toml

[dependencies]
#--snip--
bs58 = "0.4.0"
#--snip--
Enter fullscreen mode Exit fullscreen mode

• Now we add a proper genesis storage in node/src/chain_spec.rs. Similarly, import the necessary dependencies:
node/src/chain_spec.rs

/* --snip-- */
use sp_core::OpaquePeerId; // A struct wraps Vec<u8>, represents as our `PeerId`.
use node_template_runtime::NodeAuthorizationConfig; // The genesis config that serves for our pallet.
/* --snip-- */
Enter fullscreen mode Exit fullscreen mode

• Adding our genesis config in the helper function testnet_genesis,
node/src/chain_spec.rs

/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
    wasm_binary: &[u8],
    initial_authorities: Vec<(AuraId, GrandpaId)>,
    root_key: AccountId,
    endowed_accounts: Vec<AccountId>,
    _enable_println: bool,
) -> GenesisConfig {

        /* --snip-- */

    /*** Add This Block Item ***/
        node_authorization: NodeAuthorizationConfig {
            nodes: vec![
                (
                    OpaquePeerId(bs58::decode("12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2").into_vec().unwrap()),
                    endowed_accounts[0].clone()
                ),
                (
                    OpaquePeerId(bs58::decode("12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust").into_vec().unwrap()),
                    endowed_accounts[1].clone()
                ),
            ],
        },

    /* --snip-- */

}
Enter fullscreen mode Exit fullscreen mode

• Obtaining Node Keys and PeerIDs

• For Alice's well known node:

# Node Key
c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a

# Peer ID, generated from node key
12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2

# BS58 decoded Peer ID in hex:
0x0024080112201ce5f00ef6e89374afb625f1ae4c1546d31234e87e3c3f51a62b91dd6bfa57df
Enter fullscreen mode Exit fullscreen mode

• For Bob's well known node:

# Node Key
6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58

# Peer ID, generated from node key
12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust

# BS58 decoded Peer ID in hex:
0x002408011220dacde7714d8551f674b8bb4b54239383c76a2b286fa436e93b2b7eb226bf4de7
Enter fullscreen mode Exit fullscreen mode

• For Charlie's NOT well known node:

# Node Key
3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e

# Peer ID, generated from node key
12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ

# BS58 decoded Peer ID in hex:
0x002408011220876a7b4984f98006dc8d666e28b60de307309835d775e7755cc770328cdacf2e
Enter fullscreen mode Exit fullscreen mode

• For Dave's sub-node

# Node Key
a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a

# Peer ID, generated from node key
12D3KooWPHWFrfaJzxPnqnAYAoRUyAHHKqACmEycGTVmeVhQYuZN

# BS58 decoded Peer ID in hex:
0x002408011220c81bc1d7057a1511eb9496f056f6f53cdfe0e14c8bd5ffca47c70a8d76c1326d
Enter fullscreen mode Exit fullscreen mode

The nodes of Alice and Bob are already configured in genesis storage and serve as well known nodes. We will later add Charlie's node into the set of well known nodes. Finally we will add the connection between Charlie's node and Dave's node without making Dave's node as a well known node.

• Alice and Bob Start the Network

• Let's start Alice's node first:

./target/release/node-template \
--chain=local \
--base-path /tmp/validator1 \
--alice \
--node-key=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a \
--port 30333 \
--ws-port 9944
Enter fullscreen mode Exit fullscreen mode

• Start Bob's node:

# In a new terminal, leave Alice running
./target/release/node-template \
--chain=local \
--base-path /tmp/validator2 \
--bob \
--node-key=6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58 \
--port 30334 \
--ws-port 9945
Enter fullscreen mode Exit fullscreen mode

After both nodes are started, you should be able to see new blocks authored and finalized in bother terminal logs. Now let's use the polkadot.js apps and check the well known nodes of our blockchain. Don't forget to switch to one of our local nodes running: 127.0.0.1:9944 or 127.0.0.1:9945.

Then, let's go to Developer page, Chain State sub-tab, and check the data stored in the nodeAuthorization pallet, wellKnownNodes storage. You should be able to see the peer ids of Alice and Bob's nodes, prefixed with 0x to show its bytes in hex format.

We can also check the owner of one node by querying the storage owners with the peer id of the node as input, you should get the account address of the owner.

• Add charlie Node

• Let's start Charlie's node

./target/release/node-template \
--chain=local \
--base-path /tmp/validator3 \
--name charlie  \
--node-key=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e \
--port 30335 \
--ws-port=9946 \
--offchain-worker always
Enter fullscreen mode Exit fullscreen mode

• Go to Developer page, Sudo tab, in apps and submit the nodeAuthorization - add_well_known_node call with the peer id in hex of Charlie's node and the owner is Charlie, of course. Note Alice is the valid sudo origin for this call.
add_well_known_node

• Add Dave as a Sub-Node to Charlie

• Let's add Dave's node, not as a well-known node, but a "sub-node" of Charlie. Dave will only be able to connect to Charlie to access the network. This is a security feature: as Charlie is therefore solely responsible for any connected sub-node peer. There is one point of access control for David in case they need to be removed or audited.

Start Dave's node with following command:

./target/release/node-template \
--chain=local \
--base-path /tmp/validator4 \
--name dave \
--node-key=a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a \
--port 30336 \
--ws-port 9947 \
--offchain-worker always
Enter fullscreen mode Exit fullscreen mode

After it was started, there is no available connections. This is a permissioned network, so first, Charlie needs to configure his node to allow the connection from Dave's node.

In the Developer Extrinsics page, get Charlie to submit an addConnections extrinsic. The first PeerId is the peer id in hex of Charlie's node. The connections is a list of allowed peer ids for Charlie's node, here we only add Dave's.
charlie_add_connections

Then, Dave needs to configure his node to allow the connection from Charlie's node. But before he adds this, Dave needs to claim his node, hopefully it's not too late!
dave_claim_node

Similarly, Dave can add connection from Charlie's node.
dave_add_connections

You should now see Dave is catching up blocks and only has one peer which belongs to Charlie! Restart Dave's node in case it's not connecting with Charlie right away.

You are at the end of this tutorial and are already learned about how to build a permissioned network. You can also play with other dispatchable calls like remove_well_known_node, remove_connections.

• Substrate Tutorials , Substrate 教程

CN 中文 Github Substrate 教程 : github.com/565ee/Substrate_CN

CN 中文 CSDN Substrate 教程 : blog.csdn.net/wx468116118

EN 英文 Github Substrate Tutorials : github.com/565ee/Substrate_EN

EN 英文 dev.to Substrate Tutorials : dev.to/565ee

• Contact 联系方式

Homepage : 565.ee

GitHub : github.com/565ee

Email : 565.eee@gmail.com

Facebook : facebook.com/565.ee

Twitter : twitter.com/565_eee

Telegram : t.me/ee_565

Top comments (0)