12) Swap & Distribute Keys

This process can also be performed by launching theCeremony DApp with or without forking the poanetwork/poa-chain-spec repo. See Appendix C: Governance DApps for more info.

Swap keys without forking

1) Clone the Ceremony DApp repo:

$ git clone https://github.com/poanetwork/poa-dapps-keys-generation
$ cd poa-dapps-keys-generation

2) Add your network to constants.NETWORKS in src/utils/constants.js as it's described in Appendix C: Governance DApps.

3) If your network is not named as "Dai", fix the name in the line https://github.com/poanetwork/poa-dapps-keys-generation/blob/bd93bf850159b5d896eaf7433355b0aeaa839663/src/utils/keysManager.js#L15 to use zero gas price.

4) Make src/utils/addresses.js use the address of your KeysManager contract

diff --git a/src/utils/addresses.js b/src/utils/addresses.js
index 799909e..08c195e 100644
--- a/src/utils/addresses.js
+++ b/src/utils/addresses.js
@@ -1,15 +1,15 @@
import { constants } from './constants'
import helpers from './helpers'
-//const local = {
-// KEYS_MANAGER_ADDRESS: '0xfc90125492e58dbfe80c0bfb6a2a759c4f703ca8'
+const local = {
export default web3Config => {
const branch = constants.NETWORKS[web3Config.netId].BRANCH
return new Promise((resolve, reject) => {
+ resolve({ addresses: local, web3Config })
fetch(helpers.addressesURL(branch)).then((response) => {
response.json().then(json => {
resolve({ addresses: json, web3Config })
}).catch(function(err) {
let addr = helpers.addressesURL(branch)

5) Make src/utils/helpers.js use the ABI of your KeysManager contract:

diff --git a/src/utils/helpers.js b/src/utils/helpers.js
index 23b2399..af8ee58 100644
--- a/src/utils/helpers.js
+++ b/src/utils/helpers.js
@@ -28,6 +28,7 @@ function ABIURL(branch, contract) {
function getABI(branch, contract) {
+ if (contract == 'KeysManager') return [...ABI...]
let addr = ABIURL(branch, contract)
return fetch(addr).then(function(response) {
return response.json()

6) Connect your MetaMask to your network and launch DApp. Validators should use it to swap their initial keys to mining+voting+payout keys.

Instead of Ceremony DApp the script from https://github.com/poanetwork/deployment-terraform/tree/master/helper-scripts/gen-prod-keys can be used:

  • Edit helper-scripts/gen-prod-keys/index.js in the following manner:

    diff --git a/helper-scripts/gen-prod-keys/index.js b/helper-scripts/gen-prod-keys/index.js
    index 5266629..ed0802d 100644
    --- a/helper-scripts/gen-prod-keys/index.js
    +++ b/helper-scripts/gen-prod-keys/index.js
    @@ -16,7 +17,7 @@ const keysManagerABI = require('./KeysManager.abi.json');
    var keysManagerContract;
    var chainId;
    -const GASPRICE_GWEI = 2;
    +const GASPRICE_GWEI = 0;
    function loginf(...args) {
    console.log(new Date().toISOString(), ...args);
    @@ -68,11 +69,13 @@ function getInitialKey(address) {
    function checkInitialKey(address, next) {
    - keysManagerContract.methods.getInitialKey(`0x${address}`).call((err, result) => {
    + keysManagerContract.methods.getInitialKeyStatus(`0x${address}`).call((err, result) => {
    if (err) throw err;
    return next(result.toString());
  • Replace KeysManager.abi.json with abi[] part from poa-network-consensus-contracts/build/contracts/KeysManager.json (example).

  • Put initial keys into keystore subdirectory.

  • Call the script for each key once per block:

Replace https://<rpc.endpoint> with address of your bootnode with externally enabled RPC (When running from MoC node you can skip entering RPC_ENDPOINT variable) and 0xKEYS_MANAGER_ADDRESS with keys manager address (find it at poa-network-consensus-contracts/contracts.json)

$ RPC_ENDPOINT=https://<rpc.endpoint> node index.js 0xKEYS_MANAGER_ADDRESS

The primary keys (mining+voting+payout) will be saved into the production-keys subdirectory grouped by initial key


├── validator-2ec2104bc1d45f9faa6d8218c7186222bb2388e5
│ ├── initial_2ec2104bc1d45f9faa6d8218c7186222bb2388e5.json
│ ├── initial_2ec2104bc1d45f9faa6d8218c7186222bb2388e5.key
│ ├── mining_1272b1cea9c5214d6d5ab9152edc7a96f70b3111.json
│ ├── mining_1272b1cea9c5214d6d5ab9152edc7a96f70b3111.key
│ ├── payout_c1ae3c98189564f671649affcd777d5eefda2c2b.json
│ ├── payout_c1ae3c98189564f671649affcd777d5eefda2c2b.key
│ ├── voting_25d54934564b82be18a32e16be2b0bc6337164f1.json
│ └── voting_25d54934564b82be18a32e16be2b0bc6337164f1.key
└── validator-38dd91a11dbd81a6a177d94cfa391dfa771631c8

It is important that you don't just convert all initial keys without launching validator nodes (see next step). It's best to convert one key, then launch corresponding validator node and make sure it's mining, then return to this step and convert the next key, launch second validator node, and so on. Otherwise, you may encounter bugs.

Configure Validator Nodes

Repeat this process for each validator node

1) Distribute generated mining keys to validator nodes.

  • Place 0x<address>.json file into parity_data/keys/$NetworkName/

  • Change the password in node.pwd (take it from the corresponding *.key or *.txt generated file)

  • Change the address in node.toml (replace unlock = […] and engine_signer = "..." lines with mining key address).

2) Configure poa-scripts-validator directory on each validator node:

  • Set an address and ABI of KeysManager contract in the root config.json file.

  • Set zero gas price in poa-scripts-validator/transferRewardToPayoutKey/transferRewardToPayoutKey.js.

    Find the line

    var gasPrice = web3.utils.toWei(big('1'), 'gwei');

    and replace with

    var gasPrice = web3.utils.toWei(big('0'), 'gwei');

3) Change validators INSTANCE_NAME in /home/validator/eth-net-intelligence-api/app.json if necessary.

4) Update bootnodes.txt with the bootnodes.txt file from the Bootnode instance. It will contain 2 lines the first time you run this process, one enode for the MoC node and the second for the Bootnode.

4) Start validator's node.

sudo systemctl restart poa-parity && sleep 10 && sudo systemctl restart poa-netstats

5) Check that the node is synchronized with the MoC and Bootnode nodes.

Open (using your Netstats url instance) to check your nodes.

6) Repeat process for remaining Validator nodes.