alterdot-lib
Version:
A pure and powerful JavaScript Alterdot library.
275 lines (237 loc) • 8.71 kB
JavaScript
const _ = require('lodash');
const BufferReader = require('../encoding/bufferreader');
const BufferWriter = require('../encoding/bufferwriter');
const BufferUtil = require('../util/buffer');
const isHexString = require('../util/js').isHexa;
const SimplifiedMNListEntry = require('./SimplifiedMNListEntry');
const QuorumEntry = require('./QuorumEntry');
const PartialMerkleTree = require('../block/PartialMerkleTree');
const Transaction = require('../transaction');
const constants = require('../constants');
const Networks = require('../networks');
/**
* @param {Buffer|Object|string} [arg] - A Buffer, JSON string, or Object representing a MnListDiff
* @param {string} [network]
* @class SimplifiedMNListDiff
* @property {string} baseBlockHash - sha256
* @property {string} blockHash - sha256
* @property {PartialMerkleTree} cbTxMerkleTree
* @property {Transaction} cbTx
* @property {Array<string>} deletedMNs - sha256 hashes of deleted MNs
* @property {Array<SimplifiedMNListEntry>} mnList
* @property {Array<obj>} deletedQuorums - deleted quorum objects
* @property {Array<QuorumEntry>} newQuorums
* @property {string} merkleRootMNList - merkle root of the whole mn list
* @property {string} merkleRootQuorums - merkle root of the quorum list
*/
function SimplifiedMNListDiff(arg, network) {
if (arg) {
const validNetwork = Networks.get(network);
if (arg instanceof SimplifiedMNListDiff) {
return arg.copy();
}
if (BufferUtil.isBuffer(arg)) {
return SimplifiedMNListDiff.fromBuffer(arg, validNetwork);
}
if (_.isObject(arg)) {
return SimplifiedMNListDiff.fromObject(arg, validNetwork);
}
if (isHexString(arg)) {
return SimplifiedMNListDiff.fromHexString(arg, validNetwork);
}
throw new TypeError(
'Unrecognized argument passed to SimplifiedMNListDiff constructor'
);
}
}
/**
* Creates MnListDiff from a Buffer.
* @param {Buffer} buffer
* @param {string} [network]
* @return {SimplifiedMNListDiff}
*/
SimplifiedMNListDiff.fromBuffer = function fromBuffer(buffer, network) {
const bufferReader = new BufferReader(Buffer.from(buffer));
const data = {};
data.baseBlockHash = bufferReader
.read(constants.SHA256_HASH_SIZE)
.reverse()
.toString('hex');
data.blockHash = bufferReader
.read(constants.SHA256_HASH_SIZE)
.reverse()
.toString('hex');
data.cbTxMerkleTree = PartialMerkleTree.fromBufferReader(bufferReader);
data.cbTx = new Transaction().fromBufferReader(bufferReader);
const deletedMNsCount = bufferReader.readVarintNum();
data.deletedMNs = [];
for (let i = 0; i < deletedMNsCount; i += 1) {
data.deletedMNs.push(
bufferReader.read(constants.SHA256_HASH_SIZE).reverse().toString('hex')
);
}
const mnListSize = bufferReader.readVarintNum();
data.mnList = [];
for (let i = 0; i < mnListSize; i += 1) {
data.mnList.push(
SimplifiedMNListEntry.fromBuffer(
bufferReader.read(constants.SML_ENTRY_SIZE),
network
)
);
}
const deletedQuorumsCount = bufferReader.readVarintNum();
data.deletedQuorums = [];
for (let i = 0; i < deletedQuorumsCount; i += 1) {
const deletedQuorum = {};
deletedQuorum.llmqType = bufferReader.readUInt8();
deletedQuorum.quorumHash = bufferReader
.read(constants.SHA256_HASH_SIZE)
.reverse()
.toString('hex');
data.deletedQuorums.push(deletedQuorum);
}
const newQuorumsSize = bufferReader.readVarintNum();
data.newQuorums = [];
for (let i = 0; i < newQuorumsSize; i += 1) {
const quorumEntrySize = bufferReader.readVarintNum();
const entry = bufferReader.read(quorumEntrySize);
data.newQuorums.push(QuorumEntry.fromBuffer(entry));
}
data.merkleRootMNList = data.cbTx.extraPayload.merkleRootMNList;
if (data.cbTx.extraPayload.version >= 2) {
data.merkleRootQuorums = data.cbTx.extraPayload.merkleRootQuorums;
}
return this.fromObject(data, network);
};
/**
* @param {string} hexString
* @param {string} [network]
* @return {SimplifiedMNListDiff}
*/
SimplifiedMNListDiff.fromHexString = function fromHexString(
hexString,
network
) {
return SimplifiedMNListDiff.fromBuffer(
Buffer.from(hexString, 'hex'),
network
);
};
/**
* Serializes mnlist diff to a Buffer
* @return {Buffer}
*/
SimplifiedMNListDiff.prototype.toBuffer = function toBuffer() {
const bufferWriter = new BufferWriter();
bufferWriter.write(Buffer.from(this.baseBlockHash, 'hex').reverse());
bufferWriter.write(Buffer.from(this.blockHash, 'hex').reverse());
bufferWriter.write(this.cbTxMerkleTree.toBuffer());
bufferWriter.write(this.cbTx.toBuffer());
bufferWriter.writeVarintNum(this.deletedMNs.length);
this.deletedMNs.forEach((deleteMNHash) => {
bufferWriter.write(Buffer.from(deleteMNHash, 'hex').reverse());
});
bufferWriter.writeVarintNum(this.mnList.length);
this.mnList.forEach((simplifiedMNListEntry) => {
bufferWriter.write(simplifiedMNListEntry.toBuffer());
});
bufferWriter.writeVarintNum(this.deletedQuorums.length);
this.deletedQuorums.forEach((deletedQuorum) => {
bufferWriter.writeUInt8(deletedQuorum.llmqType);
bufferWriter.write(Buffer.from(deletedQuorum.quorumHash, 'hex').reverse());
});
bufferWriter.writeVarintNum(this.newQuorums.length);
this.newQuorums.forEach((quorumEntry) => {
bufferWriter.writeVarintNum(quorumEntry.toBuffer().length);
bufferWriter.write(quorumEntry.toBuffer());
});
return bufferWriter.toBuffer();
};
/**
* Creates MNListDiff from object
* @param obj
* @param {string|Network} [network]
* @return {SimplifiedMNListDiff}
*/
SimplifiedMNListDiff.fromObject = function fromObject(obj, network) {
const simplifiedMNListDiff = new SimplifiedMNListDiff();
const validNetwork = Networks.get(network);
simplifiedMNListDiff.baseBlockHash = obj.baseBlockHash;
simplifiedMNListDiff.blockHash = obj.blockHash;
/* cbTxMerkleRoot start */
simplifiedMNListDiff.cbTxMerkleTree = new PartialMerkleTree(
obj.cbTxMerkleTree
);
/* cbTxMerkleRoot stop */
simplifiedMNListDiff.cbTx = new Transaction(obj.cbTx);
// Copy array of strings
simplifiedMNListDiff.deletedMNs = obj.deletedMNs.slice();
simplifiedMNListDiff.mnList = obj.mnList.map(
(SMLEntry) => new SimplifiedMNListEntry(SMLEntry, validNetwork)
);
simplifiedMNListDiff.deletedQuorums = obj.deletedQuorums.slice();
simplifiedMNListDiff.newQuorums = obj.newQuorums.map(
(quorumEntry) => new QuorumEntry(quorumEntry)
);
simplifiedMNListDiff.merkleRootMNList = obj.merkleRootMNList;
if (obj.merkleRootQuorums) {
simplifiedMNListDiff.merkleRootQuorums = obj.merkleRootQuorums;
}
if (simplifiedMNListDiff.mnList.length > 0) {
if (
validNetwork &&
simplifiedMNListDiff.mnList[0].network.name !== validNetwork.name
) {
throw new Error(
`votingAddress network is not equal to ${validNetwork.name}`
);
}
simplifiedMNListDiff.network = simplifiedMNListDiff.mnList[0].network;
} else {
simplifiedMNListDiff.network = validNetwork;
}
return simplifiedMNListDiff;
};
/**
* This method constructs the diff from the JSON produced by JSON.sringify.
* PLEASE DON'T PASS RESULT OF .toObject() to this method!
* @param {Object} diffJSON
* @return {SimplifiedMNListDiff}
*/
SimplifiedMNListDiff.fromJSON = function fromJSON(diffJSON) {
const cbTxMerkleTree = new PartialMerkleTree();
cbTxMerkleTree.totalTransactions = diffJSON.cbTxMerkleTree.totalTransactions;
cbTxMerkleTree.merkleHashes = diffJSON.cbTxMerkleTree.merkleHashes;
cbTxMerkleTree.merkleFlags = diffJSON.cbTxMerkleTree.merkleFlags;
return SimplifiedMNListDiff.fromObject(
{
...diffJSON,
cbTxMerkleTree,
},
Networks.get(diffJSON.network.name)
);
};
SimplifiedMNListDiff.prototype.toObject = function toObject() {
const obj = {};
obj.baseBlockHash = this.baseBlockHash;
obj.blockHash = this.blockHash;
/* cbTxMerkleRoot start */
obj.cbTxMerkleTree = this.cbTxMerkleTree.toString();
/* cbTxMerkleRoot stop */
obj.cbTx = this.cbTx.serialize(true);
// Copy array of strings
obj.deletedMNs = this.deletedMNs.slice();
obj.mnList = this.mnList.map((SMLEntry) => SMLEntry.toObject());
obj.deletedQuorums = this.deletedQuorums.slice();
obj.newQuorums = this.newQuorums.map((SMLEntry) => SMLEntry.toObject());
obj.merkleRootMNList = this.merkleRootMNList;
if (this.merkleRootQuorums) {
obj.merkleRootQuorums = this.merkleRootQuorums;
}
return obj;
};
SimplifiedMNListDiff.prototype.copy = function copy() {
return SimplifiedMNListDiff.fromBuffer(this.toBuffer(), this.network);
};
module.exports = SimplifiedMNListDiff;