From dd5c9096a7d22fdb400abe9e0abce177222949b2 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 14 May 2016 20:57:52 -0700 Subject: [PATCH] use js numbers for values. --- lib/bcoin/block.js | 15 ++-- lib/bcoin/chain.js | 2 +- lib/bcoin/coin.js | 4 +- lib/bcoin/mempool.js | 34 ++++----- lib/bcoin/miner.js | 4 +- lib/bcoin/mtx.js | 34 ++++----- lib/bcoin/output.js | 17 ++--- lib/bcoin/protocol/constants.js | 10 +-- lib/bcoin/protocol/framer.js | 4 - lib/bcoin/protocol/parser.js | 4 +- lib/bcoin/script.js | 68 ++++++----------- lib/bcoin/tx.js | 66 ++++++++--------- lib/bcoin/txdb.js | 10 +-- lib/bcoin/utils.js | 125 ++++++++++++++++++++++++-------- test/mempool-test.js | 2 +- test/script-test.js | 4 +- test/tx-test.js | 2 +- test/utils-test.js | 12 +-- test/wallet-test.js | 18 ++--- 19 files changed, 235 insertions(+), 200 deletions(-) diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 2320ce0a..b7287e99 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -434,7 +434,7 @@ Block.prototype.getReward = function getReward(network) { var i; for (i = 1; i < this.txs.length; i++) - reward.iadd(this.txs[i].getFee()); + reward += this.txs[i].getFee(); return reward; }; @@ -463,13 +463,18 @@ Block.reward = function reward(height, network) { halvings = height / network.halvingInterval | 0; if (height < 0) - return new bn(0); + return 0; if (halvings >= 64) - return new bn(0); + return 0; - reward = new bn(5000000000); - reward.iushrn(halvings); + if (halvings === 0) + return 5000000000; + + reward = 2500000000 >>> (halvings - 1); + + // reward = 5000000000; + // reward = Math.floor(reward / Math.pow(2, halvings)); return reward; }; diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 35955cc5..efd82250 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -909,7 +909,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, state, callbac } // Make sure the miner isn't trying to conjure more coins. - if (block.getClaimed().cmp(block.getReward(self.network)) > 0) { + if (block.getClaimed() > block.getReward(self.network)) { return callback(new VerifyError(block, 'invalid', 'bad-cb-amount', diff --git a/lib/bcoin/coin.js b/lib/bcoin/coin.js index 58236ba1..7c94c982 100644 --- a/lib/bcoin/coin.js +++ b/lib/bcoin/coin.js @@ -45,8 +45,6 @@ function Coin(tx, index) { this.version = tx.version; this.height = tx.height; this.value = tx.outputs[index].value; - if (tx.mutable) - this.value = this.value.clone(); this.script = bcoin.script(tx.outputs[index].script, false); this.coinbase = tx.isCoinbase(); this.hash = tx.hash('hex'); @@ -64,7 +62,7 @@ function Coin(tx, index) { assert(typeof this.version === 'number'); assert(utils.isNumber(this.height)); - assert(bn.isBN(this.value)); + assert(typeof this.value === 'number'); assert(this.script instanceof bcoin.script); assert(typeof this.coinbase === 'boolean'); assert(!this.hash || typeof this.hash === 'string'); diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index 305186b5..0356566e 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -843,7 +843,7 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(entry, limit, callb self.total--; if (limit) { - rate = entry.fees.muln(1000).divn(entry.size).toNumber(); + rate = Math.floor(entry.fees * 1000 / entry.size); rate += self.minReasonableFee; if (rate > self.minFeeRate) { self.minFeeRate = rate; @@ -952,14 +952,14 @@ Mempool.prototype.verify = function verify(entry, callback) { rejectFee = tx.getMinFee(size, minRate); minRelayFee = tx.getMinFee(size, self.minRelayFee); - if (rejectFee.cmpn(0) > 0 && modFee.cmp(rejectFee) < 0) { + if (rejectFee > 0 && modFee < rejectFee) { return callback(new VerifyError(tx, 'insufficientfee', 'mempool min fee not met', 0)); } - if (self.relayPriority && modFee.cmp(minRelayFee) < 0) { + if (self.relayPriority && modFee < minRelayFee) { if (!entry.isFree(height)) { return callback(new VerifyError(tx, 'insufficientfee', @@ -973,7 +973,7 @@ Mempool.prototype.verify = function verify(entry, callback) { // sending thousands of free transactions just to be // annoying or make others' transactions take longer // to confirm. - if (self.limitFree && modFee.cmp(minRelayFee) < 0) { + if (self.limitFree && modFee < minRelayFee) { now = utils.now(); if (!self.lastTime) @@ -995,7 +995,7 @@ Mempool.prototype.verify = function verify(entry, callback) { self.freeCount += size; } - if (self.rejectAbsurdFees && fee.cmp(minRelayFee.muln(10000)) > 0) + if (self.rejectAbsurdFees && fee > minRelayFee * 10000) return callback(new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0)); if (!tx.checkInputs(height, ret)) @@ -1136,7 +1136,7 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, callback, force) { */ Mempool.prototype.getBalance = function getBalance(callback) { - var total = new bn(0); + var total = 0; var i; return this.db.iterate({ @@ -1151,10 +1151,10 @@ Mempool.prototype.getBalance = function getBalance(callback) { return callback(err); for (i = 0; i < coins.length; i++) - total.iadd(coins[i].value); + total += coins[i].value; return callback(null, { - confirmed: new bn(0), + confirmed: 0, unconfirmed: total, total: total }); @@ -1876,12 +1876,12 @@ MempoolEntry.fromRaw = function fromRaw(data) { return new MempoolEntry({ tx: bcoin.tx.fromRaw(p), height: p.readU32(), - priority: p.readVarint(true), - chainValue: p.readVarint(true), + priority: p.readVarint(), + chainValue: p.readVarint(), ts: p.readU32(), count: p.readU32(), size: p.readU32(), - fees: p.readVarint(true) + fees: p.readVarint() }); }; @@ -1894,12 +1894,12 @@ MempoolEntry.fromRaw = function fromRaw(data) { */ MempoolEntry.prototype.getPriority = function getPriority(height) { - var heightDelta = Math.max(0, height - this.height); + var heightDelta = height - this.height; var modSize = this.tx.getModifiedSize(this.size); - var deltaPriority = new bn(heightDelta).mul(this.chainValue).divn(modSize); - var result = this.priority.add(deltaPriority); - if (result.cmpn(0) < 0) - result = new bn(0); + var deltaPriority = heightDelta * this.chainValue / modSize; + var result = this.priority * deltaPriority; + if (result < 0) + result = 0; return result; }; @@ -1913,7 +1913,7 @@ MempoolEntry.prototype.getPriority = function getPriority(height) { MempoolEntry.prototype.isFree = function isFree(height) { var priority = this.getPriority(height); - return priority.cmp(constants.tx.FREE_THRESHOLD) > 0; + return priority > constants.tx.FREE_THRESHOLD; }; /* diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index 5536c88f..6ccf06db 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -392,7 +392,7 @@ function MinerBlock(options) { this.coinbase.addOutput({ address: options.address, - value: new bn(0) + value: 0 }); // Create our block @@ -416,7 +416,7 @@ function MinerBlock(options) { this.coinbase.inputs[0].witness.items[0] = this.witnessNonce; this.coinbase.addOutput({ script: new bcoin.script(), - value: new bn(0) + value: 0 }); } diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index f6262c04..5888dc00 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -1082,11 +1082,11 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { function total() { if (options.subtractFee != null) return outputValue; - return outputValue.add(fee); + return outputValue + fee; } function isFull() { - return tx.getInputValue().cmp(total()) >= 0; + return tx.getInputValue() >= total(); } function addCoins() { @@ -1124,7 +1124,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { // Transfer `total` funds maximum. addCoins(); } else { - fee = new bn(constants.tx.MIN_FEE); + fee = constants.tx.MIN_FEE; // Transfer `total` funds maximum. addCoins(); @@ -1136,7 +1136,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { // In case we don't have a change address, // use a fake p2pkh output to gauge size. keyHash: constants.ZERO_HASH.slice(0, 20), - value: new bn(0) + value: 0 }); // Change fee value if it is more than 1024 @@ -1151,7 +1151,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { // fee is zero (i.e. the mempool is // not full). if (tx.isFree(options.height + 1, size)) { - fee = new bn(0); + fee = 0; break; } tryFree = false; @@ -1175,11 +1175,11 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { throw err; } - if (fee.cmp(constants.tx.MAX_FEE) > 0) - fee = constants.tx.MAX_FEE.clone(); + if (fee > constants.tx.MAX_FEE) + fee = constants.tx.MAX_FEE; // How much money is left after filling outputs. - change = tx.getInputValue().sub(total()); + change = tx.getInputValue() - total(); // Attempt to subtract fee. if (options.subtractFee != null) { @@ -1190,18 +1190,18 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) { if (!output) throw new Error('Subtraction index does not exist.'); - min = fee.add(output.getDustThreshold()); + min = fee + output.getDustThreshold(); - if (output.value.cmp(min) < 0) + if (output.value < 0) throw new Error('Could not subtract fee.'); - output.value.isub(fee); + output.value -= fee; } else { for (i = 0; i < tx.outputs.length; i++) { output = tx.outputs[i]; - min = fee.add(output.getDustThreshold()); - if (output.value.cmp(min) >= 0) { - output.value.isub(fee); + min = fee + output.getDustThreshold(); + if (output.value >= min) { + output.value -= fee; break; } } @@ -1253,10 +1253,10 @@ MTX.prototype.fill = function fill(coins, options) { // Do nothing. Change is added to fee. this.outputs.pop(); this.changeIndex = -1; - assert(this.getFee().cmp(result.fee.add(result.change)) === 0); + assert(this.getFee() === result.fee + result.change); } else { this.changeIndex = this.outputs.length - 1; - assert(this.getFee().cmp(result.fee) === 0); + assert(this.getFee() === result.fee); } return result; @@ -1287,7 +1287,7 @@ MTX.prototype.sortMembers = function sortMembers() { }); this.outputs = this.outputs.slice().sort(function(a, b) { - var res = a.value.cmp(b.value); + var res = a.value - b.value; if (res !== 0) return res; return utils.cmp(a.encode(), b.encode()); diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index 7e062715..52e2200f 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -35,20 +35,15 @@ function Output(options, mutable) { value = options.value; - if (typeof value === 'number') { - assert(value % 1 === 0, 'Output value cannot be a float.'); - value = new bn(value); - } - if (!value) - value = new bn(0); + value = 0; this.mutable = !!mutable; this.value = value; this.script = bcoin.script(options.script, this.mutable); - assert(bn.isBN(this.value)); - assert(!this.mutable || !this.value.isNeg()); + assert(typeof this.value === 'number'); + assert(!this.mutable || this.value > 0); } /** @@ -167,12 +162,12 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) { rate = constants.tx.MIN_RELAY; if (this.script.isUnspendable()) - return new bn(0); + return 0; size = Framer.output(this, new BufferWriter()).written; size += 148; - return bcoin.tx.getMinFee(size, rate).muln(3); + return 3 * bcoin.tx.getMinFee(size, rate); }; /** @@ -182,7 +177,7 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) { */ Output.prototype.isDust = function isDust(rate) { - return this.value.cmp(this.getDustThreshold(rate)) < 0; + return this.value < this.getDustThreshold(rate); }; /** diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index b2f88bf5..f50c28d2 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -306,7 +306,7 @@ exports.opcodesByVal = utils.revMap(exports.opcodes); * @default */ -exports.COIN = new bn(10000000).muln(10); +exports.COIN = 100000000; /** * One bitcoin / 100. @@ -314,7 +314,7 @@ exports.COIN = new bn(10000000).muln(10); * @default */ -exports.CENT = new bn(1000000); +exports.CENT = 1000000; /** * Maximum amount of money in satoshis (1btc * 21million) @@ -322,7 +322,7 @@ exports.CENT = new bn(1000000); * @default */ -exports.MAX_MONEY = new bn(21000000).mul(exports.COIN); +exports.MAX_MONEY = 21000000 * exports.COIN; /** * Sighash Types. @@ -410,10 +410,10 @@ exports.tx = { MAX_SIZE: 100000, MAX_COST: 400000, MIN_FEE: 10000, - MAX_FEE: exports.COIN.divn(10), + MAX_FEE: exports.COIN / 10, MIN_RELAY: 10000, BARE_MULTISIG: true, - FREE_THRESHOLD: exports.COIN.muln(144).divn(250), + FREE_THRESHOLD: Math.floor(exports.COIN * 144 / 250), MAX_SIGOPS: exports.block.MAX_SIGOPS / 5, MAX_SIGOPS_COST: exports.block.MAX_SIGOPS_COST / 5, COINBASE_MATURITY: 100 diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index 036094f8..901f8ea2 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -652,8 +652,6 @@ Framer.coin = function _coin(coin, extended, writer) { if (height === -1) height = 0x7fffffff; - assert(coin.value.byteLength() <= 8); - p.writeU32(coin.version); p.writeU32(height); p.write64(coin.value); @@ -753,8 +751,6 @@ Framer.input = function _input(input, writer) { Framer.output = function _output(output, writer) { var p = new BufferWriter(writer); - assert(output.value.byteLength() <= 8); - p.write64(output.value); Framer.script(output.script, p); diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index ff70c6dc..90505bfd 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -875,7 +875,7 @@ Parser.parseOutput = function parseOutput(p) { p = new BufferReader(p); - value = p.read64(); + value = p.read64N(); script = Parser.parseScript(p); return { @@ -898,7 +898,7 @@ Parser.parseCoin = function parseCoin(p, extended) { version = p.readU32(); height = p.readU32(); - value = p.read64(); + value = p.read64N(); script = Parser.parseScript(p); coinbase = p.readU8() === 1; diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index a212766e..730dff9f 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -2700,35 +2700,26 @@ Script.isUnknownInput = function isUnknownInput(code, isWitness) { * @example * Script.createOutputScript({ address: '1HT7xU2Ngenf7D4yocz2SAcnNLW7rK8d4E' }); * @param {Object} options - * @param {Base58Address?} options.address - Base58 address to send to. + * @param {(Address|Base58Address)?} options.address - Address to send to. * @param {Buffer?} options.flags - Nulldata flags. * @param {Buffer?} options.key - Key for pay-to-pubkey. * @param {Buffer?} options.keyHash - Key has for pay-to-pubkeyhash. * @param {Buffer[]?} options.keys - Keys for pay-to-multisig. - * @param {Boolean|Buffer[]} options.scriptHash - Whether to create a scripthash + * @param {Buffer} options.scriptHash - Whether to create a scripthash * @returns {Script} */ Script.createOutputScript = function createOutputScript(options) { - var script, m, n, hash, flags, address, redeem; + var m, n, flags, address; if (!options) options = {}; if (options.address) { - if (typeof options.address === 'string') - address = bcoin.address.parseBase58(options.address); - - if (address.type === 'pubkeyhash') - script = Script.createPubkeyhash(address.hash); - else if (address.type === 'scripthash') - script = Script.createScripthash(address.hash); - else if (address.version !== -1) - script = Script.createWitnessProgram(address.version, address.hash); - else - assert(false, 'Unknown address type.'); - - return script; + address = options.address; + if (typeof address === 'string') + address = bcoin.address.fromBase58(address); + return address.toScript(); } if (options.flags) { @@ -2738,19 +2729,23 @@ Script.createOutputScript = function createOutputScript(options) { return Script.createNulldata(flags); } - if (options.key) { - script = Script.createPubkey(options.key); - } else if (options.keyHash) { + if (options.key) + return Script.createPubkey(options.key); + + if (options.keyHash) { assert(options.keyHash.length === 20); if (options.version != null) - script = Script.createWitnessProgram(options.version, options.keyHash); - else - script = Script.createPubkeyhash(options.keyHash); - } else if (options.keys) { + return Script.createWitnessProgram(options.version, options.keyHash); + return Script.createPubkeyhash(options.keyHash); + } + + if (options.keys) { m = options.m; n = options.n || options.keys.length; - script = Script.createMultisig(options.keys, m, n); - } else if (Buffer.isBuffer(options.scriptHash)) { + return Script.createMultisig(options.keys, m, n); + } + + if (options.scriptHash) { if (options.version != null) { assert(options.scriptHash.length === 32); return Script.createWitnessProgram(options.version, options.scriptHash); @@ -2759,28 +2754,7 @@ Script.createOutputScript = function createOutputScript(options) { return Script.createScripthash(options.scriptHash); } - if (!script) - return new Script([]); - - if (options.locktime != null) { - script.code.unshift(opcodes.OP_DROP); - script.code.unshift(opcodes.OP_CHECKLOCKTIMEVERIFY); - script.code.unshift(Script.array(options.locktime)); - } - - if (options.scriptHash) { - redeem = script; - if (options.version != null) { - hash = utils.sha256(redeem.encode()); - script = Script.createWitnessProgram(options.version, hash); - } else { - hash = utils.ripesha(redeem.encode()); - script = Script.createScripthash(hash); - } - script.redeem = redeem; - } - - return script; + return new Script(); }; /** diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index a995fa5e..86b57ebc 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -428,7 +428,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { for (i = 0; i < copy.outputs.length; i++) { if (i !== index) { copy.outputs[i].script = new Script([]); - copy.outputs[i].value = utils.U64; + copy.outputs[i].value = -1; } } @@ -651,9 +651,9 @@ TX.prototype.isCoinbase = function isCoinbase() { TX.prototype.getFee = function getFee() { if (!this.hasCoins()) - return new bn(0); + return 0; - return this.getInputValue().sub(this.getOutputValue()); + return this.getInputValue() - this.getOutputValue(); }; /** @@ -662,14 +662,14 @@ TX.prototype.getFee = function getFee() { */ TX.prototype.getInputValue = function getInputValue() { - var total = new bn(0); + var total = 0; var i; if (!this.hasCoins()) return total; for (i = 0; i < this.inputs.length; i++) - total.iadd(this.inputs[i].coin.value); + total += this.inputs[i].coin.value; return total; }; @@ -680,11 +680,11 @@ TX.prototype.getInputValue = function getInputValue() { */ TX.prototype.getOutputValue = function getOutputValue() { - var total = new bn(0); + var total = 0; var i; for (i = 0; i < this.outputs.length; i++) - total.iadd(this.outputs[i].value); + total += this.outputs[i].value; return total; }; @@ -1056,7 +1056,7 @@ TX.prototype.getSigops = function getSigops(flags) { TX.prototype.isSane = function isSane(ret) { var prevout = {}; - var total = new bn(0); + var total = 0; var i, input, output, size, key; if (!ret) @@ -1083,21 +1083,21 @@ TX.prototype.isSane = function isSane(ret) { for (i = 0; i < this.outputs.length; i++) { output = this.outputs[i]; - if (output.value.cmpn(0) < 0) { + if (output.value < 0) { ret.reason = 'bad-txns-vout-negative'; ret.score = 100; return false; } - if (output.value.cmp(constants.MAX_MONEY) > 0) { + if (output.value > constants.MAX_MONEY) { ret.reason = 'bad-txns-vout-toolarge'; ret.score = 100; return false; } - total.iadd(output.value); + total += output.value; - if (total.cmpn(0) < 0 || total.cmp(constants.MAX_MONEY) > 0) { + if (total < 0 || total > constants.MAX_MONEY) { ret.reason = 'bad-txns-txouttotal-toolarge'; ret.score = 100; return false; @@ -1286,7 +1286,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(flags) { */ TX.prototype.checkInputs = function checkInputs(spendHeight, ret) { - var total = new bn(0); + var total = 0; var i, input, coin, fee, value; if (!ret) @@ -1304,16 +1304,16 @@ TX.prototype.checkInputs = function checkInputs(spendHeight, ret) { } } - if (coin.value.cmpn(0) < 0 || coin.value.cmp(constants.MAX_MONEY) > 0) { + if (coin.value < 0 || coin.value > constants.MAX_MONEY) { ret.reason = 'bad-txns-inputvalues-outofrange'; ret.score = 100; return false; } - total.iadd(coin.value); + total += coin.value; } - if (total.cmpn(0) < 0 || total.cmp(constants.MAX_MONEY) > 0) { + if (total < 0 || total > constants.MAX_MONEY) { ret.reason = 'bad-txns-inputvalues-outofrange'; ret.score = 100; return false; @@ -1321,21 +1321,21 @@ TX.prototype.checkInputs = function checkInputs(spendHeight, ret) { value = this.getOutputValue(); - if (value.cmp(total) > 0) { + if (value > total) { ret.reason = 'bad-txns-in-belowout' ret.score = 100; return false; } - fee = total.sub(value); + fee = total - value; - if (fee.cmpn(0) < 0) { + if (fee < 0) { ret.reason = 'bad-txns-fee-negative'; ret.score = 100; return false; } - if (fee.cmp(constants.MAX_MONEY) > 0) { + if (fee > constants.MAX_MONEY) { ret.reason = 'bad-txns-fee-outofrange'; ret.score = 100; return false; @@ -1392,7 +1392,7 @@ TX.prototype.getPriority = function getPriority(height, size) { var sum, i, input, age, value; if (this.isCoinbase()) - return new bn(0); + return 0; if (height == null) { height = this.height; @@ -1403,8 +1403,8 @@ TX.prototype.getPriority = function getPriority(height, size) { if (size == null) size = this.maxSize(); - sum = new bn(0); - value = new bn(0); + sum = 0; + value = 0; for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; @@ -1417,14 +1417,14 @@ TX.prototype.getPriority = function getPriority(height, size) { if (input.coin.height <= height) { age = height - input.coin.height; - value.iadd(input.coin.value); - sum.iadd(input.coin.value.muln(age)); + value += input.coin.value; + sum += input.coin.value * age; } } return { value: value, - priority: sum.divn(size) + priority: sum / size }; }; @@ -1451,7 +1451,7 @@ TX.prototype.isFree = function isFree(height, size) { priority = this.getPriority(height, size).priority; - return priority.cmp(constants.tx.FREE_THRESHOLD) > 0; + return priority > constants.tx.FREE_THRESHOLD; }; /** @@ -1483,10 +1483,10 @@ TX.getMinFee = function getMinFee(size, rate) { if (rate == null) rate = constants.tx.MIN_RELAY; - fee = new bn(rate).muln(size).divn(1000); + fee = Math.floor(rate * size / 1000); - if (fee.cmpn(0) === 0 && rate > 0) - fee = new bn(rate); + if (fee === 0 && rate > 0) + fee = rate; return fee; }; @@ -1510,10 +1510,10 @@ TX.prototype.getMaxFee = function getMaxFee(size, rate) { if (rate == null) rate = constants.tx.MIN_RELAY; - fee = new bn(rate).muln(Math.ceil(size / 1000)); + fee = rate * Math.ceil(size / 1000); - if (fee.cmpn(0) === 0 && rate > 0) - fee = new bn(rate); + if (fee === 0 && rate > 0) + fee = rate; return fee; }; diff --git a/lib/bcoin/txdb.js b/lib/bcoin/txdb.js index 5ca0af3e..8cb5a6ec 100644 --- a/lib/bcoin/txdb.js +++ b/lib/bcoin/txdb.js @@ -1609,8 +1609,8 @@ TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) { */ TXDB.prototype.getBalance = function getBalance(address, callback) { - var confirmed = new bn(0); - var unconfirmed = new bn(0); + var confirmed = 0; + var unconfirmed = 0; var i; if (typeof address === 'function') { @@ -1624,15 +1624,15 @@ TXDB.prototype.getBalance = function getBalance(address, callback) { for (i = 0; i < coins.length; i++) { if (coins[i].height === -1) - unconfirmed.iadd(coins[i].value); + unconfirmed += coins[i].value; else - confirmed.iadd(coins[i].value); + confirmed += coins[i].value; } return callback(null, { confirmed: confirmed, unconfirmed: unconfirmed, - total: confirmed.add(unconfirmed) + total: confirmed + unconfirmed }); }); }; diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index d8bb5f6d..1606386c 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -638,7 +638,7 @@ utils.assert.fatal = function fatal(value, message) { * @default */ -utils.COIN = new bn(10000000).muln(10); +utils.COIN = 100000000; /** * Convert satoshis to a BTC string. Note that @@ -656,16 +656,13 @@ utils.btc = function btc(satoshi) { assert(utils.isSatoshi(satoshi), 'Non-satoshi value for conversion.'); - if (satoshi.isNeg()) { - satoshi = satoshi.neg(); + if (satoshi < 0) { + satoshi = -satoshi; neg = true; } - hi = satoshi.div(utils.COIN).toString(10); - - lo = satoshi.mod(utils.COIN); - - lo = lo.toString(10); + hi = Math.floor(satoshi / utils.COIN).toString(10); + lo = (satoshi % utils.COIN).toString(10); while (lo.length < 8) lo = '0' + lo; @@ -711,12 +708,14 @@ utils.satoshi = function satoshi(btc) { while (lo.length < 8) lo += '0'; + assert(lo.length === 8); + satoshi = (hi + lo).replace(/^0+/, ''); - satoshi = new bn(satoshi, 10); + satoshi = parseInt(satoshi, 10); if (neg) - satoshi.ineg(); + satoshi = -satoshi; return satoshi; }; @@ -738,7 +737,7 @@ utils.isNumber = function isNumber(val) { */ utils.isSatoshi = function isSatoshi(val) { - return bn.isBN(val); + return utils.isNumber(val) && val % 1 === 0; }; /** @@ -1733,20 +1732,54 @@ utils.readU64NBE = function readU64NBE(data, off, force53) { */ utils.read64N = function read64N(data, off, force53) { + var hi, lo, result, one, b, v; + off = off >>> 0; - var hi = utils.readU32(data, off + 4); - var lo = utils.readU32(data, off); - if (hi & 0x80000000) { - hi = ~hi + 1; - lo = ~lo + 1; - if (force53) - hi &= utils.MAX_SAFE_HI; - assert(hi <= utils.MAX_SAFE_HI, 'Number exceeds 2^53-1'); - return -(hi * 0x100000000 + lo); + + if (data[off + 7] & 0x80) { + result = 0; + one = 1; + + for (i = 0; i < 8; i++) { + b = (data[i + off] ^ 0xff) + one; + v = b & 0xff; + + // We can't have any bits in the msb. + if (i === 7 && v !== 0) { + assert(force53, 'Number exceeds 2^53-1'); + v = 0; + } + + // We can only have 5 bits in the second msb. + if (i === 6 && v > 0x1f) { + assert(force53, 'Number exceeds 2^53-1'); + v &= 0x1f; + } + + // We need to shift left by `i` bytes, + // but we can't because this will + // exceed 32 bits. So we multiply by + // `Math.pow(2, shiftBits)` instead. + // Equivalent to `v <<= 8 * i`. + v *= Math.pow(2, 8 * i); + + // We can't OR so we add. + result += v; + + one = b >>> 8; + } + + return -result; } + + hi = utils.readU32(data, off + 4); + lo = utils.readU32(data, off); + if (force53) hi &= utils.MAX_SAFE_HI; + assert(hi <= utils.MAX_SAFE_HI, 'Number exceeds 2^53-1'); + return (hi * 0x100000000) + lo; }; @@ -1760,20 +1793,54 @@ utils.read64N = function read64N(data, off, force53) { */ utils.read64NBE = function read64NBE(data, off, force53) { + var hi, lo, result, one, b, v; + off = off >>> 0; - var hi = utils.readU32BE(data, off); - var lo = utils.readU32BE(data, off + 4); - if (hi & 0x80000000) { - hi = ~hi + 1; - lo = ~lo + 1; - if (force53) - hi &= utils.MAX_SAFE_HI; - assert(hi <= utils.MAX_SAFE_HI, 'Number exceeds 2^53-1'); - return -(hi * 0x100000000 + lo); + + if (data[off] & 0x80) { + result = 0; + one = 1; + + for (i = 7; i >= 0; i--) { + b = (data[i + off] ^ 0xff) + one; + v = b & 0xff; + + // We can't have any bits on the msb. + if (i === 0 && v !== 0) { + assert(force53, 'Number exceeds 2^53-1'); + v = 0; + } + + // We can only have 5 bits on the second msb. + if (i === 1 && v > 0x1f) { + assert(force53, 'Number exceeds 2^53-1'); + v &= 0x1f; + } + + // We need to shift left by `7 - i` bytes, + // but we can't because this will exceed + // 32 bits. So we multiply by + // `Math.pow(2, shiftBits)` instead. + // Equivalent to `v <<= 8 * (7 - i)`. + v *= Math.pow(2, 8 * (7 - i)); + + // We can't OR so we add. + result += v; + + one = b >>> 8; + } + + return -result; } + + hi = utils.readU32(data, off); + lo = utils.readU32(data, off + 4); + if (force53) hi &= utils.MAX_SAFE_HI; + assert(hi <= utils.MAX_SAFE_HI, 'Number exceeds 2^53-1'); + return (hi * 0x100000000) + lo; }; diff --git a/test/mempool-test.js b/test/mempool-test.js index f4b01fea..afa2cdb4 100644 --- a/test/mempool-test.js +++ b/test/mempool-test.js @@ -39,7 +39,7 @@ describe('Mempool', function() { coin: { version: 1, height: 0, - value: new bn(70000), + value: 70000, script: prev, coinbase: false, hash: constants.ONE_HASH.toString('hex'), diff --git a/test/script-test.js b/test/script-test.js index 520ad45a..3f46a091 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -302,7 +302,7 @@ describe('Script', function() { }], outputs: [{ script: output, - value: new bn(0) + value: 0 }], locktime: 0 }); @@ -320,7 +320,7 @@ describe('Script', function() { }], outputs: [{ script: new bcoin.script(), - value: new bn(0) + value: 0 }], locktime: 0 }); diff --git a/test/tx-test.js b/test/tx-test.js index 6958971f..3a4c2b5f 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -161,7 +161,7 @@ describe('TX', function() { hash: utils.revHex(hash), index: index, script: script, - value: value != null ? new bn(value) : new bn(0) + value: value != null ? parseInt(value, 10) : 0 }); tx.fillCoins(coin); }); diff --git a/test/utils-test.js b/test/utils-test.js index 1b0673a0..5a22c06a 100644 --- a/test/utils-test.js +++ b/test/utils-test.js @@ -22,20 +22,20 @@ describe('Utils', function() { }); it('should convert satoshi to btc', function() { - var btc = utils.btc(new bn(5460)); + var btc = utils.btc(5460); assert.equal(btc, '0.0000546'); - btc = utils.btc(new bn(54678).mul(new bn(1000000))); + btc = utils.btc(54678 * 1000000); assert.equal(btc, '546.78'); - btc = utils.btc(new bn(5460).mul(new bn(10000000))); + btc = utils.btc(5460 * 10000000); assert.equal(btc, '546.0'); }); it('should convert btc to satoshi', function() { var btc = utils.satoshi('0.0000546'); - assert(btc.cmp(new bn(5460)) === 0); + assert(btc === 5460); btc = utils.satoshi('546.78'); - assert(btc.cmp(new bn(54678).mul(new bn(1000000))) === 0); + assert(btc === 54678 * 1000000); btc = utils.satoshi('546.0'); - assert(btc.cmp(new bn(5460).mul(new bn(10000000))) === 0); + assert(btc === 5460 * 10000000); }); }); diff --git a/test/wallet-test.js b/test/wallet-test.js index 80e6b61f..56711853 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -13,7 +13,7 @@ var dummyInput = { coin: { version: 1, height: 0, - value: constants.MAX_MONEY.clone(), + value: constants.MAX_MONEY, script: new bcoin.script([]), coinbase: false, hash: constants.NULL_HASH, @@ -342,7 +342,7 @@ describe('Wallet', function() { tx.addOutput(to, 5460); var cost = tx.getOutputValue(); - var total = cost.add(new bn(constants.tx.MIN_FEE)); + var total = cost * constants.tx.MIN_FEE; w1.getCoins(function(err, coins1) { assert.ifError(err); @@ -350,19 +350,19 @@ describe('Wallet', function() { assert.ifError(err); // Add dummy output (for `left`) to calculate maximum TX size - tx.addOutput(w1, new bn(0)); + tx.addOutput(w1, 0); // Add our unspent inputs to sign tx.addInput(coins1[0]); tx.addInput(coins1[1]); tx.addInput(coins2[0]); - var left = tx.getInputValue().sub(total); - if (left.cmpn(constants.tx.DUST_THRESHOLD) < 0) { - tx.outputs[tx.outputs.length - 2].value.iadd(left); - left = new bn(0); + var left = tx.getInputValue() - total; + if (left < constants.tx.DUST_THRESHOLD) { + tx.outputs[tx.outputs.length - 2].value += left; + left = 0; } - if (left.cmpn(0) === 0) + if (left === 0) tx.outputs.pop(); else tx.outputs[tx.outputs.length - 1].value = left; @@ -527,7 +527,7 @@ describe('Wallet', function() { send.inputs[0].script.code[2] = 0; assert(!send.verify(null, true, flags)); - assert.equal(send.getFee().toNumber(), 10000); + assert.equal(send.getFee(), 10000); w3 = bcoin.wallet.fromJSON(w3.toJSON()); assert.equal(w3.receiveDepth, 2);