Initial commit

This commit is contained in:
viktor 2018-02-13 20:47:21 +03:00
parent 36e6a42e62
commit 9ea871e6e1
34 changed files with 4131 additions and 0 deletions

1
.gitignore vendored
View File

@ -57,3 +57,4 @@ typings/
# dotenv environment variables file
.env
.DS_Store

38
MetaMaskWallet.js Normal file
View File

@ -0,0 +1,38 @@
const fs = require('fs');
class MetaMaskWallet {
constructor() {
this.privateKey;
this.account;
this.networkID;
}
static createMetaMaskWallet(fileName) {
var c=new MetaMaskWallet();
//by default
//c.account="0xF16AB2EA0a7F7B28C267cbA3Ed211Ea5c6e27411";
// c.privateKey="03c06a9fab22fe0add145e337c5a8251e140f74468d72eab17ec7419ab812cd0";
// c.networkID=4;//1-main network by default
c.parser(fileName);
return c;
}
parser(fileName) {
var obj=JSON.parse(fs.readFileSync(fileName,"utf8"));
this.account=obj.account;
this.privateKey=obj.privateKey;
this.networkID=obj.networkID;
}
print() {
console.log("account:"+this.account);
console.log("privateKey:"+this.privateKey);
console.log("networkID:"+this.networkID);
}
}
module.exports={
MetaMaskWallet:MetaMaskWallet
}

BIN
MetaMask_v3.14.1.crx Normal file

Binary file not shown.

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# POA Network test setup
## How it works:
- [x] gets content of master branch of `poa-network-consensus-contracts` repo
- [x] compiles all POA Network contracts
- [x] gets binary code of POA Network Consensus contract
- [x] gets spec.json from `sokol` branch of `chain-spec` repo
- [x] generates custom private, public key and password of MoC and save them to `./keys/moc` folder
- [x] updates spec.json with new MoC and binary code of POA Network Consensus contracts
- [x] starts MoC Parity node
- [x] deploys secondary POA Network contracts
- [x] gets content of master branch of `poa-scripts-moc` repo
- [x] generates 1 initial key with password and copy it to `./keys/initial_keys` folder
- [x] gets content of sokol branch of `poa-dapps-keys-generation` repo
- [x] launches Ceremony DApp is locally builded from repo
- [x] runs e2e tests on Ceremony DApp
- [ ] saves generated production keys with Ceremony DApp to `./keys` folder
- [ ] runs miners nodes
- [ ] gets content of sokol branch of `poa-dapps-validators` repo
- [ ] launches Validators DApp is locally builded from repo
- [ ] runs e2e tests on Validators DApp
- [ ] gets content of sokol branch of `poa-dapps-voting` repo
- [ ] launches Voting DApp is locally builded from repo
- [ ] runs e2e tests on Governance DApp
## Requirements
1. Parity 1.9.2+
## Start test POA setup
1. `npm i`
2. `npm run start-test-setup`
At the successful end of POA test setup start you'll see this message `### POA test setup is configured ###`
### Expected result:
- RPC of Parity node with unlocked MoC account will be on http://localhost:8545
- Spec of the network is generated to `./spec` folder
- MoC keystore file, password, private key is generated to `./keys/moc` folder
- Initial key password, private key is generated to `.keys/initial_keys` folder
- Parity config of MoC node is generated to `./nodes/parity-moc/moc.toml` file
- Addresses of governance smart contracts are generated to `./submodules/poa-network-consensus-contracts/contracts.json`
- ABI of smart contracts are generated to `./submodules/poa-network-consensus-contracts/build/contracts`
## Start e2e Ceremony test
`npm run e2e-ceremony-test` (you need start test POA setup before)
## Finish test POA setup
`npm run stop-test-setup`

56
e2eCeremonyTest.js Normal file
View File

