Skip to content

Commit

Permalink
feat: implement add custom sudo key for parachain (#204)
Browse files Browse the repository at this point in the history
* fix: fix issue for robonomics mainnet relay not showing blocks

* fix: fix issue litentry parachain testnet not showing blocks

* fix: kilt issue and acala karura testnet issue

* fix: acala, karura testnet issue

* chore: change base for manta parachain

* feat: implement add custom sudo key for parachain

* refactor: change insert_keys function, from js script to curl command

* chore: code clean in parachain.star

* refactor: change insertkey function from curl to js script

* chore: updated the config.json

* refactor: refactor the insert_keys function parameter

* refactor: refactor config.json, change sudo_key key position

* feat: add functionality to add sepate key wallet for each node

* refactor: refactor code in parachain.star, nodes can start with and without keys

* refactor: update script to update parachain spec

* fix: fix issue if sudo_key, key is not provided in config then it throw error

* fix: issue with sudo key while without registratioon is true

---------

Co-authored-by: Shanith K K <[email protected]>
  • Loading branch information
abhiyana and shanithkk authored Feb 14, 2024
1 parent ffd46a9 commit 76a0492
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 39 deletions.
43 changes: 20 additions & 23 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,43 @@
{
"name": "bob",
"node_type": "validator",
"prometheus": true
"prometheus": false

}
]
},

"parachains": [
{
"name":"acala",
"nodes": [
{
"name": "alice",
"node_type": "validator",
"prometheus": false

},
{
"name": "bob",
"node_type": "full",
"prometheus": true
}
]
},
{
"name":"frequency",
"nodes": [
{
"name": "alice",
"node_type": "validator",
"prometheus": false
"node_type": "collator",
"prometheus": false,
"key":{
"private_phrase":"dizzy rose offer wall social glory debris gift govern seminar almost bicycle" ,
"public_key":"5G3vA9UC6J7hPN5Jqfiz4qFNqYAfahHxffbuQf6dcZZx3Yx6"
}

},
{
"name": "bob",
"node_type": "full",
"prometheus": true
"prometheus": false,
"key": {
"private_phrase":"diamond crane pioneer aisle conduct media news cup price olive dust light" ,
"public_key":"5GgwsM48CCT7oPUyFTTpE5L1t7Fjpe7D8SDNKxJxug15YEKy"
}
}
]
],
"sudo_key": {
"private_phrase":"dizzy rose offer wall social glory debris gift govern seminar almost bicycle" ,
"public_key":"5G3vA9UC6J7hPN5Jqfiz4qFNqYAfahHxffbuQf6dcZZx3Yx6"
}
}
],
"explorer": true,
"without_registration" : true

"explorer": false,
"without_registration" : false
}
15 changes: 11 additions & 4 deletions parachain/build-spec.star
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
build_spec = import_module("../package_io/build-spec.star")
constant = import_module("../package_io/constant.star")

def create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id):
def create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id, sudo_key, collators_keys):
files = {
"/app": "configs",
}
Expand All @@ -16,13 +16,19 @@ def create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, ch
files = {
"/app": "configs",
"/build": chain_name + "plain",
"/javascript": "javascript",
}


run_command = "cd /javascript && npm i && node edit_parachain_plain.js /build/{0}.json {1} \"{2}\" \'{3}\'".format(chain_name, para_id, sudo_key, collators_keys)
plan.print(run_command)
plan.run_sh(
run = "sed -e 's/\"parachainId\": *[0-9]\\+/\"parachainId\": {0}/' -e 's/\"para_id\": [0-9]*,/\"para_id\": {0},/' -e 's/\"paraId\": [0-9]*,/\"paraId\": {0},/' -e 's/\"parachain_id\": [0-9]*,/\"parachain_id\": {0},/' /build/{1}.json > /tmp/{1}.json".format(para_id, chain_name),
image = constant.CURL_JQ_IMAGE,
run = run_command,
image = constant.NODE_IMAGE,
files = files,
store = [StoreSpec(src = "/tmp/{0}.json".format(chain_name), name = chain_name + "edit")],
store = [StoreSpec(src = "/build/{0}.json".format(chain_name), name = chain_name + "edit")],
)


raw_service = create_raw_build_spec_genisis_state_genisis_wasm_for_parachain(plan, binary, image, chain_name)

Expand All @@ -42,3 +48,4 @@ def create_raw_build_spec_genisis_state_genisis_wasm_for_parachain(plan, binary,
)

