int-cli
Version:
INT is the new generation of bottom-up created system of IoT and blockchain
161 lines (160 loc) • 6.14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require('assert');
const error_code_1 = require("../error_code");
const address_1 = require("../address");
const value_chain_1 = require("../value_chain");
const chain_1 = require("./chain");
const consensus_node_1 = require("./consensus_node");
class DbftMinerChain extends chain_1.DbftChain {
_defaultNetworkOptions() {
return {
netType: 'validators',
initialValidator: this.globalOptions.superAdmin,
minConnectionRate: this.globalOptions.agreeRateNumerator / this.globalOptions.agreeRateDenominator,
};
}
get headerStorage() {
return this.m_headerStorage;
}
async _calcuteReqLimit(fromHeader, limit) {
let hr = await this.getHeader(fromHeader);
let reSelectionBlocks = this.globalOptions.reSelectionBlocks;
return reSelectionBlocks - (hr.header.number % reSelectionBlocks);
}
}
class DbftMiner extends value_chain_1.ValueMiner {
constructor(options) {
super(options);
this.m_miningBlocks = new Map();
}
get chain() {
return this.m_chain;
}
get address() {
return this.m_address;
}
_chainInstance() {
return new DbftMinerChain(this.m_constructOptions);
}
parseInstanceOptions(options) {
let { err, value } = super.parseInstanceOptions(options);
if (err) {
return { err };
}
if (!options.origin.get('minerSecret')) {
this.m_logger.error(`invalid instance options not minerSecret`);
return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM };
}
value.minerSecret = Buffer.from(options.origin.get('minerSecret'), 'hex');
return { err: error_code_1.ErrorCode.RESULT_OK, value };
}
async _createBlock(header) {
const block = this.chain.newBlock(header);
await this._collectTransactions(block);
await this._decorateBlock(block);
const cer = await this._createExecuteRoutine(block);
if (cer.err) {
return { err: cer.err };
}
// first broadcast,then execute
const err = await this.m_consensusNode.newProposal(cer.routine.block);
if (err) {
this._setIdle(cer.routine.name);
return { err };
}
return cer.next();
}
async initialize(options) {
this.m_secret = options.minerSecret;
this.m_address = address_1.addressFromSecretKey(this.m_secret);
if (!options.coinbase) {
this.coinbase = this.m_address;
}
let err = await super.initialize(options);
if (err) {
this.m_logger.error(`dbft miner super initialize failed, errcode ${err}`);
return err;
}
this.m_consensusNode = new consensus_node_1.DbftConsensusNode({
network: this.m_chain.node.getNetwork(),
globalOptions: this.m_chain.globalOptions,
secret: this.m_secret
});
err = await this.m_consensusNode.init();
if (err) {
this.m_logger.error(`dbft miner consensus node init failed, errcode ${err}`);
return err;
}
let tip = this.chain.tipBlockHeader;
err = await this._updateTip(tip);
if (err) {
this.m_logger.error(`dbft miner initialize failed, errcode ${err}`);
return err;
}
this.m_consensusNode.on('createBlock', async (header) => {
if (header.preBlockHash !== this.chain.tipBlockHeader.hash) {
this.m_logger.warn(`mine block skipped`);
return;
}
this.m_logger.info(`begin create block ${header.hash} ${header.number} ${header.view}`);
let cbr = await this._createBlock(header);
if (cbr.err) {
this.m_logger.error(`create block failed `, cbr.err);
}
else {
this.m_logger.info(`create block finsihed `);
}
});
this.m_consensusNode.on('verifyBlock', async (block) => {
this.m_logger.info(`begin verify block ${block.hash} ${block.number}`);
const cer = await this._createExecuteRoutine(block);
if (cer.err) {
this.m_logger.error(`dbft verify block failed `, cer.err);
return;
}
const nr = await cer.next();
if (nr.err) {
this.m_logger.error(`dbft verify block failed `, nr.err);
return;
}
});
this.m_consensusNode.on('mineBlock', async (block, signs) => {
block.header.setSigns(signs);
assert(this.m_miningBlocks.has(block.hash));
const resolve = this.m_miningBlocks.get(block.hash);
resolve(error_code_1.ErrorCode.RESULT_OK);
});
return err;
}
async _updateTip(tip) {
let gnmr = await this.chain.dbftHeaderStorage.getNextMiners(tip);
if (gnmr.err) {
this.m_logger.error(`dbft miner initialize failed for `, gnmr.err);
return gnmr.err;
}
let gtvr = await this.chain.dbftHeaderStorage.getTotalView(tip);
if (gtvr.err) {
this.m_logger.error(`dbft miner initialize failed for `, gtvr.err);
return gnmr.err;
}
this.m_consensusNode.updateTip(tip, gnmr.miners, gtvr.totalView);
return error_code_1.ErrorCode.RESULT_OK;
}
async _onTipBlock(chain, tipBlock) {
await this._updateTip(tipBlock);
}
async _mineBlock(block) {
this.m_logger.info(`create block, sign ${this.m_address}`);
block.header.updateHash();
return new Promise((resolve) => {
if (this.m_miningBlocks.has(block.hash)) {
resolve(error_code_1.ErrorCode.RESULT_SKIPPED);
return;
}
this.m_miningBlocks.set(block.hash, resolve);
this.m_consensusNode.agreeProposal(block);
});
}
}
exports.DbftMiner = DbftMiner;