From bd97f20f1c851f9eabf7f042e6b735b659600703 Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 4 Feb 2015 12:10:47 -0300 Subject: [PATCH 1/4] Use addInput in _fromNonP2SH --- lib/transaction/transaction.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 45ed523..158627c 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -353,8 +353,14 @@ Transaction.prototype.from = function(utxo, pubkeys, threshold) { }; Transaction.prototype._fromNonP2SH = function(utxo) { + var clazz; utxo = new UnspentOutput(utxo); - this.inputs.push(new PublicKeyHashInput({ + if (utxo.script.isPublicKeyHashOut()) { + clazz = PublicKeyHashInput; + } else { + clazz = Input; + } + this.addInput(new clazz({ output: new Output({ script: utxo.script, satoshis: utxo.satoshis @@ -364,7 +370,6 @@ Transaction.prototype._fromNonP2SH = function(utxo) { sequenceNumber: DEFAULT_SEQNUMBER, script: Script.empty() })); - this._inputAmount += utxo.satoshis; }; Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { From ed393dcb9117ef680b32d732cbc6e34f107d9a5d Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 4 Feb 2015 12:15:43 -0300 Subject: [PATCH 2/4] Update change on each output or input change --- lib/transaction/transaction.js | 23 ++++++++++------------- test/transaction/transaction.js | 3 ++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 158627c..02b6276 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -421,11 +421,11 @@ Transaction.prototype.addInput = function(input, outputScript, satoshis) { */ Transaction.prototype.uncheckedAddInput = function(input) { $.checkArgumentType(input, Input, 'input'); - this._changeSetup = false; this.inputs.push(input); if (input.output) { this._inputAmount += input.output.satoshis; } + this._updateChangeOutput(); return this; }; @@ -450,7 +450,7 @@ Transaction.prototype.hasAllUtxoInfo = function() { */ Transaction.prototype.fee = function(amount) { this._fee = amount; - this._changeSetup = false; + this._updateChangeOutput(); return this; }; @@ -467,7 +467,7 @@ Transaction.prototype.fee = function(amount) { */ Transaction.prototype.change = function(address) { this._change = new Address(address); - this._changeSetup = false; + this._updateChangeOutput(); return this; }; @@ -509,8 +509,12 @@ Transaction.prototype.addData = function(value) { Transaction.prototype.addOutput = function(output) { $.checkArgumentType(output, Output, 'output'); + this._addOutput(output); + this._updateChangeOutput(); +}; + +Transaction.prototype._addOutput = function(output) { this.outputs.push(output); - this._changeSetup = false; this._outputAmount += output.satoshis; }; @@ -518,12 +522,7 @@ Transaction.prototype._updateChangeOutput = function() { if (!this._change) { return; } - if (this._changeSetup) { - return; - } - if (!_.isUndefined(this._changeSetup)) { - this._clearSignatures(); - } + this._clearSignatures(); if (!_.isUndefined(this._changeOutput)) { this.removeOutput(this._changeOutput); } @@ -531,14 +530,13 @@ Transaction.prototype._updateChangeOutput = function() { var fee = this.getFee(); if (available - fee > 0) { this._changeOutput = this.outputs.length; - this.addOutput(new Output({ + this._addOutput(new Output({ script: Script.fromAddress(this._change), satoshis: available - fee })); } else { this._changeOutput = undefined; } - this._changeSetup = true; }; Transaction.prototype.getFee = function() { @@ -606,7 +604,6 @@ Transaction.prototype.removeOutput = function(index) { */ Transaction.prototype.sign = function(privateKey, sigtype) { $.checkState(this.hasAllUtxoInfo()); - this._updateChangeOutput(); var self = this; if (_.isArray(privateKey)) { _.each(privateKey, function(privateKey) { diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index cb8938c..3460712 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -260,7 +260,8 @@ describe('Transaction', function() { var transaction = new Transaction() .from(simpleUtxoWith1BTC) .change(changeAddress) - .to(toAddress, 1); + .fee(50000000) + .to(toAddress, 40000000); expect(function() { return transaction.serialize(); }).to.throw(errors.Transaction.FeeError); From 1f45e882686b3355464490b0837908ff480ec38c Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 4 Feb 2015 12:45:02 -0300 Subject: [PATCH 3/4] Add fee to serialization --- lib/transaction/transaction.js | 4 ++++ test/transaction/transaction.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 02b6276..33b00ed 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -239,6 +239,7 @@ Transaction.prototype.toObject = function toObject() { }); return { change: this._change ? this._change.toString() : undefined, + fee: this._fee ? this._fee : undefined, version: this.version, inputs: inputs, outputs: outputs, @@ -269,6 +270,9 @@ Transaction.prototype.fromObject = function(transaction) { if (transaction.change) { this.change(transaction.change); } + if (transaction.fee) { + this.fee(transaction.fee); + } this.nLockTime = transaction.nLockTime; this.version = transaction.version; }; diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index 3460712..c0ff98d 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -245,6 +245,14 @@ describe('Transaction', function() { return transaction.serialize(true); }).to.not.throw(); }); + it('stores the fee set by the user', function() { + var fee = 1000000; + var serialized = new Transaction() + .fee(fee) + .toObject(); + var deserialized = new Transaction(serialized); + expect(deserialized._fee).to.equal(fee); + }); }); describe('checked serialize', function() { From e568a8786cdfccaf403b45fb45e7e2ae53769fe7 Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 4 Feb 2015 13:15:06 -0300 Subject: [PATCH 4/4] Transaction: Fix wrong logic on input addition --- lib/transaction/transaction.js | 4 ++-- test/transaction/transaction.js | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 33b00ed..e800ed8 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -402,10 +402,10 @@ Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { */ Transaction.prototype.addInput = function(input, outputScript, satoshis) { $.checkArgumentType(input, Input, 'input'); - if (!input.output || !(input.output instanceof Output) && !outputScript && !satoshis) { + if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(satoshis))) { throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and satoshis'); } - if (!input.output && outputScript && satoshis) { + if (!input.output && outputScript && !_.isUndefined(satoshis)) { outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript); $.checkArgumentType(satoshis, 'number', 'satoshis'); input.output = new Output({ diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index c0ff98d..80d89e1 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -329,6 +329,29 @@ describe('Transaction', function() { expect(deserialized.inputs[0] instanceof Transaction.Input.MultiSigScriptHash).to.equal(true); }); }); + + describe('checks on adding inputs', function() { + var transaction = new Transaction(); + it('fails if no output script is provided', function() { + expect(function() { + transaction.addInput(new Transaction.Input()); + }).to.throw(errors.Transaction.NeedMoreInfo); + }); + it('fails if no satoshi amount is provided', function() { + var input = new Transaction.Input(); + expect(function() { + transaction.addInput(input); + }).to.throw(errors.Transaction.NeedMoreInfo); + expect(function() { + transaction.addInput(new Transaction.Input(), Script.empty()); + }).to.throw(errors.Transaction.NeedMoreInfo); + }); + it('allows output and transaction to be feed as arguments', function() { + expect(function() { + transaction.addInput(new Transaction.Input(), Script.empty(), 0); + }).to.not.throw(); + }); + }); }); var tx_empty_hex = '01000000000000000000';