@ -0,0 +1,56 @@
const utils = require("./utils/utils");
const downloadRepo = require("./utils/downloadRepo");
const Constants = require("./utils/constants");
const constants = Constants.constants;
const dir = require('node-dir');
const webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome');
require("chromedriver");
const metaMaskWallet=require('./MetaMaskWallet.js');
const MetaMaskWallet=metaMaskWallet.MetaMaskWallet;
const meta=require('./pages/MetaMask.js');
const buttonSubmit=require('./pages/MetaMask.js');
const ceremony=require('./pages/Ceremony.js');
const timeout = ms => new Promise(res => setTimeout(res, ms))
const ceremonyURL = 'http://localhost:3000'
main()
async function main() {
let options = new chrome.Options();
options.addExtensions('./MetaMask_v3.14.1.crx');
options.addArguments('start-maximized');
options.addArguments('disable-popup-blocking');
let driver = new webdriver.Builder()
.withCapabilities(options.toCapabilities())
.build();
var files = dir.files(constants.initialKeysFolder, {sync:true});
var wallet = MetaMaskWallet.createMetaMaskWallet(files[1]);
var metaMask = new meta.MetaMask(driver, wallet);
var ceremonyPage = await new ceremony.Ceremony(driver,ceremonyURL);
metaMask.open();
metaMask.activate();
ceremonyPage.open();
//ceremonyPage.clickButtonGenerateKeys();
driver.sleep(2000);
ceremonyPage.clickButtonGenerateKeys();
driver.sleep(2000);
metaMask.switchToAnotherPage();
driver.sleep(2000);
if ( await metaMask.isElementPresent(buttonSubmit.buttonSubmit)) {
metaMask.submitTransaction();
ceremonyPage.switchToAnotherPage();
}
}

45
getPrivateInitialKeys.js Normal file
View File

@ -0,0 +1,45 @@
const dir = require('node-dir');
const Constants = require("./utils/constants");
const constants = Constants.constants;
const keythereum = require("keythereum");
const path = require('path');
const fs = require('fs');
main()
function main() {
let initial_keys = {};
dir.readFiles(constants.scriptsMocOutputFolder,
function(err, content, filepath, next) {
let filename = path.basename(filepath)
if (filename == '.gitkeep') {
return next();
}
let key = path.parse(filename).name;
if (!initial_keys[key])
initial_keys[key] = {};
if (filename.includes(".json")) {
let keyStore = content;
initial_keys[key].keyStore = keyStore;
} else if (filename.includes(".key")) {
initial_keys[key].password = content
}
if (initial_keys[key].password && initial_keys[key].keyStore)
initial_keys[key].privateKey = keythereum.recover(initial_keys[key].password, JSON.parse(initial_keys[key].keyStore)).toString('hex');
if (err) throw err;
next();
},
function(err, files){
for (let initial_key in initial_keys) {
let keyObj = {
address: `0x${initial_key}`,
privateKey: initial_keys[initial_key].privateKey
}
fs.writeFileSync(`${constants.initialKeysFolder}${keyObj.address}`, JSON.stringify(keyObj, null, 2));
}
}
);
}

View File

View File

0
keys/moc/.gitkeep Normal file
View File

View File

View File

0
nodes/.gitkeep Normal file
View File

22
nodes/node-master.toml Normal file
View File

@ -0,0 +1,22 @@
[parity]
chain = "./spec/spec.json"
base_path = "./nodes/parity-moc"
[network]
port = 30300
[rpc]
cors = ["null"]
hosts = ["all"]
port = 8545
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[account]
unlock = []
password = ["./keys/moc/moc.pwd"]
[mining]
force_sealing = true
engine_signer = ""
reseal_on_txs = "none"

31
nodes/node-slave.toml Normal file
View File

@ -0,0 +1,31 @@
[parity]
chain = "./spec/spec.json"
base_path = ""
[network]
port = 30301
discovery=true
reserved_peers="./reserved_peers"
[rpc]
cors = ["null"]
hosts = ["all"]
port = 8554
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[account]
unlock = []
password = []
[mining]
force_sealing = true
engine_signer = ""
reseal_on_txs = "none"
[websockets]
disable = false
port = 8546
interface = "all"
origins = ["all"]
apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
hosts = ["all"]

