itns-sidechain/etc/genesis
2020-02-03 17:56:33 -08:00

247 lines
6.3 KiB
JavaScript
Executable file

#!/usr/bin/env node
/* eslint quotes: "off" */
'use strict';
const fs = require('bfile');
const Path = require('path');
const BLAKE2b = require('bcrypto/lib/blake2b');
const merkle = require('bcrypto/lib/mrkl');
const consensus = require('../lib/protocol/consensus');
const Network = require('../lib/protocol/network');
const Address = require('../lib/primitives/address');
const AirdropProof = require('../lib/primitives/airdropproof');
const Block = require('../lib/primitives/block');
const TX = require('../lib/primitives/tx');
const Witness = require('../lib/script/witness');
const util = require('../lib/utils/util');
const reserved = require('../lib/covenants/reserved');
const {AIRDROP_ROOT, FAUCET_ROOT} = AirdropProof;
const NAME_ROOT = merkle.createRoot(BLAKE2b, [...reserved.keys()]);
const networks = {
main: Network.get('main'),
testnet: Network.get('testnet'),
regtest: Network.get('regtest'),
simnet: Network.get('simnet')
};
function createGenesis(options) {
const genesis = Address.fromHash(consensus.GENESIS_KEY, 0);
const nonce = options.nonce >>> 0;
let flags = options.flags;
if (!flags)
flags = consensus.ZERO_HASH;
const tx = new TX({
version: 0,
inputs: [{
prevout: {
hash: consensus.ZERO_HASH,
index: 0xffffffff
},
witness: new Witness([flags, NAME_ROOT, AIRDROP_ROOT, FAUCET_ROOT]),
sequence: 0xffffffff
}],
outputs: [
{
value: consensus.GENESIS_REWARD,
address: genesis
}
],
locktime: 0
});
tx.refresh();
const block = new Block({
version: 0,
prevBlock: consensus.ZERO_HASH,
merkleRoot: consensus.ZERO_HASH,
witnessRoot: consensus.ZERO_HASH,
treeRoot: consensus.ZERO_HASH,
reservedRoot: consensus.ZERO_HASH,
time: options.time,
bits: options.bits,
nonce: nonce,
extraNonce: Buffer.alloc(consensus.NONCE_SIZE, 0x00),
mask: consensus.ZERO_HASH
});
block.txs.push(tx);
block.merkleRoot = block.createMerkleRoot();
block.witnessRoot = block.createWitnessRoot();
return block;
}
function formatJS(name, block) {
let out = '';
out += `genesis.${name} = {\n`;
out += ` version: ${block.version},\n`;
out += ` hash: Buffer.from(\n`;
out += ` '${block.hash().toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` prevBlock: Buffer.from(\n`;
out += ` '${block.prevBlock.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` merkleRoot: Buffer.from(\n`;
out += ` '${block.merkleRoot.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` witnessRoot: Buffer.from(\n`;
out += ` '${block.witnessRoot.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` treeRoot: Buffer.from(\n`;
out += ` '${block.treeRoot.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` reservedRoot: Buffer.from(\n`;
out += ` '${block.reservedRoot.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` time: ${block.time},\n`;
out += ` bits: 0x${util.hex32(block.bits)},\n`;
out += ` nonce: 0x${util.hex32(block.nonce)},\n`;
out += ` extraNonce: Buffer.from(\n`;
out += ` '${block.extraNonce.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` mask: Buffer.from(\n`;
out += ` '${block.mask.toString('hex')}',\n`;
out += ` 'hex'),\n`;
out += ` height: 0,\n`;
out += ` magic: ${block.hash().readUInt32BE(0)}\n`;
out += `};`;
return out;
}
function formatC(name, block) {
const hdr = block.toHead().toString('hex');
const upper = name.toUpperCase();
const chunks = [`static const uint8_t HSK_GENESIS_${upper}[] = ""`];
for (let i = 0; i < hdr.length; i += 26)
chunks.push(` "${hdr.slice(i, i + 26)}"`);
const hex = chunks.join('\n');
const data = hex.replace(/([a-f0-9]{2})/g, '\\x$1');
return `${data};`;
}
function writeJS(blocks) {
const code = [
'// Autogenerated, do not edit.',
'',
`'use strict';`,
'',
`const data = require('./genesis-data.json');`,
'const genesis = exports;',
''
];
for (const name of Object.keys(blocks)) {
const upper = name[0].toUpperCase() + name.substring(1);
const block = blocks[name];
code.push('/*');
code.push(` * ${upper}`);
code.push(' */');
code.push('');
code.push(formatJS(name, block));
code.push('');
code.push(`genesis.${name}Data = Buffer.from(data.${name}, 'base64');`);
code.push('');
}
const file = Path.resolve(__dirname, '..', 'lib', 'protocol', 'genesis.js');
fs.writeFileSync(file, code.join('\n'));
}
function writeJSON(blocks) {
const json = JSON.stringify({
main: blocks.main.encode().toString('base64'),
testnet: blocks.testnet.encode().toString('base64'),
regtest: blocks.regtest.encode().toString('base64'),
simnet: blocks.simnet.encode().toString('base64')
}, null, 2);
const file = Path.resolve(__dirname, '..', 'lib',
'protocol', 'genesis-data.json');
fs.writeFileSync(file, json + '\n');
}
function writeC(blocks) {
const code = [
'#ifndef _HSK_GENESIS_H',
'#define _HSK_GENESIS_H',
'',
'/* Autogenerated, do not edit. */',
''
];
for (const name of Object.keys(blocks)) {
const upper = name[0].toUpperCase() + name.substring(1);
const block = blocks[name];
code.push('/*');
code.push(` * ${upper}`);
code.push(' */');
code.push('');
code.push(formatC(name, block));
code.push('');
}
code.push('#endif');
code.push('');
const file = Path.resolve(__dirname, '..', 'etc', 'genesis.h');
fs.writeFileSync(file, code.join('\n'));
}
function generate() {
// From Bitcoin block 615817.
const time = 1580745078;
const flags = Buffer.from(
'50b8937fc5def08f9f3cbda7e5f08c706edb80aba5880c000000000000000000',
'hex');
return {
main: createGenesis({
bits: networks.main.pow.bits,
time,
flags
}),
testnet: createGenesis({
bits: networks.testnet.pow.bits,
time: time + 1,
flags
}),
regtest: createGenesis({
bits: networks.regtest.pow.bits,
time: time + 2,
flags
}),
simnet: createGenesis({
bits: networks.simnet.pow.bits,
time: time + 3,
flags
})
};
}
function main(argv) {
const blocks = generate();
writeJS(blocks);
writeJSON(blocks);
writeC(blocks);
return 0;
}
process.exit(main(process.argv.slice()));