공공 네트워크나 허락이 필요없는 블록체인은 누구나 네트워크에 참여할 수 있지만, permissioned network에서는 오직 권한이 있는 노드들만 특정 활동(e.g. validate blocks)이 가능함.
예를 들어서 private network나 규제를 받는 데이터인 경우(헬스케어처럼) 그리고 공공 네트워크를 테스트할 때도 사용할 수 있다.
이 pallet는 FRAME에 내장되어있다. 각각의 노드들은 Vec<u8>
타입을 가지는 'PeerId'로 구분되고 'peerId'는 'AccountId'에 의해 소유됌.
이 pallet으로 새로운 노드에게 권한을 부여하는 방법은 두 가지가 있다.
1. 연결이 허용된 잘 알려진 노드들의 집합에 참가하는 것.
2. 특정한 노드에게 paired peer 연결을 요청하는 것. 특정한 노드는 유명한 노드일 수도 있고 평범한 노드일 수도 있음.
PeerId와 관련된 노드는 오직 하나의 소유자를 가져야만 한다. 유명한 노드의 소유자는 추가될 때부터 명시되고, 일반적인 노드라면 어느 유저나 'PeerId'의 소유자임을 주장할 수 있기 때문에, false claim을 방지하기 위해 노드를 시작하기 전에 PeerId에 대한 소유권을 주장해야한다.
그러고 난 다음, 네트워크에 노드를 연결하거나 제거할 수 있음.
추가로, 유명한 노드 사이의 연결은 항상 서로 연결되어있기로 정해져서 변경할 수 없음.
반면에 유명한 노드와 일반 노드의 연결 혹은 일반 노드끼리의 연결은 조작가능.
노드가 가장 최근 블록과 동기화 되지 않을 수도 있기 때문에 이러한 경우에는 offchain worker를 무력화 시키고 수동으로 예약 노드를 설정해야할수도 있음.
substrate-node-template directory의 runtime/cargo.toml로 이동.
[dependencies.pallet-node-authorization]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
tag = 'devhub/latest'
version = '4.0.0-dev'
#--snip--
[features]
default = ['std']
std = [
#--snip--
'pallet-node-authorization/std',
#--snip--
]
sudo
admin rule을 허용한다./* --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-- */
마지막으로 construct_runtime! macro에 추가
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
NodeAuthorization: pallet_node_authorization, //이 줄 추가
RandomnessCollectiveFlip: pallet_randomness_collective_flip,
Timestamp: pallet_timestamp,
Aura: pallet_aura,
Grandpa: pallet_grandpa,
Balances: pallet_balances,
TransactionPayment: pallet_transaction_payment,
Sudo: pallet_sudo,
// Include the custom logic from the pallet-template in the runtime.
TemplateModule: pallet_template,
}
);
PeerId는 bs58로 인코딩 되어있다. bs58 라이브러리를 node/cargo.toml에 추가
[dependencies]
#--snip--
bs58 = "0.4.0"
#--snip--
그 다음 node/src/chain_spec.rs에 genesis storage를 추가한다.
먼저 필요한 dependencies를 import해주고
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.
testnet_genesis function에 아래 코드를 추가한다.
NodeAuthorizationConfig는 nodes
라는 tuple의 vector인 property를 포함한다.
tuple의 첫번째 element(OpaquePeerId)는 PeerId를 사람이 읽을 수 있는 형식에서 bytes 형식으로 변환하는 것이고, 두번째는(endowed_accounts) AccountId이다
여기서는 Alice와 Bob을 사용
/// 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-- */
}
Alice - well known node
# Node Key
c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a
# Peer ID, generated from node key
12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2
# BS58 decoded Peer ID in hex:
0x0024080112201ce5f00ef6e89374afb625f1ae4c1546d31234e87e3c3f51a62b91dd6bfa57df
Bob - well known node
# Node Key
6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58
# Peer ID, generated from node key
12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust
# BS58 decoded Peer ID in hex:
0x002408011220dacde7714d8551f674b8bb4b54239383c76a2b286fa436e93b2b7eb226bf4de7
Charlie - 일반 노드
# Node Key
3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e
# Peer ID, generated from node key
12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ
# BS58 decoded Peer ID in hex:
0x002408011220876a7b4984f98006dc8d666e28b60de307309835d775e7755cc770328cdacf2e
Dave의 sub-node
# Node Key
a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a
# Peer ID, generated from node key
12D3KooWPHWFrfaJzxPnqnAYAoRUyAHHKqACmEycGTVmeVhQYuZN
# BS58 decoded Peer ID in hex:
0x002408011220c81bc1d7057a1511eb9496f056f6f53cdfe0e14c8bd5ffca47c70a8d76c1326d
Alice와 Bob은 well-known이기 때문에 이미 genesis storage에 구성되었고,
Charlie 노드는 후에 well-known으로 추가할 것이다. 마지막으로 Charlie와 David의 노드 사이의 연결을 추가하는 것이 목표.
./target/release/node-template -h
을 통해서 확인할 수 있다../target/release/node-template \
--chain=local \
--base-path /tmp/validator1 \
--alice \
--node-key=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a \
--port 30333 \
--ws-port 9944
# 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
./target/release/node-template \
--chain=local \
--base-path /tmp/validator3 \
--name charlie \
--node-key=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e \
--port 30335 \
--ws-port=9946 \
--offchain-worker always
Polkadot.js를 이용하여 sudo pallet의 add_well_known_node를 통해 Charlie의 PeerId와 함께 submit하면 터미널에서 Charlie가 Alice, Bod에게 연결된 것을 확인할 수 있음.
./target/release/node-template \
--chain=local \
--base-path /tmp/validator4 \
--name dave \
--node-key=a99331ff4f0e0a0434a6263da0a5823ea3afcfffe590c9f3014e6cf620f2b19a \
--port 30336 \
--ws-port 9947 \
--offchain-worker always
Dave를 Charlie에게 연결하는 과정은 공식문서 참고
성공했을 경우 아래 결과를 확인 가능
2022-02-18 20:00:24 ✨ Imported #282 (0xc2d5…b6f3)