View File

View File

View File

0
nodes/reserved_peers Normal file
View File

3249
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
package.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "poa-test-setup",
"version": "0.1.0",
"private": false,
"homepage": "",
"dependencies": {
"chromedriver": "^2.35.0",
"create-poa-crowdsale": "^1.0.33",
"download-git-repo": "^1.0.2",
"keythereum": "^1.0.2",
"node-dir": "^0.1.17",
"node-fetch": "^2.0.0",
"password-generator": "^2.2.0",
"path": "^0.12.7",
"selenium-webdriver": "^3.6.0",
"toml": "^2.3.3",
"toml-js": "0.0.8",
"web3": "^1.0.0-beta.29"
},
"scripts": {
"start-test-setup": "npm run download-repos && npm run prepare-contracts-repo && npm run prepare-moc-node && npm run start-moc-node && npm run deploy-secondary-contracts && npm run prepare-scrips-moc-repo && npm run prepare-ceremony-dapp && npm run prepare-ceremony-dapp-more && npm run generate-initial-keys && npm run get-private-initial-keys && npm run start-ceremony && npm run test-setup-is-started",
"download-repos": "git submodule update --init --recursive --remote",
"prepare-contracts-repo": "bash ./scripts/prepare-contracts-repo",
"prepare-moc-node": "node prepareMoCNode",
"start-moc-node": "parity --config ./nodes/parity-moc/moc.toml > /dev/null 2>&1 &",
"deploy-secondary-contracts": "bash ./scripts/deploy-secondary-contracts",
"prepare-scrips-moc-repo": "node prepareMoCScripts",
"prepare-ceremony-dapp": "node prepareCeremonyDapp",
"prepare-ceremony-dapp-more": "cd ./submodules/poa-dapps-keys-generation && npm i > /dev/null 2>&1",
"generate-initial-key": "bash ./scripts/generate-initial-key",
"generate-initial-keys": "bash ./scripts/generate-initial-keys",
"get-private-initial-keys": "node getPrivateInitialKeys",
"start-ceremony": "cd ./submodules/poa-dapps-keys-generation && npm start > /dev/null 2>&1 &",
"test-setup-is-started": "echo '### POA test setup is configured ###'",
"e2e-ceremony-test": "node e2eCeremonyTest",
"stop-test-setup": "rm -rf ./submodules/poa-dapps-keys-generation && rm -rf ./submodules/poa-scripts-moc/generateInitialKey/output/* && git clean -f -d && kill -9 $(lsof -t -i:8545)"
}
}

30
pages/Ceremony.js Normal file
View File

@ -0,0 +1,30 @@
const page=require('./Page.js');
const webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome'),
firefox = require('selenium-webdriver/firefox'),
by = require('selenium-webdriver/lib/by');
const generateKeysButton = by.By.xpath("//*[@id=\"root\"]/div/section/div/div");
class Ceremony extends page.Page{
constructor(driver,URL){
super(driver);
this.URL=URL;
}
open() {
this.driver.get(this.URL);
}
clickButtonGenerateKeys(){
super.clickWithWait(generateKeysButton);
}
open() {
this.driver.get(this.URL);
}
}
module.exports.Ceremony=Ceremony;

159
pages/MetaMask.js Normal file
View File

