@kba-tools/genesis-tool
Version:
A forked repo from ConsenSys which helps to generate genesis block for Besu Network with xemptyBlockPeriod field.
266 lines • 18.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateNetworkConfig = void 0;
exports.main = main;
const questions_1 = require("./questions");
const questionRenderer_1 = require("./questionRenderer");
const networkGenerate_1 = require("./lib/networkGenerate");
const yargs_1 = __importDefault(require("yargs/yargs"));
const chalk_1 = __importDefault(require("chalk"));
// import { CryptoCurve } from "./types/cryptoCurve";
function main() {
return __awaiter(this, void 0, void 0, function* () {
if (process.platform === "win32") {
console.error(chalk_1.default.red("Unfortunately this tool is not compatible with Windows at the moment.\n" +
"We recommend running it under Windows Subsystem For Linux 2 with Docker Desktop.\n" +
"Please visit the following pages for installation instructions.\n\n" +
"https://docs.microsoft.com/en-us/windows/wsl/install-win10\n" +
"https://docs.docker.com/docker-for-windows/wsl/"));
process.exit(1);
}
let answers = {};
if (process.argv.slice(2).length > 0) {
const args = yield (0, yargs_1.default)(process.argv.slice(2))
.options({
consensus: {
type: "string",
demandOption: true,
default: "qbft",
choices: ["ibft", "ibft2", "qbft", "clique", "raft"],
describe: "Consensus algorithm to use",
},
chainID: {
type: "number",
demandOption: true,
default: 1337,
describe: "ChainID for blockchain",
},
blockperiod: {
type: "number",
demandOption: true,
default: 5,
describe: "Number of seconds per block",
},
requestTimeout: {
type: "number",
demandOption: false,
default: 10,
describe: "Minimum request timeout for each round",
},
emptyBlockPeriod: {
type: "number",
demandOption: false,
default: 60,
describe: "Reduce number (seconds) of blocks produced when there are no transactions",
},
xemptyBlockPeriod: {
type: "boolean",
demandOption: false,
default: false,
describe: "Include xemptyBlockPeriod field in genesis block (Besu only)",
},
epochLength: {
type: "number",
demandOption: true,
default: 30000,
describe: "Number of blocks after which votes reset",
},
difficulty: {
type: "number",
demandOption: true,
default: 1,
describe: "Difficulty of network",
},
gasLimit: {
type: "string",
demandOption: true,
default: "0xFFFF",
describe: "Block gas limit",
},
coinbase: {
type: "string",
demandOption: false,
default: "0x0000000000000000000000000000000000000000",
describe: "Address to pay mining rewards to",
},
maxCodeSize: {
type: "number",
demandOption: false,
default: 64,
describe: "Maximum contract size (kb)",
},
txnSizeLimit: {
type: "number",
demandOption: false,
default: 64,
describe: "Maximum transaction size (kb)",
},
validators: {
type: "number",
demandOption: true,
default: 4,
describe: "Number of validator node keys to generate",
},
members: {
type: "number",
demandOption: true,
default: 1,
describe: "Number of member node keys to generate",
},
bootnodes: {
type: "number",
demandOption: true,
default: 2,
describe: "Number of bootnode node keys to generate",
},
// curve: { type: 'string', demandOption: false, default: CryptoCurve.k1, choices: [CryptoCurve.k1, CryptoCurve.r1], describe: 'Type of curve for keys' },
accountPassword: {
type: "string",
demandOption: false,
default: "",
describe: "Password for keys",
},
outputPath: {
type: "string",
demandOption: false,
default: "./output",
describe: "Output path relative to current directory",
},
tesseraEnabled: {
type: "boolean",
demandOption: false,
default: false,
describe: "Whether to generate tessera keys",
},
tesseraPassword: {
type: "string",
demandOption: false,
default: "",
describe: "Set password to encrypt generated keys",
},
quickstartDevAccounts: {
type: "boolean",
demandOption: true,
default: false,
describe: "Include quorum-dev-quickstart test accounts",
},
genesisNodeAllocation: {
type: "string",
demandOption: true,
default: "1000000000000000000000000000",
describe: "Balance allocated to each nodes",
},
alloc: {
type: "string",
demandOption: true,
default: "{}",
describe: "JSON format of the prefunded accounts {'address': { balance: '100000'}}",
},
noOutputTimestamp: {
type: "boolean",
demandOption: false,
default: false,
describe: "Remove generated timestamp from output folder name",
},
})
.coerce(["consensus"], (opt) => {
return opt.toLowerCase();
}).argv;
answers = {
consensus: args.consensus,
chainID: args.chainID,
blockperiod: args.blockperiod,
requestTimeout: args.requestTimeout,
xemptyBlockPeriod: args.xemptyBlockPeriod,
emptyBlockPeriod: args.emptyBlockPeriod,
epochLength: args.epochLength,
difficulty: args.difficulty,
gasLimit: args.gasLimit,
coinbase: args.coinbase,
maxCodeSize: args.maxCodeSize,
txnSizeLimit: args.txnSizeLimit,
validators: args.validators,
members: args.members,
bootnodes: args.bootnodes,
curve: args.curve,
accountPassword: args.accountPassword,
outputPath: args.outputPath,
tesseraEnabled: args.tesseraEnabled,
tesseraPassword: args.tesseraPassword,
quickstartDevAccounts: args.quickstartDevAccounts,
noOutputTimestamp: args.noOutputTimestamp,
prefundedAccounts: args.alloc,
genesisNodeAllocation: args.genesisNodeAllocation,
};
}
else {
const qr = new questionRenderer_1.QuestionRenderer(questions_1.rootQuestion);
answers = yield qr.render(); // begin rendering the questions
// console.log(answers); // log answer output for debugging
}
yield (0, networkGenerate_1.generateNetworkConfig)(answers); // build artifacts
setTimeout(() => {
process.exit(0);
}, 500);
});
}
if (require.main === module) {
// note: main returns a Promise<void>, but we don't need to do anything
// special with it, so we use the void operator to indicate to eslint that
// we left this dangling intentionally...
try {
void main();
}
catch (err) {
if (err &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
err.stack &&
process.argv.length >= 3 &&
process.argv[2] === "--stackTraceOnError") {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
console.error(`Fatal error: ${err.stack}`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
}
else if (err && err.message) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
console.error(`Fatal error: ${err.message}`);
}
else if (err) {
console.error(`Fatal error: ${err}`);
}
else {
console.error(`Fatal error: unknown`);
}
process.exit(1);
}
}
var networkGenerate_2 = require("./lib/networkGenerate");
Object.defineProperty(exports, "generateNetworkConfig", { enumerable: true, get: function () { return networkGenerate_2.generateNetworkConfig; } });
__exportStar(require("./types"), exports);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFRQSxvQkF5TUM7QUFqTkQsMkNBQTJDO0FBQzNDLHlEQUFzRDtBQUN0RCwyREFBOEQ7QUFFOUQsd0RBQWdDO0FBQ2hDLGtEQUEwQjtBQUMxQixxREFBcUQ7QUFFckQsU0FBc0IsSUFBSTs7UUFDeEIsSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQ2pDLE9BQU8sQ0FBQyxLQUFLLENBQ1gsZUFBSyxDQUFDLEdBQUcsQ0FDUCx5RUFBeUU7Z0JBQ3ZFLG9GQUFvRjtnQkFDcEYscUVBQXFFO2dCQUNyRSw4REFBOEQ7Z0JBQzlELGlEQUFpRCxDQUNwRCxDQUNGLENBQUM7WUFDRixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xCLENBQUM7UUFFRCxJQUFJLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDakIsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckMsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFBLGVBQUssRUFBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDNUMsT0FBTyxDQUFDO2dCQUNQLFNBQVMsRUFBRTtvQkFDVCxJQUFJLEVBQUUsUUFBUTtvQkFDZCxZQUFZLEVBQUUsSUFBSTtvQkFDbEIsT0FBTyxFQUFFLE1BQU07b0JBQ2YsT0FBTyxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQztvQkFDcEQsUUFBUSxFQUFFLDRCQUE0QjtpQkFDdkM7Z0JBQ0QsT0FBTyxFQUFFO29CQUNQLElBQUksRUFBRSxRQUFRO29CQUNkLFlB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