UNPKG

bgoldjs-lib-bit

Version:

Client-side Bitcoin Gold JavaScript library

114 lines (113 loc) 3.34 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); // https://github.com/BTCGPU/BTCGPU/blob/c919e0774806601f8b192378d078f63f7804b721/src/pow.cpp#L74 const BN = require('bn.js'); const b0 = new BN(0); function calcNextBits(currentBlock, previousBlocks, lwmaConfig) { if (!previousBlocks || previousBlocks.length <= lwmaConfig.averagingWindow) { throw new Error( 'LWMA need the last ' + (lwmaConfig.averagingWindow + 1) + ' blocks to determine the next target', ); } const prevBlocks = {}; previousBlocks.forEach(b => { prevBlocks[b.height] = b; }); for ( let i = currentBlock.height - lwmaConfig.averagingWindow - 1; i < currentBlock.height; i++ ) { if (!prevBlocks[i]) { throw new Error( 'Block with height ' + i + ' is missing, cannot calculate next target', ); } } // loss of precision when converting target to bits, comparing target to target // (from bits) will result in different uint256 const nextTarget = getLwmaTarget(currentBlock, prevBlocks, lwmaConfig); const bits = targetToBits(nextTarget); return bits; } exports.calcNextBits = calcNextBits; function getLwmaTarget(cur, prevBlocks, lwmaConfig) { const weight = lwmaConfig.adjustWeight; const height = cur.height; let prev = prevBlocks[height - 1]; // Special testnet handling if (lwmaConfig.regtest) { return bitsToTarget(prev.bits); } const limitBig = new BN(lwmaConfig.powLimit.toString()); if ( lwmaConfig.testnet && cur.timestamp > prev.timestamp + lwmaConfig.powTargetSpacing * 2 ) { return limitBig; } let totalBig = b0; let t = 0; let j = 0; const ts = 6 * lwmaConfig.powTargetSpacing; const dividerBig = new BN( weight * lwmaConfig.averagingWindow * lwmaConfig.averagingWindow, ); // Loop through N most recent blocks. "< height", not "<=" for (let i = height - lwmaConfig.averagingWindow; i < height; i++) { cur = prevBlocks[i]; prev = prevBlocks[i - 1]; let solvetime = cur.timestamp - prev.timestamp; if (lwmaConfig.solveTimeLimitation && solvetime > ts) { solvetime = ts; } j += 1; t += solvetime * j; const targetBig = bitsToTarget(cur.bits); totalBig = totalBig.add(targetBig.div(dividerBig)); } // Keep t reasonable in case strange solvetimes occurred. if ( t < Math.trunc( (lwmaConfig.averagingWindow * weight) / lwmaConfig.minDenominator, ) ) { t = Math.trunc( (lwmaConfig.averagingWindow * weight) / lwmaConfig.minDenominator, ); } let newTargetBig = totalBig.mul(new BN(t)); if (newTargetBig.cmp(limitBig) >= 0) { newTargetBig = limitBig; } return newTargetBig; } function bitsToTarget(bits) { const bitsBig = new BN(bits); const size = bitsBig.shrn(24).toNumber(); const word = bits & 0x007fffff; const wordBig = new BN(word); if (size <= 3) { return wordBig.shrn(8 * (3 - size)); } return wordBig.shln(8 * (size - 3)); } function targetToBits(target) { let nsize = Math.trunc((target.bitLength() + 7) / 8); let cBig; if (nsize <= 3) { cBig = target.shln(8 * (3 - nsize)); } else { cBig = target.shrn(8 * (nsize - 3)); } let c = cBig.toNumber(); if (c & 0x00800000) { c >>= 8; nsize += 1; } c |= nsize << 24; return c; }