@ -0,0 +1,159 @@
const key = require('selenium-webdriver').Key;
const page=require('./Page.js');
const webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome'),
firefox = require('selenium-webdriver/firefox'),
by = require('selenium-webdriver/lib/by');
const By=by.By;
//"chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn//popup.html"
const IDMetaMask="nkbihfbeogaeaoehlefnkodbefgpgknn";
const URL="chrome-extension://"+IDMetaMask+"//popup.html";
const passMetaMask="kindzadza";
const fieldEnterPass= By.xpath("//*[@id=\"password-box\"]");
const buttonUnlock=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div[1]/button");
const buttonBuy= By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div/div[2]/button[1]");
const buttonSend= By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div/div[2]/button[2]");
const buttonSubmit=By.xpath("//*[@id=\"pending-tx-form\"]/div[3]/input");
const fieldGasPrise=By.xpath("//*[@id=\"pending-tx-form\"]/div[1]/div[2]/div[3]/div[2]/div/div/input");
///////Imported from TestCircle//////
const buttonAccept=By.xpath('//*[@id="app-content"]/div/div[4]/div/button');
const agreement=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div/div/p[1]/strong");
const fieldNewPass=By.xpath("//*[@id=\"password-box\"]");
const fieldConfirmPass=By.xpath("//*[@id=\"password-box-confirm\"]");
const buttonCreate=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/button");
const fieldSecretWords=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/textarea");
const buttonIveCopied=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/button[1]");
//const popupNetwork=By.xpath("//*[@id=\"network_component\"]/div/i");
const popupNetwork=By.className("network-name");
//const popupRinkeby=By.className("menu-icon golden-square");
const popupRinkeby=By.css("Rinkeby Test Network");
const popupAccount=By.xpath("//*[@id=\"app-content\"]/div/div[1]/div/div[2]/span/div");
const popupImportAccount=By.xpath("//*[@id=\"app-content\"]/div/div[1]/div/div[2]/span/div/div/span/div/li[3]/span");
const popupImportAccountCSS="#app-content > div > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(4) > span";
const fieldPrivateKey=By.xpath("//*[@id=\"private-key-box\"]");
const pass="kindzadza";
const buttonImport=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div[3]/button");
const secretWords="mask divorce brief insane improve effort ranch forest width accuse wall ride";
const amountEth=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div/div[2]/div[1]/div/div/div[1]/div[1]");
const fieldNewRPCURL=By.id("new_rpc");
const buttonSave=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div[3]/div/div[2]/button");
//const arrowBackRPCURL=By.className("fa fa-arrow-left fa-lg cursor-pointer");
const arrowBackRPCURL=By.xpath("//*[@id=\"app-content\"]/div/div[4]/div/div[1]/i");
var lengthNetworkMenu=6;
var networks=[];
class MetaMask extends page.Page{
constructor(driver,wallet) {
super(driver);
this.URL=URL;
this.wallet=wallet;
}
setGasPriceTransaction(price) {
super.fillWithWait(fieldGasPrise,price);
}
clickButtonSubmit() {
super.clickWithWait(buttonSubmit);
}
clickPopupNetwork() {
super.clickWithWait(popupNetwork);
}
isReadyTransaction() {
return this.isElementPresent(buttonSubmit);
}
submitTransaction() {
this.clickButtonSubmit();
}
unlock() {
//this.open();
super.fillWithWait(fieldEnterPass,passMetaMask);
super.clickWithWait(buttonUnlock);
}
open() {
this.driver.get(this.URL);
}
clickDotMenu() {
super.clickWithWait(dotMenu);
}
getAddressWallet() {
//super.clickWithWait(addrWallet);
return this.driver.findElement(addrWallet).getText();
}
activate() {
super.clickWithWait(buttonAccept);
const action=this.driver.actions();
action.click(this.driver.findElement(agreement)).perform();
//this.driver.findElement(agreement).click();
// this.driver.sleep(2000);
for (var i=0;i<9;i++) {
action.sendKeys(key.TAB).perform();
//this.driver.findElement(agreement).sendKeys(key.TAB);
}
super.clickWithWait(buttonAccept);
super.fillWithWait(fieldNewPass,pass);
super.fillWithWait(fieldConfirmPass,pass);
super.clickWithWait(buttonCreate);
this.driver.sleep(1500);
// this.driver.findElement(fieldSecretWords).getText().then(console.log);
super.clickWithWait(buttonIveCopied);
this.chooseProvider();
super.clickWithWait(popupAccount);
this.driver.executeScript("document.getElementsByClassName('dropdown-menu-item')[2].click();");
super.fillWithWait(fieldPrivateKey,this.wallet.privateKey);
this.driver.sleep(1500);
super.clickWithWait(buttonImport);
// this.driver.sleep(1500);
//this.driver.findElement(amountEth).getText().then(console.log);
}
async isElementPresent(element)
{
return await super.isElementPresent(element);
}
chooseProvider(){
super.clickWithWait(popupNetwork);
var n=4;
if (n<=4)this.driver.executeScript("document.getElementsByClassName('dropdown-menu-item')["+n+"].click();");
}
addNetwork(){
var url="http://localhost:8545";
this.driver.executeScript("" +
"document.getElementsByClassName('dropdown-menu-item')["+(lengthNetworkMenu-1)+"].click();");
super.fillWithWait(fieldNewRPCURL,url);
super.clickWithWait(buttonSave);
this.driver.sleep(1000);
super.clickWithWait(arrowBackRPCURL);
lengthNetworkMenu++;
};
}
module.exports={
MetaMask:MetaMask,
buttonSubmit:buttonSubmit
}

