UNPKG

int-cli

Version:

INT is the new generation of bottom-up created system of IoT and blockchain

333 lines (332 loc) 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const assert = require('assert'); const events_1 = require("events"); const error_code_1 = require("../error_code"); const node_storage_1 = require("./node_storage"); const block_1 = require("./block"); const util_1 = require("util"); const { LogShim } = require('../lib/log_shim'); var BAN_LEVEL; (function (BAN_LEVEL) { BAN_LEVEL[BAN_LEVEL["minute"] = 1] = "minute"; BAN_LEVEL[BAN_LEVEL["hour"] = 60] = "hour"; BAN_LEVEL[BAN_LEVEL["day"] = 1440] = "day"; BAN_LEVEL[BAN_LEVEL["month"] = 43200] = "month"; BAN_LEVEL[BAN_LEVEL["forever"] = 0] = "forever"; })(BAN_LEVEL = exports.BAN_LEVEL || (exports.BAN_LEVEL = {})); var NetworkBroadcastStrategy; (function (NetworkBroadcastStrategy) { NetworkBroadcastStrategy[NetworkBroadcastStrategy["transaction"] = 1] = "transaction"; NetworkBroadcastStrategy[NetworkBroadcastStrategy["headers"] = 2] = "headers"; })(NetworkBroadcastStrategy = exports.NetworkBroadcastStrategy || (exports.NetworkBroadcastStrategy = {})); class Network extends events_1.EventEmitter { constructor(options) { super(); this.m_connecting = new Set(); this.m_ignoreBan = false; this.m_broadcastStrategies = new Map(); this.m_node = options.node; this.m_node.logger = options.logger; this.m_logger = new LogShim(options.logger).bind(`[network: ${this.name} peerid: ${this.peerid}]`, true).log; this.m_dataDir = options.dataDir; this.m_blockHeaderType = options.blockHeaderType; this.m_transactionType = options.transactionType; this.m_receiptType = options.receiptType; this.m_headerStorage = options.headerStorage; } on(event, listener) { return super.on(event, listener); } once(event, listener) { return super.once(event, listener); } prependListener(event, listener) { return super.prependListener(event, listener); } prependOnceListener(event, listener) { return super.prependOnceListener(event, listener); } parseInstanceOptions(options) { let value = Object.create(null); value.ignoreBan = options.origin.get('ignoreBan'); value.nodeCacheSize = options.origin.get('nodeCacheSize'); let strategyOptNames = { broadcast_limit_transaction: NetworkBroadcastStrategy.transaction, broadcast_limit_headers: NetworkBroadcastStrategy.headers }; value.strategy = new Map(); for (const [n, s] of Object.entries(strategyOptNames)) { const ss = options.origin.get(n); if (ss) { let count; count = Number.parseInt(ss); let filter; if (isNaN(count)) { const address = ss.split(','); count = address.length; filter = (conn) => address.indexOf(conn.remote) !== -1; } value.strategy.set(s, { count, filter }); } } return { err: error_code_1.ErrorCode.RESULT_OK, value }; } setInstanceOptions(options) { this.m_ignoreBan = !!options.ignoreBan; this.m_nodeStorage = new node_storage_1.NodeStorage({ count: options.nodeCacheSize ? options.nodeCacheSize : 50, dataDir: this.m_dataDir, logger: this.m_logger }); for (const [n, s] of options.strategy) { this.addBroadcastStrategy(n, s); } } async init() { this.m_node.on('error', (conn, err) => { this.emit('error', conn.remote, conn.id); }); // 收到net/node的ban事件, 调用 ChainNode的banConnection方法做封禁处理 // 日期先设置为按天 this.m_node.on('ban', (remote) => { this.banConnection(remote, BAN_LEVEL.day); }); // 读取创始块的hash值, 并将其传入 net/node const result = await this.m_headerStorage.getHeader(0); const genesis_hash = result.header.hash; this.m_node.genesisHash = genesis_hash; await this.m_node.init(); return error_code_1.ErrorCode.RESULT_OK; } uninit() { return this.m_node.uninit(); } newTransaction() { return new this.m_transactionType(); } newBlockHeader() { return new this.m_blockHeaderType(); } newBlock(header) { let block = new block_1.Block({ header, headerType: this.m_blockHeaderType, transactionType: this.m_transactionType, receiptType: this.m_receiptType }); return block; } async initialOutbounds() { return error_code_1.ErrorCode.RESULT_OK; } get logger() { return this.m_logger; } get node() { return this.m_node; } get peerid() { return this.m_node.peerid; } get name() { return this.m_node.network; } get headerStorage() { return this.m_headerStorage; } async _connectTo(willConn, callback) { if (!willConn.size) { if (callback) { callback(0); } return error_code_1.ErrorCode.RESULT_SKIPPED; } let ops = []; for (let peer of willConn) { if (this._onWillConnectTo(peer)) { this.m_connecting.add(peer); ops.push(this.m_node.connectTo(peer)); } } if (ops.length === 0) { if (callback) { callback(0); } return error_code_1.ErrorCode.RESULT_SKIPPED; } Promise.all(ops).then((results) => { let connCount = 0; for (let r of results) { this.m_connecting.delete(r.peerid); this.logger.debug(`connect to ${r.peerid} err: `, r.err); if (r.conn) { this.m_nodeStorage.add(r.conn.remote); this.emit('outbound', r.conn); ++connCount; } else { if (r.err !== error_code_1.ErrorCode.RESULT_ALREADY_EXIST) { this.m_nodeStorage.remove(r.peerid); } if (r.err === error_code_1.ErrorCode.RESULT_VER_NOT_SUPPORT) { this.m_nodeStorage.ban(r.peerid, BAN_LEVEL.month); } } } if (callback) { callback(connCount); } }); return error_code_1.ErrorCode.RESULT_OK; } _isBan(peerid) { if (this.m_ignoreBan) { return false; } return this.m_nodeStorage.isBan(peerid); } async listen() { this.m_node.on('inbound', (inbound) => { if (this._isBan(inbound.remote)) { this.logger.warn(`new inbound from ${inbound.remote} ignored for ban`); this.m_node.closeConnection(inbound); } else { this.logger.info(`new inbound from `, inbound.remote); this.emit('inbound', inbound); } }); return await this.m_node.listen(); } banConnection(remote, level) { if (this.m_ignoreBan) { return; } this.m_logger.warn(`banned peer ${remote} for ${level}`); this.m_nodeStorage.ban(remote, level); this.m_node.banConnection(remote); this.emit('ban', remote); } _onWillConnectTo(peerid) { if (this._isBan(peerid)) { return false; } if (this.m_node.getConnection(peerid)) { return false; } if (this.m_connecting.has(peerid)) { return false; } if (this.m_node.peerid === peerid) { return false; } return true; } broadcast(writer, options) { let bopt = Object.create(null); if (options) { bopt.count = options.count; bopt.filter = options.filter; if (!util_1.isNullOrUndefined(options.strategy)) { const s = this.m_broadcastStrategies.get(options.strategy); if (s) { if (!util_1.isNullOrUndefined(s.count)) { bopt.count = util_1.isNullOrUndefined(bopt.count) ? s.count : Math.min(bopt.count, s.count); } if (s.filter) { if (bopt.filter) { let srcFilter = bopt.filter; bopt.filter = (conn) => srcFilter(conn) && s.filter(conn); } else { bopt.filter = s.filter; } } } } } return this.m_node.broadcast(writer, bopt); } addBroadcastStrategy(strategy, options) { this.m_broadcastStrategies.set(strategy, { count: options.count, filter: options.filter }); } } exports.Network = Network; class NetworkCreator { constructor(options) { this.m_network = new Map(); this.m_node = new Map(); this.m_logger = options.logger; } create(options) { let pnr = this._parseNetwork(options); if (pnr.err) { this.m_logger.error(`parseNetwork failed, err ${pnr.err}`); return { err: pnr.err }; } const network = pnr.network; return { err: error_code_1.ErrorCode.RESULT_OK, network }; } registerNetwork(type, instance) { this.m_network.set(type, instance); } _parseNetwork(options) { const { parsed } = options; if (!parsed.dataDir || !parsed.blockHeaderType || !parsed.headerStorage || !parsed.receiptType || !parsed.transactionType || !parsed.logger) { this.m_logger.error(`parsed should has contructor options`); return { err: error_code_1.ErrorCode.RESULT_PARSE_ERROR }; } let type = options.parsed.netType; if (!type) { type = options.origin.get('netType'); } if (!type) { this.m_logger.error(`parse network failed for netype missing`); return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM }; } let node = options.parsed.node; if (!node) { const pr = this._parseNode(options.origin); if (pr.err) { this.m_logger.error(`parseNode failed, err ${pr.err}`); return { err: pr.err }; } node = pr.node; } const instance = this.m_network.get(type); if (!instance) { this.m_logger.error(`parse network failed for invalid netType ${type}`); return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM }; } let ops = Object.create(parsed); ops.node = node; ops.logger = this.m_logger; const ins = new instance(ops); return { err: error_code_1.ErrorCode.RESULT_OK, network: ins }; } registerNode(type, instance) { this.m_node.set(type, instance); } _parseNode(commandOptions) { const type = commandOptions.get('net'); if (type) { let ni = this.m_node.get(type); if (!ni) { this.m_logger.error(`parse node failed for invalid node ${type}`); return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM }; } return { err: error_code_1.ErrorCode.RESULT_OK, node: ni(commandOptions) }; } else { this.m_logger.error(`parse node failed for node missing`); return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM }; } } } exports.NetworkCreator = NetworkCreator;