UNPKG

bbqpool-stratum

Version:

High performance Stratum poolserver in Node.js. Optimized to build with GCC 10 and O3 / bugfixes

301 lines (268 loc) 9.85 kB
/* * * Transactions (Updated) * */ const utils = require('./utils'); //////////////////////////////////////////////////////////////////////////////// // Main Transactions Function const Transactions = function() { // Default Transaction Protocol this.default = function(poolConfig, rpcData, extraNoncePlaceholder, auxMerkle) { const txLockTime = 0; const txInSequence = 0; const txInPrevOutHash = ''; const txInPrevOutIndex = Math.pow(2, 32) - 1; const txOutputBuffers = []; let txExtraPayload; let txVersion = poolConfig.primary.coin.version; const network = !poolConfig.settings.testnet ? poolConfig.primary.coin.mainnet : poolConfig.primary.coin.testnet; // Handle Version w/ CoinbaseTxn if (rpcData.coinbasetxn && rpcData.coinbasetxn.data) { txVersion = parseInt(utils.reverseHex(rpcData.coinbasetxn.data.slice(0, 8)), 16); } // Support Coinbase v3 Block Template if (rpcData.coinbase_payload && rpcData.coinbase_payload.length > 0) { txExtraPayload = Buffer.from(rpcData.coinbase_payload, 'hex'); txVersion = txVersion + (5 << 16); } let reward = rpcData.coinbasevalue; let rewardToPool = reward; const coinbaseAux = rpcData.coinbaseaux.flags ? Buffer.from(rpcData.coinbaseaux.flags, 'hex') : Buffer.from([]); const poolAddressScript = utils.addressToScript(poolConfig.primary.address, network); // Handle Timestamp if Necessary const txTimestamp = poolConfig.primary.coin.hybrid === true ? utils.packUInt32LE(rpcData.curtime) : Buffer.from([]); let scriptSig = Buffer.concat([ utils.serializeNumber(rpcData.height), coinbaseAux, utils.serializeNumber(Date.now() / 1000 | 0), Buffer.from([extraNoncePlaceholder.length]), ]); if (auxMerkle && poolConfig.auxiliary && poolConfig.auxiliary.enabled) { scriptSig = Buffer.concat([ scriptSig, Buffer.from(poolConfig.auxiliary.coin.header, 'hex'), utils.reverseBuffer(auxMerkle.root), utils.packUInt32LE(auxMerkle.data.length), utils.packUInt32LE(0) ]); } // Build First Part of Generation Transaction const p1 = Buffer.concat([ utils.packUInt32LE(txVersion), txTimestamp, utils.varIntBuffer(1), utils.uint256BufferFromHash(txInPrevOutHash), utils.packUInt32LE(txInPrevOutIndex), utils.varIntBuffer(scriptSig.length + extraNoncePlaceholder.length), scriptSig ]); // Handle Masternodes if (rpcData.masternode) { if (rpcData.masternode.payee) { const payeeReward = rpcData.masternode.amount; const payeeScript = utils.addressToScript(rpcData.masternode.payee, network); reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); } else if (rpcData.masternode.length > 0) { rpcData.masternode.forEach(payee => { const payeeReward = payee.amount; let payeeScript; if (payee.script) { payeeScript = Buffer.from(payee.script, 'hex'); } else { payeeScript = utils.addressToScript(payee.payee, network); } reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); }); } } // Handle Smartnodes if (rpcData.smartnode) { if (rpcData.smartnode.payee) { const payeeReward = rpcData.smartnode.amount; const payeeScript = utils.addressToScript(rpcData.smartnode.payee, network); reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); } else if (rpcData.smartnode.length > 0) { rpcData.smartnode.forEach(payee => { const payeeReward = payee.amount; let payeeScript; if (payee.script) { payeeScript = Buffer.from(payee.script, 'hex'); } else { payeeScript = utils.addressToScript(payee.payee, network); } reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); }); } } // Handle Superblocks if (rpcData.superblock && rpcData.superblock.length > 0) { rpcData.superblock.forEach(payee => { const payeeReward = payee.amount; let payeeScript; if (payee.script) { payeeScript = Buffer.from(payee.script, 'hex'); } else { payeeScript = utils.addressToScript(payee.payee, network); } reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); }); } // Handle ZNodes (Evo Nodes) if (rpcData.znode_payments_started && rpcData.znode_payments_enforced) { rpcData.znode.forEach(payee => { const payeeReward = payee.amount; let payeeScript; if (payee.script) { payeeScript = Buffer.from(payee.script, 'hex'); } else { payeeScript = utils.addressToScript(payee.payee, network); } // Block Reward Already Subtracts ZNode Rewards (FiroCoin) txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); }); } // Handle Other Given Payees if (rpcData.payee) { const payeeReward = rpcData.payee_amount || Math.ceil(reward / 5); const payeeScript = utils.addressToScript(rpcData.payee, network); reward -= payeeReward; rewardToPool -= payeeReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(payeeReward), utils.varIntBuffer(payeeScript.length), payeeScript, ])); } // Handle Secondary Transactions let founderReward, founderScript; switch (poolConfig.primary.coin.rewards.type) { // RTM-Based Transactions case 'raptoreum': if (rpcData.founder_payments_started && rpcData.founder) { founderReward = rpcData.founder.amount; founderScript = utils.addressToScript(rpcData.founder.payee, network); reward -= founderReward; rewardToPool -= founderReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(founderReward), utils.varIntBuffer(founderScript.length), founderScript, ])); } break; // FIRO-Based Transactions case 'firocoin': poolConfig.primary.coin.rewards.addresses.forEach((address) => { founderReward = address.amount; founderScript = utils.addressToScript(address.address, network); // Block Reward Already Subtracts Founder Rewards (FiroCoin) txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(founderReward), utils.varIntBuffer(founderScript.length), founderScript, ])); }); break; // HVQ-Based Transactions case 'hivecoin': founderReward = rpcData.CommunityAutonomousValue; founderScript = utils.addressToScript(rpcData.CommunityAutonomousAddress, network); txOutputBuffers.unshift(Buffer.concat([ utils.packUInt64LE(founderReward), utils.varIntBuffer(founderScript.length), founderScript, ])); break; default: break; } // Handle Recipient Transactions let recipientTotal = 0; poolConfig.primary.recipients.forEach(recipient => { const recipientReward = Math.floor(recipient.percentage * reward); const recipientScript = utils.addressToScript(recipient.address, network); recipientTotal += recipientReward; txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(recipientReward), utils.varIntBuffer(recipientScript.length), recipientScript, ])); }); // Remove Recipient Percentages from Total reward -= recipientTotal; rewardToPool -= recipientTotal; // Handle Pool Transaction txOutputBuffers.unshift(Buffer.concat([ utils.packUInt64LE(rewardToPool), utils.varIntBuffer(poolAddressScript.length), poolAddressScript ])); // Handle Witness Commitment if (rpcData.default_witness_commitment !== undefined) { const witness_commitment = Buffer.from(rpcData.default_witness_commitment, 'hex'); txOutputBuffers.push(Buffer.concat([ utils.packUInt64LE(0), utils.varIntBuffer(witness_commitment.length), witness_commitment ])); } // Combine Output Transactions const outputTransactions = Buffer.concat([ utils.varIntBuffer(txOutputBuffers.length), Buffer.concat(txOutputBuffers) ]); // Build Second Part of Generation Transaction let p2 = Buffer.concat([ utils.packUInt32LE(txInSequence), outputTransactions, utils.packUInt32LE(txLockTime), ]); // Check for Extra Transaction Payload if (txExtraPayload !== undefined) { p2 = Buffer.concat([ p2, utils.varIntBuffer(txExtraPayload.length), txExtraPayload ]); } return [p1, p2]; }; }; module.exports = Transactions;