77
pages/Page.js Normal file
View File

@ -0,0 +1,77 @@
const webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome'),
firefox = require('selenium-webdriver/firefox'),
by = require('selenium-webdriver/lib/by');
const key = require('selenium-webdriver').Key;
const Twait=20000;
console.log(module.filename);
class Page {
constructor(driver){
this.driver=driver;
this.pageID;
this.footer;
this.header;
}
async isElementPresent(element) {
var q;
try {
q = await this.driver.findElement(element).isDisplayed();
} catch (err) {
q = false;
}
return q;
}
clearField(element){
let field = this.driver.wait(webdriver.until.elementLocated(element), Twait);
const c=key.chord(key.CONTROL,"a");
const action=this.driver.actions();
action.click(field).perform();
//action.click(field).perform();
this.driver.sleep(500);
action.sendKeys(c).perform();
action.sendKeys(key.DELETE).perform();
action.sendKeys(key.DELETE).perform();
}
clickWithWait(element) {
let button = this.driver.wait(webdriver.until.elementLocated(element), Twait);
button.click();
}
fillWithWait(element,k) {
let field = this.driver.wait(webdriver.until.elementLocated(element), Twait);
field.sendKeys(k);
}
refresh(){
this.driver.navigate().refresh();
}
switchToAnotherPage(){
let dr=this.driver;
dr.getWindowHandle().then(function (mainWindowHandle) {
dr.getAllWindowHandles().then(function (windowHandles) {
windowHandles.forEach(function(handle){
if(!(handle===mainWindowHandle))
{
dr.switchTo().window(handle);
}
});
});
});
}
}
module.exports.Page=Page;

22
prepareCeremonyDapp.js Normal file
View File

@ -0,0 +1,22 @@
const fs = require('fs');
const Constants = require("./utils/constants");
const constants = Constants.constants;
const utils = require("./utils/utils");
main()
function main() {
const pathToAddressesJSON = `${constants.pathToContractRepo}/${constants.addressesSourceFile}`;
const addresses = JSON.parse(fs.readFileSync(pathToAddressesJSON));
const addition = `const local = { "KEYS_MANAGER_ADDRESS": "${addresses.KEYS_MANAGER_ADDRESS}" };`
let addressesFromDapp = fs.readFileSync(`${constants.pathToCeremonyDAppRepo}/src/addresses.js`, 'utf8');
let lastImport = `import helpers from "./helpers";`;
addressesFromDapp = addressesFromDapp.replace(lastImport, lastImport + addition)
addressesFromDapp = addressesFromDapp.replace('resolve({addresses: json', 'resolve({addresses: local')
fs.writeFileSync(`${constants.pathToCeremonyDAppRepo}/src/addresses.js`, addressesFromDapp);
console.log("Ceremony Dapp is prepared");
}

128
prepareMoCNode.js Normal file
View File

