diff --git a/lib/transaction/input/input.js b/lib/transaction/input/input.js index c34afb521ac..d425768f599 100644 --- a/lib/transaction/input/input.js +++ b/lib/transaction/input/input.js @@ -13,6 +13,7 @@ var Output = require('../output'); var DEFAULT_SEQNUMBER = 0xFFFFFFFF; +var DEFAULT_LOCKTIME_SEQNUMBER = 0x00000000; function Input(params) { if (!(this instanceof Input)) { @@ -24,6 +25,7 @@ function Input(params) { } Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER; +Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER; Object.defineProperty(Input.prototype, 'script', { configurable: false, diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 2c200318aa9..c106bcd04dc 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -414,6 +414,13 @@ Transaction.prototype.lockUntilDate = function(time) { if (_.isDate(time)) { time = time.getTime() / 1000; } + + for (var i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER){ + this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; + } + } + this.nLockTime = time; return this; }; @@ -433,6 +440,14 @@ Transaction.prototype.lockUntilBlockHeight = function(height) { if (height < 0) { throw new errors.Transaction.NLockTimeOutOfRange(); } + + for (var i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER){ + this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER; + } + } + + this.nLockTime = height; return this; }; diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index 2cee2221ffd..fbbc5abedeb 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -748,6 +748,40 @@ describe('Transaction', function() { return new Transaction().lockUntilBlockHeight(-1); }).to.throw(errors.Transaction.NLockTimeOutOfRange); }); + it('has a non-max sequenceNumber for effective date locktime tx', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC) + .lockUntilDate(date); + transaction.inputs[0].sequenceNumber + .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER); + }); + it('has a non-max sequenceNumber for effective blockheight locktime tx', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC) + .lockUntilBlockHeight(blockHeight); + transaction.inputs[0].sequenceNumber + .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER); + }); + it('should serialize correctly for date locktime ', function() { + var transaction= new Transaction() + .from(simpleUtxoWith1BTC) + .lockUntilDate(date); + var serialized_tx = transaction.uncheckedSerialize(); + var copy = new Transaction(serialized_tx); + serialized_tx.should.equal(copy.uncheckedSerialize()); + copy.inputs[0].sequenceNumber + .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER) + }); + it('should serialize correctly for a block height locktime', function() { + var transaction= new Transaction() + .from(simpleUtxoWith1BTC) + .lockUntilBlockHeight(blockHeight); + var serialized_tx = transaction.uncheckedSerialize(); + var copy = new Transaction(serialized_tx); + serialized_tx.should.equal(copy.uncheckedSerialize()); + copy.inputs[0].sequenceNumber + .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER) + }); }); it('handles anyone-can-spend utxo', function() {