Skip to content

Commit

Permalink
Refactor add authorities/parachains to genesis (#21)
Browse files Browse the repository at this point in the history
* wip

* more work in add auths

* support add parachain in genesis or register through rpc call
  • Loading branch information
pepoviola authored Dec 16, 2021
1 parent 3b8ee3a commit e5cce54
Show file tree
Hide file tree
Showing 11 changed files with 559 additions and 332 deletions.
175 changes: 175 additions & 0 deletions src/chain-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { Keyring } from "@polkadot/api";
import { cryptoWaitReady } from "@polkadot/util-crypto";
import { encodeAddress } from "@polkadot/util-crypto";
import { ChainSpec } from "./types";
import { readDataFile } from "./utils";
const fs = require("fs");

function nameCase(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}

// Get authority keys from within chainSpec data
function getAuthorityKeys(chainSpec: ChainSpec) {
// Check runtime_genesis_config key for rococo compatibility.
const runtimeConfig =
chainSpec.genesis.runtime?.runtime_genesis_config ||
chainSpec.genesis.runtime;
if (runtimeConfig && runtimeConfig.session) {
return runtimeConfig.session.keys;
}

// For retro-compatibility with substrate pre Polkadot 0.9.5
if (runtimeConfig && runtimeConfig.palletSession) {
return runtimeConfig.palletSession.keys;
}

console.error(" ⚠ session not found in runtimeConfig");
process.exit(1);
}

// Remove all existing keys from `session.keys`
export function clearAuthorities(spec: string) {
let rawdata = fs.readFileSync(spec);
let chainSpec;
try {
chainSpec = JSON.parse(rawdata);
} catch {
console.error(" ⚠ failed to parse the chain spec");
process.exit(1);
}

let keys = getAuthorityKeys(chainSpec);
keys.length = 0;

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
console.log(`\n🧹 Starting with a fresh authority set...`);
}

// Add additional authorities to chain spec in `session.keys`
export async function addAuthority(spec: string, name: string) {
await cryptoWaitReady();

const sr_keyring = new Keyring({ type: "sr25519" });
const sr_account = sr_keyring.createFromUri(`//${nameCase(name)}`);
const sr_stash = sr_keyring.createFromUri(`//${nameCase(name)}//stash`);

const ed_keyring = new Keyring({ type: "ed25519" });
const ed_account = ed_keyring.createFromUri(`//${nameCase(name)}`);

const ec_keyring = new Keyring({ type: "ecdsa" });
const ec_account = ec_keyring.createFromUri(`//${nameCase(name)}`);

let key = [
sr_stash.address,
sr_stash.address,
{
grandpa: ed_account.address,
babe: sr_account.address,
im_online: sr_account.address,
parachain_validator: sr_account.address,
authority_discovery: sr_account.address,
para_validator: sr_account.address,
para_assignment: sr_account.address,
beefy: encodeAddress(ec_account.publicKey),
},
];

let rawdata = fs.readFileSync(spec);
let chainSpec = JSON.parse(rawdata);

let keys = getAuthorityKeys(chainSpec);
keys.push(key);

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
console.log(` 👤 Added Genesis Authority ${name} - ${sr_stash.address}`);
}

// Add parachains to the chain spec at genesis.
export async function addParachainToGenesis(
spec_path: string,
para_id: string,
head: string,
wasm: string,
parachain: boolean = true
) {
let rawdata = fs.readFileSync(spec_path);
let chainSpec = JSON.parse(rawdata);

// Check runtime_genesis_config key for rococo compatibility.
const runtimeConfig =
chainSpec.genesis.runtime?.runtime_genesis_config ||
chainSpec.genesis.runtime;
let paras = undefined;
if (runtimeConfig.paras) {
paras = runtimeConfig.paras.paras;
}
// For retro-compatibility with substrate pre Polkadot 0.9.5
else if (runtimeConfig.parachainsParas) {
paras = runtimeConfig.parachainsParas.paras;
}
if (paras) {
let new_para = [
parseInt(para_id),
[
readDataFile(head), //fs.readFileSync(head).toString(),
readDataFile(wasm), //fs.readFileSync(wasm).toString(),
parachain
],
];

paras.push(new_para);

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec_path, data);
console.log(` ✓ Added Genesis Parachain ${para_id}`);
} else {
console.error(" ⚠ paras not found in runtimeConfig");
process.exit(1);
}
}

// Update the runtime config in the genesis.
// It will try to match keys which exist within the configuration and update the value.
export async function changeGenesisConfig(spec: string, updates: any) {
let rawdata = fs.readFileSync(spec);
let chainSpec = JSON.parse(rawdata);

console.log(`\n⚙ Updating Relay Chain Genesis Configuration`);

if (chainSpec.genesis) {
let config = chainSpec.genesis;
findAndReplaceConfig(updates, config);

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
}
}