@ -0,0 +1,128 @@
const downloadRepo = require("./utils/downloadRepo");
const Constants = require("./utils/constants");
const constants = Constants.constants;
const fs = require('fs');
const keythereum = require("keythereum");
const generatePassword = require('password-generator');
const Web3 = require('web3');
const utils = require("./utils/utils");
const toml = require('toml');
const tomlJS = require('toml-js');
main()
async function main() {
const consensusObj = JSON.parse(fs.readFileSync(constants.pathToConsensusContract));
const consensusBytecode = consensusObj.bytecode;
const mocPassword = generatePassword(20, false)
const keyObject = await generateAddress(mocPassword)
const moc = `0x${keyObject.address}`;
const keyStoreFileName = `${constants.mocKeysFolder}${keyObject.address}.json`;
const privateKeyFileName = `${constants.mocKeysFolder}moc.key`;
const passwordFileName = `${constants.mocKeysFolder}moc.pwd`;
const mocKeyStore = JSON.stringify(keyObject);
const privateKey = keythereum.recover(mocPassword, keyObject).toString('hex');
let spec
try {
spec = await utils.getSpec('sokol');
} catch (e) {
return console.log(e.message)
}
utils.clearFolder(constants.mocKeysFolder);
let POAKeysFolder = `${constants.masterNodeKeysFolder}${spec.name}`;
if (!fs.existsSync(POAKeysFolder)){
fs.mkdirSync(POAKeysFolder);
}
utils.clearFolder(POAKeysFolder);
try { await utils.saveToFile(keyStoreFileName, mocKeyStore) }
catch (err) { return console.log(err.message); }
console.log(`MoC keystore file ${moc} is generated to ${keyStoreFileName}`);
const key = {
address: moc,
privateKey: privateKey
}
try { await utils.saveToFile(privateKeyFileName, JSON.stringify(key, null, 2)) }
catch (err) { return console.log(err.message); }
console.log(`MoC private key are generated to ${privateKeyFileName}`);
try { await utils.saveToFile(passwordFileName, mocPassword) }
catch (err) { return console.log(err.message); }
console.log(`MoC password is generated to ${passwordFileName}`);
utils.clearFolder(constants.masterNodeKeysFolder);
const masterNodeKeyStoreFolder = `${constants.masterNodeKeysFolder}${spec.name}`;
fs.existsSync(masterNodeKeyStoreFolder) || fs.mkdirSync(masterNodeKeyStoreFolder);
const masterNodeParentKeyStorePath = `${masterNodeKeyStoreFolder}/moc_${moc}.json`;
try { await utils.saveToFile(masterNodeParentKeyStorePath, mocKeyStore) }
catch (err) { return console.log(err.message); }
console.log(`Keystore file is copied to ${masterNodeParentKeyStorePath}`);
web3 = new Web3(new Web3.providers.HttpProvider('https://sokol.poa.network'));
const mocABIEncoded = web3.eth.abi.encodeParameters(['address', `address[]`], [moc, []]).substr(2);
const newConsensusBytecode = consensusBytecode + mocABIEncoded;
spec.accounts[moc] = {
balance: '252460800000000000000000000'
};
spec.accounts[constants.poaNetworkConsensusContractAddress] = {
balance: '1',
constructor: newConsensusBytecode
};
spec.engine.authorityRound.params.validators.multi = {
"0": {
"safeContract": constants.poaNetworkConsensusContractAddress
}
};
utils.clearFolder(constants.specFolder);
try { await utils.saveToFile(`${constants.specFolder}spec.json`, JSON.stringify(spec, null, 2)) }
catch (err) { return console.log(err.message); }
console.log(`spec.json is generated to ${constants.specFolder}`);
const masterNodeExampleTomlPath = `${constants.nodeFolder}node-master.toml`;
const masterNodeTomlContent = fs.readFileSync(masterNodeExampleTomlPath, "utf8");
const masterNodeToml = toml.parse(masterNodeTomlContent);
masterNodeToml.account.unlock = [moc];
masterNodeToml.mining.engine_signer = moc;
const newToml = tomlJS.dump(masterNodeToml);
utils.removeFolderRecursive(`${constants.masterNodeFolder}cache`);
utils.removeFolderRecursive(`${constants.masterNodeFolder}chains`);
utils.removeFolderRecursive(`${constants.masterNodeFolder}dapps`);
utils.removeFolderRecursive(`${constants.masterNodeFolder}network`);
const mocTomlPath = `${constants.masterNodeFolder}moc.toml`;
try { await utils.saveToFile(`${mocTomlPath}`, newToml)}
catch (err) { return console.log(err.message); }
console.log("MoC node is prepared");
}
//generates initial key keystore file
function generateAddress(password) {
return new Promise((resolve, reject) => {
let params = { keyBytes: 32, ivBytes: 16 };
let dk = keythereum.create(params);
keythereum.create(params, function (dk) {
let options = {};
keythereum.dump(password, dk.privateKey, dk.salt, dk.iv, options, function (keyObject) {
resolve(keyObject);
});
});
})
}

