Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support BigNumber #1

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
coverage
.nyc_output
node_modules
.vscode/
32 changes: 21 additions & 11 deletions accumulative.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
var utils = require('./utils')
var ext = require('./bn-extensions')

// add inputs until we reach or surpass the target value (or deplete)
// worst-case: O(n)
module.exports = function accumulative (utxos, outputs, feeRate) {
if (!isFinite(utils.uintOrNaN(feeRate))) return {}
if (!isFinite(utils.bnOrNaN(feeRate))) return {}
var bytesAccum = utils.transactionBytes([], outputs)

var inAccum = 0
var inAccum = ext.BN_ZERO
var inputs = []
var outAccum = utils.sumOrNaN(outputs)

for (var i = 0; i < utxos.length; ++i) {
var utxo = utxos[i]
var utxoBytes = utils.inputBytes(utxo)
var utxoFee = feeRate * utxoBytes
var utxoValue = utils.uintOrNaN(utxo.value)
var utxoFee = ext.mul(feeRate, utxoBytes)
var utxoValue = utils.bnOrNaN(utxo.value)

// skip detrimental input
if (utxoFee > utxo.value) {
if (i === utxos.length - 1) return { fee: feeRate * (bytesAccum + utxoBytes) }
var feeIsMoreThanValue = ext.gt(utxoFee, utxoValue)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1

// utxoFee > utxoValue
if (feeIsMoreThanValue) {
if (i === utxos.length - 1) {
var bytesSum = ext.add(bytesAccum, utxoBytes)
return {
fee: ext.mul(feeRate, bytesSum)
}
}
continue
}

bytesAccum += utxoBytes
inAccum += utxoValue
bytesAccum = ext.add(bytesAccum, utxoBytes)
inAccum = ext.add(inAccum, utxoValue)
inputs.push(utxo)

var fee = feeRate * bytesAccum
var fee = ext.mul(feeRate, bytesAccum)

// go again?
if (inAccum < outAccum + fee) continue
if (ext.lt(inAccum, ext.add(outAccum, fee))) continue

return utils.finalize(inputs, outputs, feeRate)
}

return { fee: feeRate * bytesAccum }
return {
fee: feeRate.mul(bytesAccum)
}
}
27 changes: 17 additions & 10 deletions blackjack.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
var utils = require('./utils')
var ext = require('./bn-extensions')

// only add inputs if they don't bust the target value (aka, exact match)
// worst-case: O(n)
module.exports = function blackjack (utxos, outputs, feeRate) {
if (!isFinite(utils.uintOrNaN(feeRate))) return {}
if (!isFinite(utils.bnOrNaN(feeRate))) return {}

var bytesAccum = utils.transactionBytes([], outputs)

var inAccum = 0
var inAccum = ext.BN_ZERO
var inputs = []
var outAccum = utils.sumOrNaN(outputs)
var threshold = utils.dustThreshold({}, feeRate)

for (var i = 0; i < utxos.length; ++i) {
var input = utxos[i]
var inputBytes = utils.inputBytes(input)
var fee = feeRate * (bytesAccum + inputBytes)
var inputValue = utils.uintOrNaN(input.value)
var fee = ext.mul(feeRate, ext.add(bytesAccum, inputBytes))
var inputValue = utils.bnOrNaN(input.value)

// would it waste value?
if ((inAccum + inputValue) > (outAccum + fee + threshold)) continue
var totalInputs = ext.add(inAccum, inputValue)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2

var outputsAndFee = ext.add(outAccum, fee)
var totalOutputs = ext.add(outputsAndFee, threshold)
var inputsAreGreaterThanOutputs = ext.gt(totalInputs, totalOutputs)

bytesAccum += inputBytes
inAccum += inputValue
if (inputsAreGreaterThanOutputs) continue

bytesAccum = ext.add(bytesAccum, inputBytes)
inAccum = ext.add(inAccum, inputValue)
inputs.push(input)

// go again?
if (inAccum < outAccum + fee) continue
if (ext.lt(inAccum, outputsAndFee)) continue

return utils.finalize(inputs, outputs, feeRate)
}

return { fee: feeRate * bytesAccum }
return {
fee: feeRate.mul(bytesAccum)
}
}
74 changes: 74 additions & 0 deletions bn-extensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
var BN = require('bn.js')

var BN_ZERO = new BN(0)
var BN_ONE = new BN(1)

function mul (multiplicand, multiplier) {
if (!BN.isBN(multiplicand) || !BN.isBN(multiplier)) return NaN

return multiplicand.mul(multiplier)
}

function div (dividend, divisor) {
if (!BN.isBN(dividend) || !BN.isBN(divisor)) return NaN
if (divisor.cmp(BN_ZERO) === 0) return Infinity

return dividend.div(divisor)
}

function add (arg1, arg2, arg3) {
// Add two items
if (!BN.isBN(arg1) || !BN.isBN(arg2)) return NaN
if (typeof arg3 === 'undefined') return arg1.add(arg2)

// Add three items
if (!BN.isBN(arg3)) return NaN
return arg1.add(arg2).add(arg3)
}

function sub (arg1, arg2, arg3) {
// Subtract two items
if (!BN.isBN(arg1) || !BN.isBN(arg2)) return NaN
if (typeof arg3 === 'undefined') return arg1.sub(arg2)

// Subtract three items
if (!BN.isBN(arg3)) return NaN
return arg1.sub(arg2).sub(arg3)
}

function shrn (argument, shiftBy) {
if (!BN.isBN(argument)) return NaN
if (BN.isBN(shiftBy)) shiftBy = shiftBy.toNumber()
if (typeof shiftBy !== 'number') return NaN

return argument.shrn(shiftBy)
}

function isZero (argument) {
if (!BN.isBN(argument)) return false
if (argument.cmp(BN_ZERO) === 0) return true
return false
}

function lt (subject, argument) {
if (!BN.isBN(argument) || !BN.isBN(subject)) return false
return subject.lt(argument)
}

function gt (subject, argument) {
if (!BN.isBN(argument) || !BN.isBN(subject)) return false
return subject.gt(argument)
}

module.exports = {
mul: mul,
div: div,
add: add,
sub: sub,
shrn: shrn,
isZero: isZero,
lt: lt,
gt: gt,
BN_ZERO: BN_ZERO,
BN_ONE: BN_ONE
}
27 changes: 17 additions & 10 deletions break.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
var utils = require('./utils')
var ext = require('./bn-extensions')

// break utxos into the maximum number of 'output' possible
module.exports = function broken (utxos, output, feeRate) {
if (!isFinite(utils.uintOrNaN(feeRate))) return {}
if (!isFinite(utils.bnOrNaN(feeRate))) return {}

var bytesAccum = utils.transactionBytes(utxos, [])
var value = utils.uintOrNaN(output.value)
var value = utils.bnOrNaN(output.value)
var inAccum = utils.sumOrNaN(utxos)

if (!isFinite(value) ||
!isFinite(inAccum)) return { fee: feeRate * bytesAccum }
!isFinite(inAccum)) return { fee: feeRate.mul(bytesAccum) }

var outputBytes = utils.outputBytes(output)
var outAccum = 0
var outAccum = ext.BN_ZERO
var outputs = []

while (true) {
var fee = feeRate * (bytesAccum + outputBytes)
// feeRate * (bytesAccum + outputBytes)
var fee = ext.mul(feeRate, ext.add(bytesAccum, outputBytes))

// did we bust?
if (inAccum < (outAccum + fee + value)) {
if (ext.lt(inAccum, ext.add(outAccum, fee, value))) {
var isZero = ext.isZero(outAccum)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3

// premature?
if (outAccum === 0) return { fee: fee }

if (isZero) {
return {
fee: fee
}
}
break
}

bytesAccum += outputBytes
outAccum += value
bytesAccum = ext.add(bytesAccum, outputBytes)
outAccum = ext.add(outAccum, value)
outputs.push(output)
}

Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ var utils = require('./utils')

// order by descending value, minus the inputs approximate fee
function utxoScore (x, feeRate) {
return x.value - (feeRate * utils.inputBytes(x))
return x.value.sub((feeRate.mul(utils.inputBytes(x))))
}

module.exports = function coinSelect (utxos, outputs, feeRate) {
utxos = utxos.concat().sort(function (a, b) {
return utxoScore(b, feeRate) - utxoScore(a, feeRate)
return utxoScore(b, feeRate).sub(utxoScore(a, feeRate))
})

// attempt to use the blackjack strategy first (no change output)
Expand Down
Loading