return chain_name + "raw"

61 changes: 50 additions & 11 deletions parachain/parachain.star
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ def start_local_parachain_node(plan, chain_type, parachain, para_id):
image = parachain_details["image"]
binary = parachain_details["entrypoint"]
chain_base = parachain_details["base"][0]
raw_service = build_spec.create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id)

sudo_key = ""
if parachain.get("sudo_key") != None and len(parachain["sudo_key"]) != 0:
sudo_key = parachain["sudo_key"]["private_phrase"]

public_keys = [node.get("key", {}).get("private_phrase", "") for node in parachain["nodes"] if node.get("key")]
collators_keys = "[" + ", ".join(["\"{}\"".format(key) for key in public_keys]) + "]"

raw_service = build_spec.create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id, sudo_key, collators_keys)

parachain_final = {}

Expand All @@ -41,17 +49,32 @@ def start_local_parachain_node(plan, chain_type, parachain, para_id):
ws_port = None

if chain_name in constant.WS_PORT:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --ws-port=9944 --port=30333 --rpc-port=9947 --ws-external --rpc-external --prometheus-external --rpc-cors=all --{2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]
if node.get("key") != None and len(node["key"]) != 0:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --ws-port=9944 --port=30333 --rpc-port=9947 --ws-external --rpc-external --prometheus-external --rpc-cors=all --name={2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]
else:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --ws-port=9944 --port=30333 --rpc-port=9947 --ws-external --rpc-external --prometheus-external --rpc-cors=all --{2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]
else:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --rpc-port=9947 --port=30333 --rpc-external --rpc-cors=all --prometheus-external --{2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]
if node.get("key") != None and len(node["key"]) != 0:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --rpc-port=9947 --port=30333 --rpc-external --rpc-cors=all --prometheus-external --name={2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]
else:
exec_comexec_commandmand = [
"/bin/bash",
"-c",
"{0} --base-path=/tmp/{1} --chain=/build/{1}-raw.json --rpc-port=9947 --port=30333 --rpc-external --rpc-cors=all --prometheus-external --{2} --collator --rpc-methods=unsafe --force-authoring --execution=wasm -- --chain=/app/raw-polkadot.json --execution=wasm".format(binary, chain_name, node["name"]),
]


build_file = raw_service
parachain_spawn_detail = node_setup.spawn_parachain(plan, node["prometheus"], image, parachain["name"], "{0}-{1}-{2}".format(chain_name, node["name"], chain_type), exec_comexec_commandmand, build_file, rpc_port, prometheus_port, lib2lib_port, ws_port)
Expand All @@ -72,6 +95,9 @@ def start_local_parachain_node(plan, chain_type, parachain, para_id):

parachain_final[parachain_spawn_detail.name] = parachain_detail

if node.get("key") != None and len(node["key"]) != 0:
insert_keys(plan, "aura", node["key"]["private_phrase"], parachain_detail["endpoint"])

return parachain_final

def start_nodes(plan, chain_type, parachains, relay_chain_ip):
Expand Down Expand Up @@ -239,3 +265,16 @@ def run_testnet_mainnet(plan, chain_type, relaychain_name, parachain):

final_parachain_info[node_details.name] = node_info
return final_parachain_info



def insert_keys(plan, key_type, private_phrase, uri):
files = {
"/javascript": "javascript",
}

plan.run_sh(
run = 'cd /javascript && npm i && node insert_key.js "{0}" "{1}" "{2}"'.format(key_type, private_phrase, uri),
image = constant.NODE_IMAGE,
files = files,
)
9 changes: 8 additions & 1 deletion parachain/parachain_without_registration.star
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ def start_nodes(plan, chain_type, relaychain, parachains):
binary = parachain_details["entrypoint"]
chain_base = parachain_details["base"][0]

sudo_key = ""
if parachain.get("sudo_key") != None and len(parachain["sudo_key"]) != 0:
sudo_key = parachain["sudo_key"]["private_phrase"]

public_keys = [node.get("key", {}).get("private_phrase", "") for node in parachain["nodes"] if node.get("key")]
collators_keys = "[" + ", ".join(["\"{}\"".format(key) for key in public_keys]) + "]"

# Creating the genisis state genesis wasm and raw build spec for parachain
build_spec.create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id)
build_spec.create_parachain_build_spec_with_para_id(plan, image, binary, chain_name, chain_base, para_id, sudo_key, collators_keys)

