Skip to content

Commit d4e14a1

Browse files
A0-4231: Refactor all keystore and chainspec generation to seprate module (#1687)
# Description Folow up after 5a8b1c3 This is 2nd out of 3 PRs to remove `aleph-runtime` dependency in `aleph-node`. In this PR: * The whole keystore and chainspec generation logic is moved to `chain_spec` module. This module will be extracted as a whole, with small adjustment, to a separate crate * `bootstrap-chain` command no longer supports `--faucet-account` switch. This is because only reason for it to exists was to set an initial endowment, exactly what `--rich-accounts` does. So it's suggested to migrate all `--faucet-accounts <account-id>` to `--rich-accounts <account-id>`. This is a breaking change, yet no impactful it's not used frequently. * `bootstrap-node` command is removed. This is because it was doing the same what `bootstrap-chain` does, which now have `--authorities-account-ids` switch to differentiate between RPC and validator nodes ## Type of change Please delete options that are not relevant. - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) # Checklist: * e2e tests: https://github.com/Cardinal-Cryptography/aleph-node/actions/runs/8706331881
1 parent acaab8c commit d4e14a1

File tree

15 files changed

+307
-465
lines changed

15 files changed

+307
-465
lines changed

.github/scripts/run_consensus.sh

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,15 @@ function generate_account_ids() {
7474

7575
function generate_chainspec() {
7676
local account_ids=("$@")
77-
78-
# First array element is RPC node, so not a validator
77+
local all_account_ids=${account_ids[@]}
78+
local account_ids_comma_separated="${all_account_ids//${IFS:0:1}/,}"
79+
# the first array element is RPC node, so not a validator
7980
local validators=${account_ids[@]:1}
80-
# comma separated ids
81-
validator_ids="${validators//${IFS:0:1}/,}"
82-
83-
echo "Generate chainspec and keystores with sudo account //Alice for below validators..."
84-
echo "${validator_ids}"
85-
docker run --rm -v $(pwd)/docker/data:/data --entrypoint "/bin/sh" -e RUST_LOG=debug "${NODE_IMAGE}" \
86-
-c "aleph-node bootstrap-chain --base-path /data --account-ids "${validator_ids}" > /data/chainspec.json"
81+
local validator_ids_comma_separated="${validators//${IFS:0:1}/,}"
8782

88-
echo "Generating keystore for RPC node ${account_ids[0]}..."
83+
echo "Generate chainspec and keystores for accounts: ${account_ids_comma_separated[@]}"
8984
docker run --rm -v $(pwd)/docker/data:/data --entrypoint "/bin/sh" -e RUST_LOG=debug "${NODE_IMAGE}" \
90-
-c "aleph-node bootstrap-node --base-path /data/${account_ids[0]} --account-id ${account_ids[0]}" > /dev/null
85+
-c "aleph-node bootstrap-chain --base-path /data --account-ids ${account_ids_comma_separated} --authorities-account-ids ${validator_ids_comma_separated} > /data/chainspec.json"
9186
}
9287

9388
function generate_bootnode_peer_id() {

aleph-client/src/connections.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ impl<S: AsSigned + Sync> SignedConnectionApi for S {
419419

420420
impl Connection {
421421
const DEFAULT_RETRIES: u32 = 10;
422-
const RETRY_WAIT_SECS: u64 = 3;
422+
const RETRY_WAIT_SECS: u64 = 6;
423423

424424
/// Creates new connection from a given url.
425425
/// By default, it tries to connect 10 times, waiting 1 second between each unsuccessful attempt.

bin/node/src/chain_spec/builder.rs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
use std::string::ToString;
22

3-
use aleph_runtime::{Feature, Perbill, WASM_BINARY};
3+
use aleph_runtime::{Feature, WASM_BINARY};
44
use pallet_staking::{Forcing, StakerStatus};
55
use primitives::{
66
staking::{MIN_NOMINATOR_BOND, MIN_VALIDATOR_BOND},
7-
AccountId, AlephNodeSessionKeys as SessionKeys, Version as FinalityVersion, ADDRESSES_ENCODING,
7+
AccountId, AlephNodeSessionKeys, Version as FinalityVersion, ADDRESSES_ENCODING,
88
TOKEN_DECIMALS,
99
};
1010
use serde_json::{Number, Value};
11+
use sp_runtime::Perbill;
1112

12-
use crate::{
13-
chain_spec::{cli::ChainParams, AlephNodeChainSpec},
14-
commands::AuthorityKeys,
15-
};
13+
use crate::chain_spec::{cli::ChainSpecParams, keystore::AccountSessionKeys, AlephNodeChainSpec};
1614

17-
fn to_account_ids(authorities: &[AuthorityKeys]) -> impl Iterator<Item = AccountId> + '_ {
15+
fn to_account_ids(authorities: &[AccountSessionKeys]) -> impl Iterator<Item = AccountId> + '_ {
1816
authorities.iter().map(|auth| auth.account_id.clone())
1917
}
2018

@@ -37,13 +35,12 @@ fn system_properties(token_symbol: String) -> serde_json::map::Map<String, Value
3735

3836
/// Generate chain spec for new AlephNode chains
3937
pub fn build_chain_spec(
40-
chain_params: ChainParams,
41-
authorities: Vec<AuthorityKeys>,
38+
chain_params: &ChainSpecParams,
39+
account_session_keys: Vec<AccountSessionKeys>,
4240
) -> Result<AlephNodeChainSpec, String> {
4341
let token_symbol = String::from(chain_params.token_symbol());
4442
let sudo_account = chain_params.sudo_account_id();
4543
let rich_accounts = chain_params.rich_account_ids();
46-
let faucet_account = chain_params.faucet_account_id();
4744
let finality_version = chain_params.finality_version();
4845

4946
Ok(AlephNodeChainSpec::builder(
@@ -54,10 +51,9 @@ pub fn build_chain_spec(
5451
.with_id(chain_params.chain_id())
5552
.with_chain_type(chain_params.chain_type())
5653
.with_genesis_config_patch(generate_genesis_config(
57-
authorities.clone(), // Initial PoA authorities, will receive funds
58-
sudo_account.clone(), // Sudo account, will also be pre funded
59-
rich_accounts.clone(), // Pre-funded accounts
60-
faucet_account.clone(), // Pre-funded faucet account
54+
account_session_keys,
55+
sudo_account,
56+
rich_accounts,
6157
finality_version,
6258
))
6359
.with_properties(system_properties(token_symbol))
@@ -67,58 +63,52 @@ pub fn build_chain_spec(
6763
/// Calculate initial endowments such that total issuance is kept approximately constant.
6864
fn calculate_initial_endowment(accounts: &[AccountId]) -> u128 {
6965
let total_issuance = 300_000_000u128 * 10u128.pow(TOKEN_DECIMALS);
70-
// due to known issue https://github.com/paritytech/polkadot-sdk/pull/2987/files,
71-
// we need to make sure returned number is un u64 range, otherwise serde_json::json macro fails
66+
// (A0-4258) due to known issue https://github.com/paritytech/polkadot-sdk/pull/2987/files,
67+
// we need to make sure returned number is in u64 range, otherwise serde_json::json macro fails
7268
// this is fixed in polkadot-sdk 1.6.0
7369
total_issuance / (accounts.len() as u128) / 10
7470
}
7571

7672
/// Configure initial storage state for FRAME modules.
7773
fn generate_genesis_config(
78-
authorities: Vec<AuthorityKeys>,
74+
account_session_keys: Vec<AccountSessionKeys>,
7975
sudo_account: AccountId,
8076
rich_accounts: Option<Vec<AccountId>>,
81-
faucet_account: Option<AccountId>,
8277
finality_version: FinalityVersion,
8378
) -> serde_json::Value {
84-
let mut endowed_accounts = to_account_ids(&authorities)
79+
let mut endowed_accounts = to_account_ids(&account_session_keys)
8580
.chain(
8681
rich_accounts
8782
.unwrap_or_default()
8883
.into_iter()
8984
.chain([sudo_account.clone()]),
9085
)
9186
.collect::<Vec<_>>();
92-
if let Some(faucet_account) = faucet_account {
93-
endowed_accounts.push(faucet_account);
94-
}
9587
endowed_accounts.sort();
9688
endowed_accounts.dedup();
9789
let initial_endowement = calculate_initial_endowment(&endowed_accounts);
9890

99-
let initial_balances = endowed_accounts
100-
.into_iter()
101-
.map(|account| (account, initial_endowement))
102-
.collect::<Vec<_>>();
103-
10491
serde_json::json!({
10592
"balances": {
106-
"balances": initial_balances,
93+
"balances": endowed_accounts
94+
.into_iter()
95+
.map(|account| (account, initial_endowement))
96+
.collect::<Vec<_>>(),
10797
},
10898
"sudo": {
10999
"key": Some(sudo_account),
110100
},
111101
"elections": {
112-
"reservedValidators": to_account_ids(&authorities).collect::<Vec<_>>(),
102+
"reservedValidators": to_account_ids(&account_session_keys).collect::<Vec<_>>(),
113103
},
114104
"session": {
115-
"keys": authorities
105+
"keys": account_session_keys
116106
.iter()
117107
.map(|auth| {
118108
(
119109
auth.account_id.clone(),
120110
auth.account_id.clone(),
121-
SessionKeys {
111+
AlephNodeSessionKeys {
122112
aura: auth.aura_key.clone(),
123113
aleph: auth.aleph_key.clone(),
124114
},
@@ -128,10 +118,10 @@ fn generate_genesis_config(
128118
},
129119
"staking": {
130120
"forceEra": Forcing::NotForcing,
131-
"validatorCount": authorities.len() as u32,
121+
"validatorCount": account_session_keys.len() as u32,
132122
"minimumValidatorCount": 4,
133123
"slashRewardFraction": Perbill::from_percent(10),
134-
"stakers": authorities
124+
"stakers": account_session_keys
135125
.iter()
136126
.enumerate()
137127
.map(|(validator_idx, validator)| {
@@ -153,11 +143,20 @@ fn generate_genesis_config(
153143
},
154144
"committeeManagement": {
155145
"sessionValidators": {
156-
"committee": to_account_ids(&authorities).collect::<Vec<_>>(),
146+
"committee": to_account_ids(&account_session_keys).collect::<Vec<_>>(),
157147
},
158148
},
159149
"featureControl": {
160150
"activeFeatures": vec![Feature::OnChainVerifier],
161151
},
162152
})
163153
}
154+
155+
pub fn build_chain_spec_json(
156+
is_raw_chainspec: bool,
157+
chain_params: &ChainSpecParams,
158+
account_session_keys: Vec<AccountSessionKeys>,
159+
) -> sc_service::error::Result<String> {
160+
let chain_spec = build_chain_spec(chain_params, account_session_keys)?;
161+
sc_service::chain_ops::build_spec(&chain_spec, is_raw_chainspec)
162+
}

bin/node/src/chain_spec/cli.rs

Lines changed: 18 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,13 @@
1-
use std::io::Write;
2-
31
use primitives::{AccountId, Version as FinalityVersion, LEGACY_FINALITY_VERSION};
42
use sc_chain_spec::ChainType;
5-
use sc_cli::{
6-
clap::{self, Args, Parser},
7-
Error, KeystoreParams,
8-
};
9-
use sc_service::BasePath;
10-
use sp_application_crypto::Ss58Codec;
11-
12-
use crate::{
13-
chain_spec::{
14-
builder::build_chain_spec, CHAINTYPE_DEV, CHAINTYPE_LIVE, CHAINTYPE_LOCAL,
15-
DEFAULT_CHAIN_ID, DEFAULT_SUDO_ACCOUNT,
16-
},
17-
commands::{authority_keys, bootstrap_backup, open_keystore},
18-
shared_params::SharedParams,
3+
use sc_cli::clap::{self, Args};
4+
5+
use crate::chain_spec::{
6+
parse_account_id, parse_chaintype, CHAINTYPE_LIVE, DEFAULT_CHAIN_ID, DEFAULT_SUDO_ACCOUNT_ALICE,
197
};
208

219
#[derive(Debug, Args, Clone)]
22-
pub struct ChainParams {
10+
pub struct ChainSpecParams {
2311
/// Chain ID is a short identifier of the chain
2412
#[arg(long, value_name = "ID", default_value = DEFAULT_CHAIN_ID)]
2513
chain_id: String,
@@ -36,28 +24,30 @@ pub struct ChainParams {
3624
#[arg(long, default_value = "DZERO")]
3725
token_symbol: String,
3826

39-
/// AccountIds of authorities forming the committee at the genesis (comma delimited)
27+
/// all account ids that needs to have session keys generated when bootstraping chain (comma delimited)
4028
#[arg(long, value_delimiter = ',', value_parser = parse_account_id, num_args = 1..)]
4129
account_ids: Vec<AccountId>,
4230

31+
/// AccountIds of authorities forming the committee at the genesis (comma delimited)
32+
/// If empty, then `--account-ids` are used as authorities.
33+
/// If not empty, it should ba a subset of `--account-ids`.
34+
#[arg(long, value_delimiter = ',', value_parser = parse_account_id, num_args = 1..)]
35+
authorities_account_ids: Vec<AccountId>,
36+
4337
/// AccountId of the sudo account
44-
#[arg(long, value_parser = parse_account_id, default_value(DEFAULT_SUDO_ACCOUNT))]
38+
#[arg(long, value_parser = parse_account_id, default_value(DEFAULT_SUDO_ACCOUNT_ALICE))]
4539
sudo_account_id: AccountId,
4640

4741
/// Accounts that will receive initial endowment in genesis block
4842
#[arg(long, value_delimiter = ',', value_parser = parse_account_id, num_args = 1..)]
4943
rich_account_ids: Option<Vec<AccountId>>,
5044

51-
/// Optional faucet account to be endowed
52-
#[arg(long, value_parser = parse_account_id)]
53-
faucet_account_id: Option<AccountId>,
54-
5545
/// Finality version at chain inception.
5646
#[arg(long, default_value = LEGACY_FINALITY_VERSION.to_string())]
5747
finality_version: FinalityVersion,
5848
}
5949

60-
impl ChainParams {
50+
impl ChainSpecParams {
6151
pub fn chain_id(&self) -> &str {
6252
&self.chain_id
6353
}
@@ -78,6 +68,10 @@ impl ChainParams {
7868
self.account_ids.clone()
7969
}
8070

71+
pub fn authorities_account_ids(&self) -> Vec<AccountId> {
72+
self.authorities_account_ids.clone()
73+
}
74+
8175
pub fn sudo_account_id(&self) -> AccountId {
8276
self.sudo_account_id.clone()
8377
}
@@ -86,81 +80,7 @@ impl ChainParams {
8680
self.rich_account_ids.clone()
8781
}
8882

89-
pub fn faucet_account_id(&self) -> Option<AccountId> {
90-
self.faucet_account_id.clone()
91-
}
92-
9383
pub fn finality_version(&self) -> FinalityVersion {
9484
self.finality_version
9585
}
9686
}
97-
98-
fn parse_chaintype(s: &str) -> Result<ChainType, Error> {
99-
Ok(match s {
100-
CHAINTYPE_DEV => ChainType::Development,
101-
CHAINTYPE_LOCAL => ChainType::Local,
102-
CHAINTYPE_LIVE => ChainType::Live,
103-
s => panic!("Wrong chain type {s} Possible values: dev local live"),
104-
})
105-
}
106-
107-
/// The `bootstrap-chain` command is used to generate private keys for the genesis authorities
108-
/// keys are written to the keystore of the authorities
109-
/// and the chain specification is printed to stdout in the JSON format
110-
#[derive(Debug, Parser)]
111-
pub struct BootstrapChainCmd {
112-
/// Force raw genesis storage output.
113-
#[arg(long = "raw")]
114-
pub raw: bool,
115-
116-
#[clap(flatten)]
117-
pub keystore_params: KeystoreParams,
118-
119-
#[clap(flatten)]
120-
pub chain_params: ChainParams,
121-
122-
#[clap(flatten)]
123-
pub node_params: SharedParams,
124-
}
125-
126-
/// Assumes an input path: some_path/, which is appended to finally become: some_path/account_id
127-
impl BootstrapChainCmd {
128-
pub fn run(&self) -> Result<(), Error> {
129-
let base_path = self.node_params.base_path();
130-
let backup_dir = self.node_params.backup_dir();
131-
let node_key_file = self.node_params.node_key_file();
132-
let chain_id = self.chain_params.chain_id();
133-
134-
let genesis_authorities = self
135-
.chain_params
136-
.account_ids()
137-
.into_iter()
138-
.map(|account_id| {
139-
let account_base_path: BasePath =
140-
base_path.path().join(account_id.to_string()).into();
141-
bootstrap_backup(account_base_path.path(), backup_dir);
142-
let keystore = open_keystore(&self.keystore_params, chain_id, &account_base_path);
143-
authority_keys(
144-
&keystore,
145-
account_base_path.path(),
146-
node_key_file,
147-
account_id,
148-
)
149-
})
150-
.collect();
151-
152-
let chain_spec = build_chain_spec(self.chain_params.clone(), genesis_authorities)?;
153-
154-
let json = sc_service::chain_ops::build_spec(&chain_spec, self.raw)?;
155-
if std::io::stdout().write_all(json.as_bytes()).is_err() {
156-
let _ = std::io::stderr().write_all(b"Error writing to stdout\n");
157-
}
158-
159-
Ok(())
160-
}
161-
}
162-
163-
/// Generate AccountId based on string command line argument.
164-
fn parse_account_id(s: &str) -> Result<AccountId, Error> {
165-
Ok(AccountId::from_string(s).expect("Passed string is not a hex encoding of a public key"))
166-
}

0 commit comments

Comments
 (0)