22
prepareMoCScripts.js Normal file
View File

@ -0,0 +1,22 @@
const fs = require('fs');
const Constants = require("./utils/constants");
const constants = Constants.constants;
const utils = require("./utils/utils");
main()
function main() {
const generateInitialKeyConfig = JSON.parse(fs.readFileSync(constants.scriptsMocConfigPath));
const keysManagerObj = JSON.parse(fs.readFileSync(constants.pathToKeysManagerContract));
const pathToAddressesJSON = `${constants.pathToContractRepo}/${constants.addressesSourceFile}`;
const addresses = JSON.parse(fs.readFileSync(pathToAddressesJSON));
generateInitialKeyConfig.Ethereum.contracts.KeysManager.addr = addresses.KEYS_MANAGER_ADDRESS;
generateInitialKeyConfig.Ethereum.contracts.KeysManager.abi = keysManagerObj.abi;
utils.saveToFile(constants.scriptsMocConfigPath, JSON.stringify(generateInitialKeyConfig, null, 2));
console.log("MoC script is prepared");
}

View File

@ -0,0 +1,9 @@
#!/bin/bash
directory=./submodules/poa-network-consensus-contracts
consensus="0x8bf38d4764929064f2d4d3a56520a76ab3df415b"
moc_object=$(cat ./keys/moc/moc.key)
moc=$(node -pe 'JSON.parse(process.argv[1]).address' "${moc_object}")
cmd=$(cd ${directory} && SAVE_TO_FILE=true POA_NETWORK_CONSENSUS_ADDRESS=${consensus} MASTER_OF_CEREMONY=${moc} ./node_modules/.bin/truffle migrate --reset --network sokol)
#echo ${cmd}

View File

@ -0,0 +1,13 @@
#!/bin/bash
directory=./submodules/poa-scripts-moc/generateInitialKey
node_modules=${directory}/node_modules
if [ ! -d ${node_modules} ]; then
cmd=$(cd ${directory} && npm i && node generateInitialKey.js)
else
cmd2=$(cd ${directory} && node generateInitialKey.js)
fi

View File

@ -0,0 +1,9 @@
#!/bin/bash
initial_keys_number=1
for i in {1..${initial_keys_number}}
do
npm run generate-initial-key
done
echo "All initial keys are generated"

View File

@ -0,0 +1,12 @@
#!/bin/bash
directory=./submodules/poa-network-consensus-contracts
build_dir=${directory}/build
if [ -d ${directory} ]; then
if [ ! -d ${build_dir} ]; then
cmd=$(cd ${directory} && npm i && bash ./make_flat.sh && ./node_modules/.bin/truffle compile)
fi
fi

0
spec/.gitkeep Normal file
View File

35
utils/constants.js Normal file
View File