# if parachain are more than one, adding the genisis state genesis wasm to relay(polkadot) chain spec
if counter > 0:
Expand Down
79 changes: 79 additions & 0 deletions parachain/static_files/javascript/edit_parachain_plain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const fs = require("fs");
const { Keyring } = require('@polkadot/keyring');
const { encodeAddress, cryptoWaitReady } = require('@polkadot/util-crypto');

async function updateParachainSpec(paraSpecFile, paraId, newSudoKeyPhrase, initialCollatorsPhrase) {
try {
const rawdata = fs.readFileSync(paraSpecFile);
const chainSpec = JSON.parse(rawdata);
const collators = JSON.parse(initialCollatorsPhrase);

chainSpec.para_id = paraId;
chainSpec.genesis.runtime.parachainInfo.parachainId = paraId;


await cryptoWaitReady();
const keyring = new Keyring({ type: 'sr25519' });

let newSudoKey = ''; // Declaring newSudoKey as let instead of const

if (newSudoKeyPhrase.length > 0) {
const newSudoAccount = keyring.addFromUri(newSudoKeyPhrase);
newSudoKey = newSudoAccount.address;
chainSpec.genesis.runtime.sudo.key = newSudoKey;

const SESSION_KEYS = [
newSudoKey,
newSudoKey,
{ aura: newSudoKey }
];
chainSpec.genesis.runtime.session.keys.push(SESSION_KEYS);

const BALANCE = [
newSudoKey,
chainSpec.genesis.runtime.balances.balances[0][1]
];
chainSpec.genesis.runtime.balances.balances.push(BALANCE);
console.log("changed sudo key:", newSudoKey);
}

if (initialCollatorsPhrase.length > 0) {
collators.forEach(collatorPhrase => {
var collatorAccount = keyring.addFromUri(collatorPhrase);
var collator = collatorAccount.address;
//adding this condition to prevent adding duplicate keys
if(collatorPhrase!=newSudoKeyPhrase){
console.log("updating collator:", collator);
const sessionKey = [
collator,
collator,
{ aura: collator }
];
chainSpec.genesis.runtime.session.keys.push(sessionKey);

const balance = [
collator,
chainSpec.genesis.runtime.balances.balances[0][1]
];
chainSpec.genesis.runtime.balances.balances.push(balance);

chainSpec.genesis.runtime.collatorSelection.invulnerables.push(collator);
} else{
chainSpec.genesis.runtime.collatorSelection.invulnerables.push(collator);
}
});
}

fs.writeFileSync(paraSpecFile, JSON.stringify(chainSpec, null, 2));

console.log("✓ Updated sudo key and session keys in parachain spec");
} catch (error) {
console.error("Error updating parachain spec:", error.message);
}
}

const paraSpecFile = process.argv[2];
const paraId = parseInt(process.argv[3], 10) || 2000;
const newSudoKey = process.argv[4];
const initialCollators = process.argv[5];
updateParachainSpec(paraSpecFile, paraId, newSudoKey, initialCollators);
37 changes: 37 additions & 0 deletions parachain/static_files/javascript/insert_key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api');
const { encodeAddress } = require('@polkadot/util-crypto');
const { createType } = require('@polkadot/types');
const { u8aToHex } =require("@polkadot/util")
const { decodeAddress } = require("@polkadot/util-crypto")



async function insertKey(keyType, mnemonicOrPrivateKey, providerUrl) {
try {
const wsProvider = new WsProvider(providerUrl);
const api = await ApiPromise.create({ provider: wsProvider });
const keyring = new Keyring({ type: 'sr25519' });
const account = keyring.addFromMnemonic(mnemonicOrPrivateKey);
const result = await api.rpc.author.insertKey(keyType, mnemonicOrPrivateKey, u8aToHex(decodeAddress(account.address)));
console.log(`Account ${account.address} inserted successfully!`);
return result;
} catch (error) {
console.error('Error inserting account:', error);
throw error;
}
}

const keyType = process.argv[2];
const mnemonicOrPrivateKey = process.argv[3];
const providerUrl = process.argv[4];

(async () => {
try {
await insertKey(keyType, mnemonicOrPrivateKey, providerUrl);
console.log('Script executed successfully!');
process.exit(0);
} catch (error) {
console.error('Error executing script:', error);
process.exit(1);
}
})();

0 comments on commit 76a0492

Please sign in to comment.