From aa8e5488009dde3b277a183b11821d6d288a8772 Mon Sep 17 00:00:00 2001
From: Zaki Manian <zaki@manian.org>
Date: Fri, 14 Aug 2015 11:26:17 -0700
Subject: [PATCH 1/3] To be effective within the current Bitcoin network, the
 inputs to a transaction with an nLocktime must be not the standard max value.

We set the sequence number of 0 if the value is max.

Currently sequence numbers other than MAX_INT32 have no meaning in the Bitcoin protocol
but this may change in future BIPS
---
 lib/transaction/input/input.js  |  2 ++
 lib/transaction/transaction.js  | 15 +++++++++++++++
 test/transaction/transaction.js | 30 ++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/lib/transaction/input/input.js b/lib/transaction/input/input.js
index c34afb5..d425768 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 2c20031..c106bcd 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 2cee222..0746af9 100644
--- a/test/transaction/transaction.js
+++ b/test/transaction/transaction.js
@@ -748,6 +748,36 @@ 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);
+      expect(transaction.inputs[0].sequenceNumber
+        .should.not.equal(Transaction.Input.DEFAULT_SEQNUMBER));
+    });
+    it('has a non-max sequenceNumber for effective blockheight locktime tx', function() {
+      var transaction = new Transaction()
+        .from(simpleUtxoWith1BTC)
+        .lockUntilBlockHeight(blockHeight);
+      expect(transaction.inputs[0].sequenceNumber
+        .should.not.equal(Transaction.Input.DEFAULT_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);
+      expect(serialized_tx.should.equal(copy.uncheckedSerialize()));
+    });
+    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);
+      expect(serialized_tx.should.equal(copy.uncheckedSerialize()));
+    });
   });
 
   it('handles anyone-can-spend utxo', function() {

From c7c1122123e930e2a13d9a953f3bd57f1eb972c2 Mon Sep 17 00:00:00 2001
From: Zaki Manian <zaki@manian.org>
Date: Thu, 27 Aug 2015 14:54:42 -0700
Subject: [PATCH 2/3] Adjusted test cases as requested.

Test that the SequenceNumber is zero

Remove unncessary expect
---
 test/transaction/transaction.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js
index 0746af9..5b1a498 100644
--- a/test/transaction/transaction.js
+++ b/test/transaction/transaction.js
@@ -752,15 +752,15 @@ describe('Transaction', function() {
       var transaction = new Transaction()
         .from(simpleUtxoWith1BTC)
         .lockUntilDate(date);
-      expect(transaction.inputs[0].sequenceNumber
-        .should.not.equal(Transaction.Input.DEFAULT_SEQNUMBER));
+      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);
-      expect(transaction.inputs[0].sequenceNumber
-        .should.not.equal(Transaction.Input.DEFAULT_SEQNUMBER));
+      transaction.inputs[0].sequenceNumber
+        .should.equal(Transaction.Input.DEFAULT_LOCKTIME_SEQNUMBER);
     });
     it('should serialize correctly for date locktime ', function() {
       var transaction= new Transaction()
@@ -768,7 +768,7 @@ describe('Transaction', function() {
         .lockUntilDate(date);
       var serialized_tx = transaction.uncheckedSerialize();
       var copy = new Transaction(serialized_tx);
-      expect(serialized_tx.should.equal(copy.uncheckedSerialize()));
+      serialized_tx.should.equal(copy.uncheckedSerialize());
     });
     it('should serialize correctly for a block height locktime', function() {
       var transaction= new Transaction()
@@ -776,7 +776,7 @@ describe('Transaction', function() {
         .lockUntilBlockHeight(blockHeight);
       var serialized_tx = transaction.uncheckedSerialize();
       var copy = new Transaction(serialized_tx);
-      expect(serialized_tx.should.equal(copy.uncheckedSerialize()));
+      serialized_tx.should.equal(copy.uncheckedSerialize());
     });
   });
 

From c9980dc9b2c8f3ae1604ad8d492a3142cb1988b0 Mon Sep 17 00:00:00 2001
From: Zaki Manian <zaki@manian.org>
Date: Thu, 27 Aug 2015 15:46:22 -0700
Subject: [PATCH 3/3] Ensure that sequence number is preserved on after
 serialize->deserialize

---
 test/transaction/transaction.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js
index 5b1a498..fbbc5ab 100644
--- a/test/transaction/transaction.js
+++ b/test/transaction/transaction.js
@@ -769,6 +769,8 @@ describe('Transaction', function() {
       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()
@@ -777,6 +779,8 @@ describe('Transaction', function() {
       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)
     });
   });