@ -0,0 +1,35 @@
let constants = {};
constants.organization = 'poanetwork';
constants.chainSpecRepoName = 'poa-chain-spec';
constants.contractsRepoName = 'poa-network-consensus-contracts';
constants.pathToContractRepo = `./submodules/${constants.contractsRepoName}`;
constants.scriptsMocRepoName = 'poa-scripts-moc';
constants.pathToScriptsMocRepo = `./submodules/${constants.scriptsMocRepoName}`;
constants.CeremonyDAppRepoName = 'poa-dapps-keys-generation';
constants.pathToCeremonyDAppRepo = `./submodules/${constants.CeremonyDAppRepoName}`;
constants.scriptsMocConfigPath = `${constants.pathToScriptsMocRepo}/config.json`;
constants.scriptsMocOutputFolder = `${constants.pathToScriptsMocRepo}/generateInitialKey/output`;
constants.addressesSourceFile = 'contracts.json';
constants.contractsFolder = `${constants.pathToContractRepo}/build/contracts`;
constants.pathToConsensusContract = `${constants.contractsFolder}/PoaNetworkConsensus.json`;
constants.pathToKeysManagerContract = `${constants.contractsFolder}/KeysManager.json`;
constants.keysFolder = `./keys/`;
constants.nodeFolder = `./nodes/`;
constants.masterNodeFolder = `./nodes/parity-moc/`;
constants.masterNodeKeysFolder = `${constants.masterNodeFolder}keys/`;
constants.specFolder = `./spec/`;
constants.mocKeysFolder = `${constants.keysFolder}moc/`;
constants.initialKeysFolder = `${constants.keysFolder}initial_keys/`;
constants.poaNetworkConsensusContractAddress = '0x8bf38d4764929064f2d4d3a56520a76ab3df415b';
constants.ABIsSources = {
'KeysManager': 'KeysManager.abi.json',
'PoaNetworkConsensus': 'PoaNetworkConsensus.abi.json',
'BallotStorage': 'BallotsStorage.abi.json',
'ValidatorMetadata': 'ValidatorMetadata.abi.json',
'VotingToChangeKeys': 'VotingToChangeKeys.abi.json',
'VotingToChangeMinThreshold': 'VotingToChangeMinThreshold.abi.json',
'VotingToChangeProxyAddress': 'VotingToChangeProxyAddress.abi.json'
};
module.exports = {
constants
}

13
utils/downloadRepo.js Normal file
View File

@ -0,0 +1,13 @@
const Constants = require("./constants");
const constants = Constants.constants;
const download = require('download-git-repo');
async function downloadRepo(repoName) {
const repo = `${constants.organization}/${repoName}`;
download(repo, `./tests/${repoName}`, function (err) {
console.log(err ? err.message : `${repo} is downloaded`)
})
}
module.exports = downloadRepo

74
utils/utils.js Normal file
View File

@ -0,0 +1,74 @@
const Constants = require("./constants");
const constants = Constants.constants;
const fetch = require('node-fetch');
const fs = require('fs');
function ABIURL(branch, contract) {
const URL = `https://raw.githubusercontent.com/${constants.organization}/${constants.chainSpecRepoName}/${branch}/abis/${constants.ABIsSources[contract]}`;
return URL;
}
function specURL(branch) {
const URL = `https://raw.githubusercontent.com/${constants.organization}/${constants.chainSpecRepoName}/${branch}/spec.json`;
return URL;
}
function getABI(branch, contract) {
let addr = ABIURL(branch, contract);
return fetch(addr).then(function(response) {
return response.json();
})
}
function getSpec(branch) {
let addr = specURL(branch);
return fetch(addr).then(function(response) {
return response.json();
})
}
let clearFolder = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function(file, index){
var curPath = path + "/" + file;
if (!fs.lstatSync(curPath).isDirectory()) {
if (file != '.gitkeep') {
fs.unlinkSync(curPath);
}
}
});
}
};
let removeFolderRecursive = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function(file, index){
var curPath = path + "/" + file;
if (fs.lstatSync(curPath).isDirectory()) { // recurse
removeFolderRecursive(curPath);
} else { // delete file
if (file != '.gitkeep') {
fs.unlinkSync(curPath);
}
}
});
fs.rmdirSync(path);
}
};
function saveToFile(filename, content) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, content, (err) => {
if (err) reject(err);
resolve();
});
});
}
module.exports = {
getSpec,
getABI,
clearFolder,
removeFolderRecursive,
saveToFile
}