diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 109944c..8fc6cf8 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -384,9 +384,6 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { if (!allowIncomplete) { if (!this.tx.ins.length) throw new Error('Transaction has no inputs') if (!this.tx.outs.length) throw new Error('Transaction has no outputs') - - // do not rely on this, its merely a last resort - if (this.__hasAbsurdFee()) throw new Error('Transaction has absurd fees') } var tx = this.tx.clone() @@ -408,6 +405,13 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { tx.setInputScript(i, scriptSig) }) + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__hasAbsurdFeeRate(tx.byteLength())) { + throw new Error('Transaction has absurd fees') + } + } + return tx } @@ -499,7 +503,7 @@ TransactionBuilder.prototype.__canModifyOutputs = function () { }) } -TransactionBuilder.prototype.__hasAbsurdFee = function () { +TransactionBuilder.prototype.__hasAbsurdFeeRate = function (bytes) { // not all inputs will have .value defined var incoming = this.inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0) @@ -507,10 +511,9 @@ TransactionBuilder.prototype.__hasAbsurdFee = function () { // we can immediately determine if the outputs are too small var outgoing = this.tx.outs.reduce(function (a, x) { return a + x.value }, 0) var fee = incoming - outgoing + var feeRate = fee / bytes - // its not fool-proof, but, it might help somebody - // fee > 0.2BTC - return fee > (0.2 * 1e8) + return feeRate > 1000 } module.exports = TransactionBuilder diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 65402e6..f227041 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -666,14 +666,28 @@ "exception": "Transaction has absurd fees", "inputs": [ { - "txHex": "01000000000100e1f505000000000000000000", - "vout": 0 + "txRaw": { + "inputs": [], + "outputs": [ + { + "address": "1C5XhB1UkFuyCV1CG9dmXaXGu3xDL4nAjv", + "value": 1000000000 + } + ], + "incomplete": true + }, + "vout": 0, + "signs": [ + { + "keyPair": "KzBQVXYUGDAvqG7VeU3C7ZMRYiwtsxSVVFcYGzKU9E4aUVDUquZU" + } + ] } ], "outputs": [ { "script": "OP_DUP OP_HASH160 ff99e06c1a4ac394b4e1cb3d3a4b2b47749e339a OP_EQUALVERIFY OP_CHECKSIG", - "value": 100000 + "value": 200000 } ] }, diff --git a/test/transaction_builder.js b/test/transaction_builder.js index b370b06..25641f0 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -21,17 +21,31 @@ function construct (f, sign) { if (f.locktime !== undefined) txb.setLockTime(f.locktime) f.inputs.forEach(function (input) { - var prevTxScript + var prevTx + if (input.txRaw) { + var constructed = construct(input.txRaw) + if (input.txRaw.incomplete) prevTx = constructed.buildIncomplete() + else prevTx = constructed.build() + } else if (input.txHex) { + prevTx = Transaction.fromHex(input.txHex) + } else { + prevTx = input.txId + } - if (!input.txHex && input.prevTxScript) { + var prevTxScript + if (input.prevTxScript) { prevTxScript = bscript.fromASM(input.prevTxScript) } - txb.addInput(input.txId || Transaction.fromHex(input.txHex), input.vout, input.sequence, prevTxScript) + txb.addInput(prevTx, input.vout, input.sequence, prevTxScript) }) f.outputs.forEach(function (output) { - txb.addOutput(bscript.fromASM(output.script), output.value) + if (output.address) { + txb.addOutput(output.address, output.value) + } else { + txb.addOutput(bscript.fromASM(output.script), output.value) + } }) if (sign === false) return txb