coinselect
Advanced tools
Comparing version 3.0.5 to 3.1.0
45
accum.js
@@ -1,45 +0,28 @@ | ||
let utils = require('./utils') | ||
var utils = require('./utils') | ||
// O(n) | ||
module.exports = function accumulative (utxos, outputs, feeRate) { | ||
let outAccum = outputs.reduce((a, x) => a + x.value, 0) | ||
let inAccum = 0 | ||
let bytesAccum = utils.transactionBytes([], outputs) | ||
var outAccum = utils.sum(outputs) | ||
// accumulate inputs | ||
let inputs = [] | ||
// accumulators | ||
var bytesAccum = utils.transactionBytes([], outputs) | ||
var inAccum = 0 | ||
var inputs = [] | ||
for (let i = 0; i < utxos.length; ++i) { | ||
const utxo = utxos[i] | ||
for (var i = 0; i < utxos.length; ++i) { | ||
var utxo = utxos[i] | ||
bytesAccum += utils.inputBytes(utxo) | ||
inAccum += utxo.value | ||
bytesAccum += utils.inputBytes(utxo) | ||
inputs.push(utxo) | ||
const feeWanted = feeRate * bytesAccum | ||
if (inAccum >= outAccum + feeWanted) break | ||
} | ||
var fee = feeRate * bytesAccum | ||
// did we bust? | ||
const feeAccum = feeRate * bytesAccum | ||
if (inAccum < outAccum + feeAccum) return { fee: feeAccum } | ||
// go again? | ||
if (inAccum < outAccum + fee) continue | ||
// is it worth an extra output [for change]? | ||
{ | ||
const bytesExtra = utils.outputBytes({}) | ||
const feeExtra = feeRate * (bytesAccum + bytesExtra) | ||
const valueExtra = inAccum - outAccum - feeExtra | ||
if (valueExtra > utils.dustThreshold({}, feeRate)) { | ||
outAccum += valueExtra | ||
outputs = outputs.concat({ value: valueExtra }) | ||
const fee = inAccum - outAccum | ||
return { inputs, outputs, fee } | ||
} | ||
return utils.finalize(inputs, outputs, feeRate) | ||
} | ||
// ignore it | ||
const fee = inAccum - outAccum | ||
return { inputs, outputs, fee } | ||
return { fee: feeRate * bytesAccum } | ||
} |
@@ -1,36 +0,32 @@ | ||
let utils = require('./utils') | ||
var utils = require('./utils') | ||
// O(n * n) | ||
module.exports = function blackjack (utxos, outputs, feeRate) { | ||
const outAccum = outputs.reduce((a, x) => a + x.value, 0) | ||
const threshold = utils.dustThreshold({}, feeRate) | ||
var outAccum = utils.sum(outputs) | ||
var threshold = utils.dustThreshold({}, feeRate) | ||
let inAccum = 0 | ||
let bytesAccum = utils.transactionBytes([], outputs) | ||
// accumulate inputs until we bust | ||
let inputs = [] | ||
var inAccum = 0 | ||
var bytesAccum = utils.transactionBytes([], outputs) | ||
var inputs = [] | ||
for (let i = 0; i < utxos.length; ++i) { | ||
const utxo = utxos[i] | ||
const bytesAfter = utils.inputBytes(utxo) | ||
const feeAfter = feeRate * (bytesAccum + bytesAfter) | ||
for (var i = 0; i < utxos.length; ++i) { | ||
var input = utxos[i] | ||
var inputBytes = utils.inputBytes(input) | ||
var fee = feeRate * (bytesAccum + inputBytes) | ||
// are we wasting value? | ||
if (inAccum + utxo.value > outAccum + feeAfter + threshold) continue | ||
// would it waste value? | ||
if ((inAccum + input.value) > (outAccum + fee + threshold)) continue | ||
inAccum += utxo.value | ||
bytesAccum += bytesAfter | ||
inputs.push(utxo) | ||
bytesAccum += inputBytes | ||
inAccum += input.value | ||
inputs.push(input) | ||
// go again? | ||
if (inAccum < outAccum + feeAfter) continue | ||
if (inAccum < outAccum + fee) continue | ||
const fee = inAccum - outAccum | ||
return { inputs, outputs, fee } | ||
return utils.finalize(inputs, outputs, feeRate) | ||
} | ||
return { | ||
fee: feeRate * utils.transactionBytes(inputs, outputs) | ||
} | ||
return { fee: feeRate * bytesAccum } | ||
} |
20
index.js
@@ -1,12 +0,12 @@ | ||
let accumulative = require('./accum') | ||
let blackjack = require('./blackjack') | ||
var accumulative = require('./accum') | ||
var blackjack = require('./blackjack') | ||
// TODO | ||
// function groupByRelation (utxos) { | ||
// let txoMap = {} | ||
// let result = [] | ||
// var txoMap = {} | ||
// var result = [] | ||
// | ||
// // group by address/script | ||
// utxos.forEach((utxo) => { | ||
// let key = utxo.address || utxo.script | ||
// var key = utxo.address || utxo.script | ||
// | ||
@@ -21,4 +21,4 @@ // // no relation known, use as is | ||
// | ||
// for (let key in txoMap) { | ||
// let group = txoMap[key] | ||
// for (var key in txoMap) { | ||
// var group = txoMap[key] | ||
// | ||
@@ -35,6 +35,8 @@ // // summate 'grouping' value | ||
// order by descending value | ||
utxos = utxos.concat().sort((a, b) => b.value - a.value) | ||
utxos = utxos.concat().sort(function (a, b) { | ||
return b.value - a.value | ||
}) | ||
// attempt to use the blackjack strategy first (no change output) | ||
let base = blackjack(utxos, outputs, feeRate) | ||
var base = blackjack(utxos, outputs, feeRate) | ||
if (base.inputs) return base | ||
@@ -41,0 +43,0 @@ |
{ | ||
"name": "coinselect", | ||
"version": "3.0.5", | ||
"version": "3.1.0", | ||
"description": "A transaction input selection module for bitcoin.", | ||
@@ -28,3 +28,5 @@ "keywords": [ | ||
"blackjack.js", | ||
"broken.js", | ||
"index.js", | ||
"split.js", | ||
"utils.js" | ||
@@ -40,4 +42,4 @@ ], | ||
"coverage": "nyc --check-coverage --branches 100 --functions 100 tape test/*.js", | ||
"lint": "standard", | ||
"test": "npm run lint && npm run unit", | ||
"standard": "standard", | ||
"test": "npm run standard && npm run unit", | ||
"unit": "tape test/*.js" | ||
@@ -44,0 +46,0 @@ }, |
# coinselect | ||
[![TRAVIS](https://secure.travis-ci.org/dcousens/coinselect.png)](http://travis-ci.org/dcousens/coinselect) | ||
[![TRAVIS](https://secure.travis-ci.org/bitcoinjs/coinselect.png)](http://travis-ci.org/bitcoinjs/coinselect) | ||
[![NPM](http://img.shields.io/npm/v/coinselect.svg)](https://www.npmjs.org/package/coinselect) | ||
@@ -5,0 +5,0 @@ |
54
utils.js
// baseline estimates, used to improve performance | ||
const TX_EMPTY_SIZE = 4 + 1 + 1 + 4 | ||
const TX_INPUT_BASE = 32 + 4 + 1 + 4 | ||
const TX_INPUT_PUBKEYHASH = 106 | ||
const TX_OUTPUT_BASE = 8 + 1 | ||
const TX_OUTPUT_PUBKEYHASH = 25 | ||
var TX_EMPTY_SIZE = 4 + 1 + 1 + 4 | ||
var TX_INPUT_BASE = 32 + 4 + 1 + 4 | ||
var TX_INPUT_PUBKEYHASH = 106 | ||
var TX_OUTPUT_BASE = 8 + 1 | ||
var TX_OUTPUT_PUBKEYHASH = 25 | ||
@@ -17,3 +17,4 @@ function inputBytes () { | ||
function dustThreshold (output, feeRate) { | ||
return 3 * (outputBytes(output) * feeRate) | ||
/* ... classify the output for input estimate */ | ||
return inputBytes() * feeRate | ||
} | ||
@@ -23,11 +24,40 @@ | ||
return TX_EMPTY_SIZE + | ||
inputs.reduce((a, x) => a + inputBytes(x), 0) + | ||
outputs.reduce((a, x) => a + outputBytes(x), 0) | ||
inputs.reduce(function (a, x) { return a + inputBytes(x) }, 0) + | ||
outputs.reduce(function (a, x) { return a + outputBytes(x) }, 0) | ||
} | ||
function sum (range) { | ||
return range.reduce(function (a, x) { return a + (x.value >>> 0) }, 0) | ||
} | ||
var BLANK_OUTPUT = outputBytes({}) | ||
function worthChange (inputs, outputs, feeRate) { | ||
var bytesAccum = transactionBytes(inputs, outputs) | ||
var fee = feeRate * (bytesAccum + BLANK_OUTPUT) | ||
var remainder = sum(inputs) - (sum(outputs) + fee) | ||
if (remainder <= dustThreshold({}, feeRate)) return null | ||
return { value: remainder } | ||
} | ||
function finalize (inputs, outputs, feeRate) { | ||
// was too much left over? | ||
var change = worthChange(inputs, outputs, feeRate) | ||
if (change) outputs = outputs.concat(change) | ||
return { | ||
inputs: inputs, | ||
outputs: outputs, | ||
fee: sum(inputs) - sum(outputs) | ||
} | ||
} | ||
module.exports = { | ||
dustThreshold, | ||
inputBytes, | ||
outputBytes, | ||
transactionBytes | ||
dustThreshold: dustThreshold, | ||
finalize: finalize, | ||
inputBytes: inputBytes, | ||
outputBytes: outputBytes, | ||
sum: sum, | ||
transactionBytes: transactionBytes | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9548
9
181
1