// Look at the key + values from `obj1` and try to replace them in `obj2`.
function findAndReplaceConfig(obj1: any, obj2: any) {
// Look at keys of obj1
Object.keys(obj1).forEach((key) => {
// See if obj2 also has this key
if (obj2.hasOwnProperty(key)) {
// If it goes deeper, recurse...
if (
obj1[key] !== null &&
obj1[key] !== undefined &&
obj1[key].constructor === Object
) {
findAndReplaceConfig(obj1[key], obj2[key]);
} else {
obj2[key] = obj1[key];
console.log(
` ✓ Updated Genesis Configuration [ ${key}: ${obj2[key]} ]`
);
}
} else {
console.error(` ⚠ Bad Genesis Configuration [ ${key}: ${obj1[key]} ]`);
}
});
}

15 changes: 13 additions & 2 deletions src/configManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ export const DEFAULT_CHAIN = "rococo-local";
export const DEFAULT_BOOTNODE_PEER_ID =
"12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp";
export const DEFAULT_BOOTNODE_DOMAIN = "bootnode";
export const DEFAULT_CHAIN_SPEC_COMMAND =
"polkadot build-spec --chain {{chainName}} --disable-default-bootnode > /cfg/{{chainName}}-plain.json && polkadot build-spec --chain {{chainName}} --disable-default-bootnode --raw > /cfg/{{chainName}}.json";
export const DEFAULT_CHAIN_SPEC_PATH = "/cfg/{{chainName}}.json";
export const DEFAULT_CHAIN_SPEC_RAW_PATH = "/cfg/{{chainName}}-raw.json";
//export const DEFAULT_CHAIN_SPEC_COMMAND =
// "polkadot build-spec --chain {{chainName}} --disable-default-bootnode > /cfg/{{chainName}}-plain.json && polkadot build-spec --chain {{chainName}} --disable-default-bootnode --raw > /cfg/{{chainName}}.json";
export const DEFAULT_CHAIN_SPEC_COMMAND = "polkadot build-spec --chain {{chainName}} --disable-default-bootnode";
export const DEFAULT_GENESIS_GENERATE_COMMAND =
"/usr/local/bin/adder-collator export-genesis-state > /cfg/genesis-state";
export const DEFAULT_WASM_GENERATE_COMMAND =
Expand All @@ -44,6 +47,13 @@ export const BAKCCHANNEL_URI_PATTERN = "http://127.0.0.1:{{PORT}}";
export const BAKCCHANNEL_PORT = 3000;
export const BAKCCHANNEL_POD_NAME = "backchannel";

export const ZOMBIE_WRAPPER = "zombie-wrapper.sh";
// get the path of the zombie wrapper
export const zombieWrapperPath = resolve(
__dirname,
`../scripts/${ZOMBIE_WRAPPER}`
);

export function generateNetworkSpec(config: LaunchConfig): ComputedNetwork {
let networkSpec: any = {
relaychain: {
Expand Down Expand Up @@ -191,6 +201,7 @@ export function generateNetworkSpec(config: LaunchConfig): ComputedNetwork {

let parachainSetup: Parachain = {
id: parachain.id,
addToGenesis: parachain.addToGenesis === undefined ? true : parachain.addToGenesis, // add by default
collator: {
name: getUniqueName("collator"),
command: parachain.collator.command || DEFAULT_COLLATOR_COMMAND,
Expand Down
8 changes: 5 additions & 3 deletions src/networkNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ export class NetworkNode implements NetworkNodeInterface {

async connectApi() {
const provider = new WsProvider(this.wsUri);
debug(`Connecting api for ${this.name}...`);
this.apiInstance = await ApiPromise.create({
provider,
types: this.userDefinedTypes,
});
debug(`Connected to ${this.name}`);
}

async restart(timeout: number | null = null) {
Expand All @@ -55,7 +57,7 @@ export class NetworkNode implements NetworkNodeInterface {
: `echo restart > /tmp/zombiepipe`;
args.push(cmd);

await client._kubectl(args, undefined, true);
await client.kubectl(args, undefined, true);
}

async pause() {
Expand All @@ -68,7 +70,7 @@ export class NetworkNode implements NetworkNodeInterface {
"-c",
"echo pause > /tmp/zombiepipe",
];
await client._kubectl(args, undefined, true);
await client.kubectl(args, undefined, true);
}

async resume() {
Expand All @@ -81,7 +83,7 @@ export class NetworkNode implements NetworkNodeInterface {
"-c",
"echo pause > /tmp/zombiepipe",
];
await client._kubectl(args, undefined, true);
await client.kubectl(args, undefined, true);
}

async isUp(timeout = DEFAULT_INDIVIDUAL_TEST_TIMEOUT): Promise<boolean> {
Expand Down
Loading

0 comments on commit e5cce54

Please sign in to comment.