Skip to content

Commit

Permalink
Add Parachains to Genesis (#86)
Browse files Browse the repository at this point in the history
* add parachains to genesis

* lint
  • Loading branch information
shawntabrizi authored Apr 24, 2021
1 parent 94f6ed7 commit 7a0ef28
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 50 deletions.
94 changes: 61 additions & 33 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ import {
establishHrmpChannel,
} from "./rpc";
import { checkConfig } from "./check";
import { clearAuthorities, addAuthority, changeGenesisParachainsConfiguration } from "./spec";
import {
clearAuthorities,
addAuthority,
changeGenesisParachainsConfiguration,
addGenesisParachain,
} from "./spec";
import { parachainAccount } from "./parachain";
import { ApiPromise } from "@polkadot/api";

import { resolve, dirname } from "path";
import fs from "fs";
import { LaunchConfig } from "./types";
import { LaunchConfig, ParachainConfig } from "./types";

// Special care is needed to handle paths to various files (binaries, spec, config, etc...)
// The user passes the path to `config.json`, and we use that as the starting point for any other
Expand Down Expand Up @@ -58,10 +63,10 @@ function loadTypeDef(types: string | object): object {
}
}

async function main() {
// keep track of registered parachains
let registeredParachains: { [key: string]: boolean } = {};
// keep track of registered parachains
let registeredParachains: { [key: string]: boolean } = {};

async function main() {
// Verify that the `config.json` has all the expected properties.
if (!checkConfig(config)) {
return;
Expand All @@ -80,8 +85,12 @@ async function main() {
await addAuthority(`${chain}.json`, node.name);
}
if (config.relaychain.config) {
await changeGenesisParachainsConfiguration(`${chain}.json`, config.relaychain.config)
await changeGenesisParachainsConfiguration(
`${chain}.json`,
config.relaychain.config
);
}
await addParachainsToGenesis(`${chain}.json`, config.parachains);
// -- End Chain Spec Modify --
await generateChainSpecRaw(relay_chain_bin, chain);
const spec = resolve(`${chain}-raw.json`);
Expand Down Expand Up @@ -115,30 +124,10 @@ async function main() {
);
await startCollator(bin, id, wsPort, port, chain, spec, flags);

// If it isn't registered yet, register the parachain on the relaychain
if (!registeredParachains[id]) {
console.log(`Registering Parachain ${id}`);

// Get the information required to register the parachain on the relay chain.
let genesisState;
let genesisWasm;
try {
genesisState = await exportGenesisState(bin, id, chain);
genesisWasm = await exportGenesisWasm(bin, chain);
} catch (err) {
console.error(err);
process.exit(1);
}

await registerParachain(relayChainApi, id, genesisWasm, genesisState, config.finalization);

registeredParachains[id] = true;

// Allow time for the TX to complete, avoiding nonce issues.
// TODO: Handle nonce directly instead of this.
if (balance) {
await setBalance(relayChainApi, account, balance, config.finalization);
}
// Allow time for the TX to complete, avoiding nonce issues.
// TODO: Handle nonce directly instead of this.
if (balance) {
await setBalance(relayChainApi, account, balance, config.finalization);
}
}

Expand Down Expand Up @@ -170,7 +159,13 @@ async function main() {
}

console.log(`Registering Parachain ${id}`);
await registerParachain(relayChainApi, id, genesisWasm, genesisState, config.finalization);
await registerParachain(
relayChainApi,
id,
genesisWasm,
genesisState,
config.finalization
);

// Allow time for the TX to complete, avoiding nonce issues.
// TODO: Handle nonce directly instead of this.
Expand All @@ -181,7 +176,9 @@ async function main() {
}
if (config.hrmpChannels) {
for (const hrmpChannel of config.hrmpChannels) {
console.log(`Setting Up HRMP Channel ${hrmpChannel.sender} -> ${hrmpChannel.recipient}`);
console.log(
`Setting Up HRMP Channel ${hrmpChannel.sender} -> ${hrmpChannel.recipient}`
);
await ensureOnboarded(relayChainApi, hrmpChannel.sender);
await ensureOnboarded(relayChainApi, hrmpChannel.recipient);

Expand All @@ -192,7 +189,7 @@ async function main() {
recipient,
maxCapacity,
maxMessageSize,
config.finalization,
config.finalization
);
}
}
Expand All @@ -215,6 +212,37 @@ async function ensureOnboarded(relayChainApi: ApiPromise, paraId: number) {
});
}

async function addParachainsToGenesis(
spec: string,
parachains: ParachainConfig[]
) {
console.log("\n⛓ Adding Genesis Parachains");
for (const parachain of parachains) {
const { id, chain } = parachain;
const bin = resolve(config_dir, parachain.bin);
if (!fs.existsSync(bin)) {
console.error("Parachain binary does not exist: ", bin);
process.exit();
}
// If it isn't registered yet, register the parachain in genesis
if (!registeredParachains[id]) {
// Get the information required to register the parachain in genesis.
let genesisState;
let genesisWasm;
try {
genesisState = await exportGenesisState(bin, id, chain);
genesisWasm = await exportGenesisWasm(bin, chain);
} catch (err) {
console.error(err);
process.exit(1);
}

await addGenesisParachain(spec, id, genesisState, genesisWasm, true);
registeredParachains[id] = true;
}
}
}

// Kill all processes when exiting.
process.on("exit", function () {
killAll();
Expand Down
10 changes: 5 additions & 5 deletions src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export async function registerParachain(
id: string,
wasm: string,
header: string,
finalization: boolean = false,
finalization: boolean = false
) {
return new Promise<void>(async (resolvePromise, reject) => {
await cryptoWaitReady();
Expand Down Expand Up @@ -107,7 +107,7 @@ export async function setBalance(
api: ApiPromise,
who: string,
value: string,
finalization: boolean = false,
finalization: boolean = false
) {
return new Promise<void>(async (resolvePromise, reject) => {
await cryptoWaitReady();
Expand Down Expand Up @@ -157,7 +157,7 @@ export async function establishHrmpChannel(
receiver: number,
maxCapacity: number,
maxMessageSize: number,
finalization: boolean = false,
finalization: boolean = false
) {
return new Promise<void>(async (resolvePromise, reject) => {
await cryptoWaitReady();
Expand All @@ -178,7 +178,7 @@ export async function establishHrmpChannel(
sender,
receiver,
maxCapacity,
maxMessageSize,
maxMessageSize
)
)
.signAndSend(alice, { nonce: nonce, era: 0 }, (result) => {
Expand Down Expand Up @@ -212,7 +212,7 @@ export async function sendHrmpMessage(
api: ApiPromise,
recipient: string,
data: string,
finalization: boolean = false,
finalization: boolean = false
) {
return new Promise<void>(async (resolvePromise, reject) => {
await cryptoWaitReady();
Expand Down
1 change: 1 addition & 0 deletions src/spawn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function generateChainSpec(bin: string, chain: string) {

// Output the chainspec of a node using `--raw` from a JSON file.
export async function generateChainSpecRaw(bin: string, chain: string) {
console.log(); // Add a newline in output
return new Promise<void>(function (resolve, reject) {
let args = ["build-spec", "--chain=" + chain + ".json", "--raw"];

Expand Down
69 changes: 57 additions & 12 deletions src/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function clearAuthorities(spec: string) {

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

// Add additional authorities to chain spec in `session.keys`
Expand All @@ -51,7 +51,7 @@ export async function addAuthority(spec: string, name: string) {
const ed_keyring = new Keyring({ type: "ed25519" });
const ed_account = ed_keyring.createFromUri(`//${nameCase(name)}`);

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

let key = [
Expand All @@ -77,31 +77,76 @@ export async function addAuthority(spec: string, name: string) {

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

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

if (
chainSpec.genesis.runtime.runtime_genesis_config &&
chainSpec.genesis.runtime.runtime_genesis_config.parachainsParas
) {
let paras =
chainSpec.genesis.runtime.runtime_genesis_config.parachainsParas.paras;

let new_para = [
parseInt(para_id),
{
genesis_head: head,
validation_code: wasm,
parachain: parachain,
},
];

paras.push(new_para);

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
console.log(` ✓ Added Genesis Parachain ${para_id}`);
}
}

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

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

if (
chainSpec.genesis.runtime.runtime_genesis_config &&
chainSpec.genesis.runtime.runtime_genesis_config.parachainsConfiguration
) {
let config = chainSpec.genesis.runtime.runtime_genesis_config.parachainsConfiguration.config;
Object.keys(updates).forEach(key => {
let config =
chainSpec.genesis.runtime.runtime_genesis_config.parachainsConfiguration
.config;
Object.keys(updates).forEach((key) => {
if (config.hasOwnProperty(key)) {
config[key] = updates[key];
console.log(`Updated Parachains Configuration [ ${key}: ${config[key]} ]`);
console.log(
` ✓ Updated Parachains Configuration [ ${key}: ${config[key]} ]`
);
} else {
console.error(`!! Bad Parachains Configuration [ ${key}: ${updates[key]} ]`);
console.error(
` ⚠ Bad Parachains Configuration [ ${key}: ${updates[key]} ]`
);
}
});
}

let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
console.log(`Saved Genesis Parachains Configuration`);
let data = JSON.stringify(chainSpec, null, 2);
fs.writeFileSync(spec, data);
}
}

0 comments on commit 7a0ef28

Please sign in to comment.