247 lines
6.3 KiB
JavaScript
Executable file
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()));
|