UNPKG

@gohelpfund/helpcore-lib

Version:

A pure and powerful JavaScript Help library.

172 lines (152 loc) 5.58 kB
/* eslint-disable */ var merkleUtils = require('../util/merkletree'); var SimplifiedMNListDiff = require('./SimplifiedMNListDiff'); var constants = require('../constants'); var Transaction = require('../transaction'); var getMerkleTree = merkleUtils.getMerkleTree; var getMerkleRoot = merkleUtils.getMerkleRoot; function SimplifiedMNList(simplifiedMNListDiff) { this.baseBlockHash = constants.NULL_HASH; this.blockHash = constants.NULL_HASH; /** * Note that this property contains ALL masternodes, including banned ones. * Use getValidMasternodesList() method to get the list of only valid nodes. * This in needed for merkleRootNMList calculation * @type {SimplifiedMNListEntry[]} */ this.mnList = []; /** * This property contains only valid, not PoSe-banned nodes. * @type {SimplifiedMNListEntry[]} */ this.validMNs = []; this.merkleRootMNList = constants.NULL_HASH; this.lastDiffMerkleRootMNList = constants.NULL_HASH; this.cbTx = null; this.cbTxMerkleTree = null; if (simplifiedMNListDiff) { this.applyDiff(simplifiedMNListDiff); } } /** * * @param {SimplifiedMNListDiff|Buffer|string|Object} simplifiedMNListDiff - MNList diff. Can be serialized or parsed */ SimplifiedMNList.prototype.applyDiff = function applyDiff(simplifiedMNListDiff) { // This will copy instance of SimplifiedMNListDiff or create a new instance if serialized data is passed var diff = new SimplifiedMNListDiff(simplifiedMNListDiff); if (this.baseBlockHash === constants.NULL_HASH) { /* If the base block hash is a null hash, then this is the first time we apply any diff. * If we apply diff to the list for the first time, than diff's base block hash would be the base block hash * for the whole list. * */ this.baseBlockHash = diff.baseBlockHash; } this.blockHash = diff.blockHash; this.deleteMNs(diff.deletedMNs); this.addOrUpdateMNs(diff.mnList); this.lastDiffMerkleRootMNList = diff.merkleRootMNList; this.merkleRootMNList = this.calculateMerkleRoot(); if (!this.verify()) { throw new Error("Merkle root from the diff doesn't match calculated merkle root after diff is applied"); } this.cbTx = new Transaction(diff.cbTx); this.cbTxMerkleTree = diff.cbTxMerkleTree.copy(); this.validMNs = this.mnList.filter(function (smlEntry) { return smlEntry.isValid; }); }; /** * @private * Adds MNs to the MN list * @param {SimplifiedMNListEntry[]} mnListEntries */ SimplifiedMNList.prototype.addOrUpdateMNs = function addMNs(mnListEntries) { var newMNListEntries = mnListEntries.map(function (mnListEntry) { return mnListEntry.copy(); }); newMNListEntries.forEach(function (newMNListEntry) { var indexOfOldEntry = this.mnList.findIndex(function (oldMNListEntry) { return oldMNListEntry.proRegTxHash === newMNListEntry.proRegTxHash; }); if (indexOfOldEntry > -1) { this.mnList[indexOfOldEntry] = newMNListEntry; } else { return this.mnList.push(newMNListEntry); } }, this); }; /** * @private * Deletes MNs from the MN list * @param {string[]} proRegTxHashes - list of proRegTxHashes to delete from MNList */ SimplifiedMNList.prototype.deleteMNs = function deleteMN(proRegTxHashes) { proRegTxHashes.forEach(function (proRegTxHash) { var mnIndex = this.mnList.findIndex(function (MN) { return MN.proRegTxHash === proRegTxHash; }); if (mnIndex > -1) { this.mnList.splice(mnIndex, 1); } }, this); }; /** * Compares merkle root from the most recent diff applied matches the merkle root of the list * @returns {boolean} */ SimplifiedMNList.prototype.verify = function verify() { return this.calculateMerkleRoot() === this.lastDiffMerkleRootMNList; }; /** * @private * Sorts MN List in deterministic order */ SimplifiedMNList.prototype.sort = function sort() { this.mnList.sort(function (a, b) { return Buffer.compare(Buffer.from(a.proRegTxHash, 'hex').reverse(), Buffer.from(b.proRegTxHash, 'hex').reverse()); }); }; /** * Calculates merkle root of the MN list * @returns {string} */ SimplifiedMNList.prototype.calculateMerkleRoot = function calculateMerkleRoot() { if (this.mnList.length < 1) { return constants.NULL_HASH; } this.sort(); var sortedEntryHashes = this.mnList.map( function (mnListEntry) { return mnListEntry.calculateHash(); } ); return getMerkleRoot(getMerkleTree(sortedEntryHashes)).reverse().toString('hex'); }; /** * Returns a list of valid masternodes * @returns {SimplifiedMNListEntry[]} */ SimplifiedMNList.prototype.getValidMasternodesList = function getValidMasternodes() { return this.validMNs; }; /** * Converts simplified MN list to simplified MN list diff that can be used to serialize data * to json, buffer, or a hex string */ SimplifiedMNList.prototype.toSimplifiedMNListDiff = function toSimplifiedMNListDiff() { if (!this.cbTx || !this.cbTxMerkleTree) { throw new Error("Can't convert MN list to diff - cbTx is missing"); } return SimplifiedMNListDiff.fromObject({ baseBlockHash: this.baseBlockHash, blockHash: this.blockHash, cbTx: new Transaction(this.cbTx), cbTxMerkleTree: this.cbTxMerkleTree, // Always empty, as simplified MN list doesn't have a deleted mn list deletedMNs: [], mnList: this.mnList, merkleRootMNList: this.merkleRootMNList }); }; module.exports = SimplifiedMNList;