int-cli
Version:
INT is the new generation of bottom-up created system of IoT and blockchain
782 lines (781 loc) • 34.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const events_1 = require("events");
const error_code_1 = require("../error_code");
const storage_1 = require("../storage");
const block_1 = require("../block");
const reader_1 = require("../lib/reader");
const writer_1 = require("../lib/writer");
const net_1 = require("../net");
var SYNC_CMD_TYPE;
(function (SYNC_CMD_TYPE) {
SYNC_CMD_TYPE[SYNC_CMD_TYPE["getHeader"] = 16] = "getHeader";
SYNC_CMD_TYPE[SYNC_CMD_TYPE["header"] = 17] = "header";
SYNC_CMD_TYPE[SYNC_CMD_TYPE["getBlock"] = 18] = "getBlock";
SYNC_CMD_TYPE[SYNC_CMD_TYPE["block"] = 19] = "block";
SYNC_CMD_TYPE[SYNC_CMD_TYPE["tx"] = 21] = "tx";
SYNC_CMD_TYPE[SYNC_CMD_TYPE["end"] = 22] = "end";
})(SYNC_CMD_TYPE = exports.SYNC_CMD_TYPE || (exports.SYNC_CMD_TYPE = {}));
class ChainNode extends events_1.EventEmitter {
constructor(options) {
super();
this.m_requestingBlock = {
connMap: new Map(),
hashMap: new Map()
};
this.m_pendingBlock = { hashes: new Set(), sequence: new Array() };
this.m_blockFromMap = new Map();
this.m_requestingHeaders = new Map();
this.m_cc = {
onRecvBlock(node, block, from) {
from.wnd += 1;
from.wnd = from.wnd > 3 * node.m_initBlockWnd ? 3 * node.m_initBlockWnd : from.wnd;
},
onBlockTimeout(node, hash, from) {
from.wnd = Math.floor(from.wnd / 2);
}
};
// net/node
this.m_logger = options.logger;
this.m_networks = options.networks.slice();
this.m_blockStorage = options.blockStorage;
this.m_storageManager = options.storageManager;
this.m_blockWithLog = options.blockWithLog;
this.m_initBlockWnd = options.initBlockWnd ? options.initBlockWnd : 10;
this.m_blockTimeout = options.blockTimeout ? options.blockTimeout : 10000;
this.m_headersTimeout = options.headersTimeout ? options.headersTimeout : 30000;
this.m_reqTimeoutTimer = setInterval(() => {
this._onReqTimeoutTimer(Date.now() / 1000);
}, 1000);
}
on(event, listener) {
return super.on(event, listener);
}
once(event, listener) {
return super.once(event, listener);
}
async init() {
let inits = [];
for (const network of this.m_networks) {
network.on('inbound', (conn) => {
this._beginSyncWithNode(network, conn);
this.emit('inbound', conn);
});
network.on('outbound', (conn) => {
this._beginSyncWithNode(network, conn);
this.emit('outbound', conn);
});
network.on('error', (remote, id, err) => {
const fullRemote = net_1.INode.fullPeerid(network.name, remote);
this._onConnectionError(fullRemote, id);
this.emit('error', fullRemote);
});
network.on('ban', (remote) => {
const fullRemote = net_1.INode.fullPeerid(network.name, remote);
this._onRemoveConnection(fullRemote);
this.emit('ban', fullRemote);
});
inits.push(network.init());
}
let results = await Promise.all(inits);
if (results[0]) {
return results[0];
}
let initOutbounds = [];
for (const network of this.m_networks) {
initOutbounds.push(network.initialOutbounds());
}
results = await Promise.all(initOutbounds);
return results[0];
}
uninit() {
this.removeAllListeners('blocks');
this.removeAllListeners('headers');
this.removeAllListeners('transactions');
let uninits = [];
for (const network of this.m_networks) {
uninits.push(network.uninit());
}
return Promise.all(uninits);
}
get logger() {
return this.m_logger;
}
async listen() {
let listens = [];
for (const network of this.m_networks) {
listens.push(network.listen());
}
const results = await Promise.all(listens);
for (const err of results) {
if (err) {
return err;
}
}
return error_code_1.ErrorCode.RESULT_OK;
}
getNetwork(_network) {
if (_network) {
for (const network of this.m_networks) {
if (network.name === _network) {
return network;
}
}
return undefined;
}
else {
return this.m_networks[0];
}
}
getConnection(fullremote) {
const { network, peerid } = net_1.INode.splitFullPeerid(fullremote);
const node = this.getNetwork(network);
if (!node) {
return;
}
return node.node.getConnection(peerid);
}
getOutbounds() {
let arr = [];
for (const network of this.m_networks) {
arr.push(...network.node.getOutbounds());
}
return arr;
}
getInbounds() {
let arr = [];
for (const network of this.m_networks) {
arr.push(...network.node.getInbounds());
}
return arr;
}
broadcast(content, options) {
if (!content.length) {
return error_code_1.ErrorCode.RESULT_OK;
}
let pwriter;
let strategy;
if (content[0] instanceof block_1.BlockHeader) {
let hwriter = new writer_1.BufferWriter();
for (let header of content) {
let err = header.encode(hwriter);
if (err) {
this.logger.error(`encode header ${header.hash} failed`);
return err;
}
}
let raw = hwriter.render();
pwriter = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.header, { count: content.length }, raw.length);
pwriter.writeData(raw);
strategy = block_1.NetworkBroadcastStrategy.headers;
}
else if (content[0] instanceof block_1.Transaction) {
let hwriter = new writer_1.BufferWriter();
for (let tx of content) {
let err = tx.encode(hwriter);
if (err) {
this.logger.error(`encode transaction ${tx.hash} failed`);
return err;
}
}
let raw = hwriter.render();
pwriter = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.tx, { count: content.length }, raw.length);
pwriter.writeData(raw);
strategy = block_1.NetworkBroadcastStrategy.transaction;
}
assert(pwriter);
for (const network of this.m_networks) {
const opt = Object.create(options ? options : null);
opt.strategy = strategy;
network.broadcast(pwriter, opt);
}
return error_code_1.ErrorCode.RESULT_OK;
}
_beginSyncWithNode(network, conn) {
// TODO: node 层也要做封禁,比如发送无法解析的pkg, 过大, 过频繁的请求等等
conn.on('pkg', async (pkg) => {
if (pkg.header.cmdType === SYNC_CMD_TYPE.tx) {
let buffer = pkg.copyData();
let txReader = new reader_1.BufferReader(buffer);
let txes = [];
let err = error_code_1.ErrorCode.RESULT_OK;
for (let ix = 0; ix < pkg.body.count; ++ix) {
let tx = network.newTransaction();
if (tx.decode(txReader) !== error_code_1.ErrorCode.RESULT_OK) {
this.logger.warn(`receive invalid format transaction from ${conn.fullRemote}`);
err = error_code_1.ErrorCode.RESULT_INVALID_PARAM;
break;
}
if (!tx.verifySignature()) {
this.logger.warn(`receive invalid signature transaction ${tx.hash} from ${conn.fullRemote}`);
err = error_code_1.ErrorCode.RESULT_INVALID_TOKEN;
break;
}
txes.push(tx);
}
if (err) {
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
}
else {
if (txes.length) {
let hashs = [];
for (let tx of txes) {
hashs.push(tx.hash);
}
this.logger.debug(`receive transaction from ${conn.fullRemote} ${JSON.stringify(hashs)}`);
this.emit('transactions', conn, txes);
}
}
}
else if (pkg.header.cmdType === SYNC_CMD_TYPE.header) {
let time = Date.now() / 1000;
let buffer = pkg.copyData();
let headerReader = new reader_1.BufferReader(buffer);
let headers = [];
this.logger.debug(`receive headers from ${conn.fullRemote} err ${pkg.body.error} request `, pkg.body.request);
if (!pkg.body.error) {
let err = error_code_1.ErrorCode.RESULT_OK;
let preHeader;
for (let ix = 0; ix < pkg.body.count; ++ix) {
let header = network.newBlockHeader();
if (header.decode(headerReader) !== error_code_1.ErrorCode.RESULT_OK) {
this.logger.warn(`receive invalid format header from ${conn.fullRemote}`);
err = error_code_1.ErrorCode.RESULT_INVALID_BLOCK;
break;
}
if (!pkg.body.request || pkg.body.request.from) {
// 广播或者用from请求的header必须连续
if (preHeader) {
if (!preHeader.isPreBlock(header)) {
this.logger.warn(`receive headers not in sequence from ${conn.fullRemote}`);
err = error_code_1.ErrorCode.RESULT_INVALID_BLOCK;
break;
}
}
preHeader = header;
}
headers.push(header);
}
if (err) {
// 发错的header的peer怎么处理
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
// 用from请求的返回的第一个跟from不一致
if (headers.length && pkg.body.request && headers[0].preBlockHash !== pkg.body.request.from) {
this.logger.warn(`receive headers ${headers[0].preBlockHash} not match with request ${pkg.body.request.from} from ${conn.fullRemote}`);
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
// 任何返回 gensis 的都不对
if (headers.length) {
if (headers[0].number === 0) {
this.logger.warn(`receive genesis header from ${conn.fullRemote}`);
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
}
}
else if (pkg.body.error === error_code_1.ErrorCode.RESULT_NOT_FOUND) {
let ghr = await network.headerStorage.getHeader(0);
if (ghr.err) {
return;
}
// from用gensis请求的返回没有
if (pkg.body.request && pkg.body.request.from === ghr.header.hash) {
this.logger.warn(`receive can't get genesis header ${pkg.body.request.from} from ${conn.fullRemote}`);
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
}
if (!this._onRecvHeaders(conn.fullRemote, time, pkg.body.request)) {
return;
}
this.emit('headers', { from: conn.fullRemote, headers, request: pkg.body.request, error: pkg.body.error });
}
else if (pkg.header.cmdType === SYNC_CMD_TYPE.getHeader) {
this._responseHeaders(conn, pkg.body);
}
else if (pkg.header.cmdType === SYNC_CMD_TYPE.block) {
this._handlerBlockPackage(network, conn, pkg);
}
else if (pkg.header.cmdType === SYNC_CMD_TYPE.getBlock) {
this._responseBlocks(conn, pkg.body);
}
});
}
// 处理通过网络请求获取的block package
// 然后emit到chain层
// @param conn 网络连接
// @param pgk block 数据包
_handlerBlockPackage(network, conn, pkg) {
let buffer = pkg.copyData();
let blockReader;
let redoLogReader;
let redoLog;
// check body buffer 中是否包含了redoLog
// 如果包含了redoLog 需要切割buffer
if (pkg.body.redoLog) {
// 由于在传输时, redolog和block都放在package的data属性里(以合并buffer形式)
// 所以需要根据body中的length 分配redo和block的buffer
let blockBuffer = buffer.slice(0, pkg.body.blockLength);
let redoLogBuffer = buffer.slice(pkg.body.blockLength, buffer.length);
// console.log(pkg.body.blockLength, blockBuffer.length, pkg.body.redoLogLength, redoLogBuffer.length)
// console.log('------------------')
blockReader = new reader_1.BufferReader(blockBuffer);
redoLogReader = new reader_1.BufferReader(redoLogBuffer);
// 构造redo log 对象
redoLog = new storage_1.JStorageLogger();
let redoDecodeError = redoLog.decode(redoLogReader);
if (redoDecodeError) {
return;
}
}
else {
blockReader = new reader_1.BufferReader(buffer);
}
if (pkg.body.err === error_code_1.ErrorCode.RESULT_NOT_FOUND) {
// 请求的block肯定已经从header里面确定remote有,直接禁掉
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
// 构造block对象
let block = network.newBlock();
if (block.decode(blockReader) !== error_code_1.ErrorCode.RESULT_OK) {
this.logger.warn(`receive block invalid format from ${conn.fullRemote}`);
network.banConnection(conn.remote, block_1.BAN_LEVEL.forever);
return;
}
if (!block.verify()) {
this.logger.warn(`receive block not match header ${block.header.hash} from ${conn.fullRemote}`);
network.banConnection(conn.remote, block_1.BAN_LEVEL.day); // 可能分叉?
return;
}
const eventParams = { from: conn.fullRemote, block, redoLog };
let err = this._onRecvBlock(eventParams);
if (err) {
return;
}
// 数据emit 到chain层
this.emit('blocks', eventParams);
}
requestHeaders(from, options) {
this.logger.debug(`request headers from with options ${from.fullRemote}`, options);
if (this.m_requestingHeaders.get(from.fullRemote)) {
this.logger.warn(`request headers ${options} from ${from.fullRemote} skipped for former headers request existing`);
return error_code_1.ErrorCode.RESULT_ALREADY_EXIST;
}
this.m_requestingHeaders.set(from.fullRemote, {
time: Date.now() / 1000,
req: Object.assign(Object.create(null), options)
});
let writer = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.getHeader, options);
from.addPendingWriter(writer);
return error_code_1.ErrorCode.RESULT_OK;
}
// 这里必须实现成同步的
requestBlocks(from, options) {
this.logger.debug(`request blocks from ${from} with options `, options);
let connRequesting = this._getConnRequesting(from);
if (!connRequesting) {
this.logger.debug(`request blocks from ${from} skipped for connection not found with options `, options);
return error_code_1.ErrorCode.RESULT_NOT_FOUND;
}
let requests = [];
let addRequesting = (header) => {
if (this.m_blockStorage.has(header.hash)) {
let block = this.m_blockStorage.get(header.hash);
this.logger.debug(`request query blocks from storage hash = ${header.hash}`);
assert(block, `block storage load block ${header.hash} failed while file exists`);
if (block) {
if (this.m_blockWithLog) {
if (this.m_storageManager.hasRedoLog(header.hash)) {
let redoLog = this.m_storageManager.getRedoLog(header.hash);
if (redoLog) {
setImmediate(() => {
this.emit('blocks', { block, redoLog });
});
}
else {
setImmediate(() => {
this.emit('blocks', { block });
});
}
}
else {
setImmediate(() => {
this.emit('blocks', { block });
});
}
}
else {
setImmediate(() => {
this.emit('blocks', { block });
});
}
return false;
}
}
let sources = this.m_blockFromMap.get(header.hash);
if (!sources) {
sources = new Set();
this.m_blockFromMap.set(header.hash, sources);
}
if (!sources.has(from)) {
sources.add(from);
}
let stub = this.m_requestingBlock.hashMap.get(header.hash);
if (stub && (Date.now() / 1000 - stub.time) < 20) {
this.logger.debug(`block has requested hash = ${header.hash}, stub = ${stub}`);
return false;
}
requests.push(header.hash);
return true;
};
if (options.headers) {
for (let header of options.headers) {
addRequesting(header);
}
}
else {
assert(false, `invalid block request ${options}`);
return error_code_1.ErrorCode.RESULT_INVALID_PARAM;
}
for (let hash of requests) {
this._addToPendingBlocks(hash);
}
this._onFreeBlockWnd(connRequesting);
return error_code_1.ErrorCode.RESULT_OK;
}
_tryRequestBlockFromConnection(hash, from) {
if (from.wnd - from.hashes.size > 0) {
this._requestBlockFromConnection(hash, from);
this._removeFromPendingBlocks(hash);
return true;
}
return false;
}
_addToPendingBlocks(hash, head = false) {
if (!this.m_pendingBlock.hashes.has(hash)) {
this.m_pendingBlock.hashes.add(hash);
this.logger.debug(`add new waiting async block to m_pendingBlock, hash = ${hash}`);
if (head) {
this.m_pendingBlock.sequence.unshift(hash);
}
else {
this.m_pendingBlock.sequence.push(hash);
}
}
}
_removeFromPendingBlocks(hash) {
if (this.m_pendingBlock.hashes.has(hash)) {
this.m_pendingBlock.hashes.delete(hash);
this.m_pendingBlock.sequence.splice(this.m_pendingBlock.sequence.indexOf(hash), 1);
}
}
_getConnRequesting(fpid) {
let connRequesting = this.m_requestingBlock.connMap.get(fpid);
if (!connRequesting) {
const { network, peerid } = net_1.INode.splitFullPeerid(fpid);
const node = this.getNetwork(network);
if (!node) {
return;
}
let conn = node.node.getConnection(peerid);
// TODO: 取不到这个conn的时候要处理
// assert(conn, `no connection to ${remote}`);
this.logger.error(`non connection to ${fpid}`);
if (!conn) {
return;
}
connRequesting = { hashes: new Set(), wnd: this.m_initBlockWnd, conn: conn };
this.m_requestingBlock.connMap.set(fpid, connRequesting);
}
return connRequesting;
}
_requestBlockFromConnection(hash, connRequesting) {
this.logger.debug(`request block ${hash} from ${connRequesting.conn.fullRemote}`);
let writer = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.getBlock, { hash, redoLog: this.m_blockWithLog ? 1 : 0 });
connRequesting.conn.addPendingWriter(writer);
connRequesting.hashes.add(hash);
this.m_requestingBlock.hashMap.set(hash, { remote: connRequesting.conn.fullRemote, time: Date.now() / 1000 });
return error_code_1.ErrorCode.RESULT_OK;
}
_onFreeBlockWnd(connRequesting) {
let pending = this.m_pendingBlock;
let index = 0;
do {
if (!pending.sequence.length
|| index >= pending.sequence.length) {
break;
}
let hash = pending.sequence[index];
let sources = this.m_blockFromMap.get(hash);
assert(sources, `to request block ${hash} from unknown source`);
if (!sources) {
return error_code_1.ErrorCode.RESULT_EXCEPTION;
}
if (sources.has(connRequesting.conn.fullRemote)) {
this._requestBlockFromConnection(hash, connRequesting);
pending.sequence.splice(index, 1);
pending.hashes.delete(hash);
if (connRequesting.wnd <= connRequesting.hashes.size) {
this.logger.debug(`onFreeBlockWnd connRequesting.wnd <= connRequesting.hashes.size, from ${connRequesting.conn.fullRemote},hash ${hash}`);
break;
}
else {
continue;
}
}
++index;
} while (true);
}
_onRecvHeaders(fpid, time, request) {
let valid = true;
if (request) {
// 返回没有请求过的headers, 要干掉
let rh = this.m_requestingHeaders.get(fpid);
if (rh) {
for (let key of Object.keys(request)) {
if (request[key] !== rh.req[key]) {
valid = false;
break;
}
}
}
else {
// TODO: 如果request header之后connection失效, 会从requesting headers 中移除;
// 因为回调处理基本都是异步的,可能是会出现同时进入receive header的回调和connection error的回调;
// 此时这段分支会导致header被置为invalid;相比不停返回header的ddos攻击行为是有区别的;
// ban的策略也应该有区别;
valid = false;
}
if (valid) {
this.m_requestingHeaders.delete(fpid);
}
}
else {
// TODO: 过频繁的广播header, 要干掉
}
if (!valid) {
this._banConnection(fpid, block_1.BAN_LEVEL.forever);
}
return valid;
}
_onRecvBlock(params) {
let connRequesting = this.m_requestingBlock.connMap.get(params.from);
if (!connRequesting) {
this.logger.error(`requesting info on ${params.from} missed, skip it`);
return error_code_1.ErrorCode.RESULT_NOT_FOUND;
}
let stub = this.m_requestingBlock.hashMap.get(params.block.hash);
assert(stub, `recv block ${params.block.hash} from ${params.from} that never request`);
if (!stub) {
this._banConnection(params.from, block_1.BAN_LEVEL.day);
return error_code_1.ErrorCode.RESULT_INVALID_BLOCK;
}
this.logger.debug(`recv block hash: ${params.block.hash} number: ${params.block.number} from ${params.from}`);
this.m_blockStorage.add(params.block);
if (params.redoLog) {
this.m_storageManager.addRedoLog(params.block.hash, params.redoLog);
}
assert(stub.remote === params.from, `request ${params.block.hash} from ${stub.remote} while recv from ${params.from}`);
this.m_requestingBlock.hashMap.delete(params.block.hash);
connRequesting.hashes.delete(params.block.hash);
this.m_blockFromMap.delete(params.block.hash);
this.m_cc.onRecvBlock(this, params.block, connRequesting);
this._onFreeBlockWnd(connRequesting);
return error_code_1.ErrorCode.RESULT_OK;
}
_onConnectionError(fullRemote, id) {
this.logger.warn(`connection ${id} from ${fullRemote} break, close it.`);
this._onRemoveConnection(fullRemote);
}
/*must not async*/
_onRemoveConnection(fullRemote) {
this.logger.info(`removing ${fullRemote} from block requesting source`);
let connRequesting = this.m_requestingBlock.connMap.get(fullRemote);
if (connRequesting) {
for (let hash of connRequesting.hashes) {
this.logger.debug(`change block ${hash} from requesting to pending`);
this.m_requestingBlock.hashMap.delete(hash);
this._addToPendingBlocks(hash, true);
}
}
this.m_requestingBlock.connMap.delete(fullRemote);
for (let hash of this.m_blockFromMap.keys()) {
let sources = this.m_blockFromMap.get(hash);
if (sources.has(fullRemote)) {
sources.delete(fullRemote);
if (!sources.size) {
this.logger.debug(`remove block ${hash} from pending blocks for all source removed`);
// this._removeFromPendingBlocks(hash);
}
else {
for (let from of sources) {
let fromRequesting = this.m_requestingBlock.connMap.get(from);
assert(fromRequesting, `block requesting connection ${from} not exists`);
if (this._tryRequestBlockFromConnection(hash, fromRequesting)) {
break;
}
}
}
}
}
this.m_requestingHeaders.delete(fullRemote);
}
banConnection(fullRemote, level) {
return this._banConnection(fullRemote, level);
}
_banConnection(fullRemote, level) {
const { network, peerid } = net_1.INode.splitFullPeerid(fullRemote);
const node = this.getNetwork(network);
if (node) {
node.banConnection(peerid, level);
}
}
_onReqTimeoutTimer(now) {
for (let hash of this.m_requestingBlock.hashMap.keys()) {
let stub = this.m_requestingBlock.hashMap.get(hash);
let fromRequesting = this.m_requestingBlock.connMap.get(stub.remote);
if (now - stub.time > this.m_blockTimeout) {
this.m_cc.onBlockTimeout(this, hash, fromRequesting);
// close it
if (fromRequesting.wnd < 1) {
this._banConnection(stub.remote, block_1.BAN_LEVEL.hour);
}
}
}
// 返回headers超时
for (let fullRemote of this.m_requestingHeaders.keys()) {
let rh = this.m_requestingHeaders.get(fullRemote);
if (now - rh.time > this.m_headersTimeout) {
this.logger.debug(`header request timeout from ${fullRemote} timeout with options `, rh.req);
this._banConnection(fullRemote, block_1.BAN_LEVEL.hour);
}
}
}
async _responseBlocks(conn, req) {
assert(this.m_blockStorage);
this.logger.info(`receive block request from ${conn.fullRemote} with ${JSON.stringify(req)}`);
let bwriter = new writer_1.BufferWriter();
let block = this.m_blockStorage.get(req.hash);
if (!block) {
this.logger.crit(`cannot get Block ${req.hash} from blockStorage`);
const node = this.getNetwork(conn.network);
assert(false, `${conn.fullRemote} cannot get Block ${req.hash} from blockStorage`);
return error_code_1.ErrorCode.RESULT_OK;
}
let err = block.encode(bwriter);
if (err) {
this.logger.error(`encode block ${block.hash} failed`);
return err;
}
let rawBlocks = bwriter.render();
let redoLogRaw;
// 如果请求参数里设置了redoLog, 则读取redoLog, 合并在返回的包里
if (req.redoLog === 1) {
do {
let redoLogWriter = new writer_1.BufferWriter();
// 从本地文件中读取redoLog, 处理raw 拼接在block后
let redoLog = this.m_storageManager.getRedoLog(req.hash);
if (!redoLog) {
this.logger.error(`${req.hash} redo log missing`);
break;
}
err = redoLog.encode(redoLogWriter);
if (err) {
this.logger.error(`encode redolog ${req.hash} failed`);
break;
}
redoLogRaw = redoLogWriter.render();
} while (false);
}
if (redoLogRaw) {
let dataLength = rawBlocks.length + redoLogRaw.length;
let pwriter = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.block, {
blockLength: rawBlocks.length,
redoLogLength: redoLogRaw.length,
redoLog: 1,
}, dataLength);
pwriter.writeData(rawBlocks);
pwriter.writeData(redoLogRaw);
conn.addPendingWriter(pwriter);
}
else {
let pwriter = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.block, { redoLog: 0 }, rawBlocks.length);
pwriter.writeData(rawBlocks);
conn.addPendingWriter(pwriter);
}
return error_code_1.ErrorCode.RESULT_OK;
}
async _responseHeaders(conn, req) {
const node = this.getNetwork(conn.network);
this.logger.info(`receive header request from ${conn.fullRemote} with ${JSON.stringify(req)}`);
if (req.from) {
let hwriter = new writer_1.BufferWriter();
let respErr = error_code_1.ErrorCode.RESULT_OK;
let headerCount = 0;
do {
let tipResult = await node.headerStorage.getHeader('latest');
if (tipResult.err) {
return tipResult.err;
}
let heightResult = await node.headerStorage.getHeightOnBest(req.from);
if (heightResult.err === error_code_1.ErrorCode.RESULT_NOT_FOUND) {
respErr = error_code_1.ErrorCode.RESULT_NOT_FOUND;
break;
}
assert(tipResult.header);
if (tipResult.header.hash === req.from) {
// 没有更多了
respErr = error_code_1.ErrorCode.RESULT_SKIPPED;
break;
}
if (!req.limit || heightResult.height + req.limit > tipResult.header.number) {
headerCount = tipResult.header.number - heightResult.height;
}
else {
headerCount = req.limit;
}
let hr = await node.headerStorage.getHeader(heightResult.height + headerCount);
if (hr.err) {
// 中间changeBest了,返回not found
if (hr.err === error_code_1.ErrorCode.RESULT_NOT_FOUND) {
respErr = error_code_1.ErrorCode.RESULT_NOT_FOUND;
break;
}
else {
return hr.err;
}
}
let hsr = await node.headerStorage.getHeader(hr.header.hash, -headerCount + 1);
if (hsr.err) {
return hsr.err;
}
if (hsr.headers[0].preBlockHash !== req.from) {
// 中间changeBest了,返回not found
respErr = error_code_1.ErrorCode.RESULT_NOT_FOUND;
break;
}
for (let h of hsr.headers) {
let err = h.encode(hwriter);
if (err) {
this.logger.error(`encode header ${h.hash} failed`);
respErr = error_code_1.ErrorCode.RESULT_NOT_FOUND;
}
}
} while (false);
let rawHeaders = hwriter.render();
let pwriter = net_1.PackageStreamWriter.fromPackage(SYNC_CMD_TYPE.header, { count: headerCount, request: req, error: respErr }, rawHeaders.length);
pwriter.writeData(rawHeaders);
conn.addPendingWriter(pwriter);
return error_code_1.ErrorCode.RESULT_OK;
}
else {
return error_code_1.ErrorCode.RESULT_INVALID_PARAM;
}
}
}
exports.ChainNode = ChainNode;
;