From 786198f130ba2acbf1e8fa9afb2e65d51898f456 Mon Sep 17 00:00:00 2001
From: xnova <xnova@counterparty.co>
Date: Wed, 5 Mar 2014 16:53:29 -0500
Subject: [PATCH] * Fixes address.js to be able to deal with testnet P2SH
 addresses * Enhanced address.js testsuite...now also verifies address
 versions * Enhances README to show how to run test suite

---
 README.md       |  6 ++++++
 src/address.js  |  2 +-
 src/script.js   | 17 +++++++++--------
 test/address.js | 51 ++++++++++++++++++++++++++++---------------------
 4 files changed, 45 insertions(+), 31 deletions(-)

diff --git a/README.md b/README.md
index 1adac0a..0c9e191 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,12 @@ Bitcoin library for node.js and browsers.
 
 `npm run-script compile`
 
+## Run the test suite
+
+First install `mocha` (e.g. `npm install -g mocha` ).
+
+Then, just run `mocha` at the root of the `bitcoinjs-lib` checkout directory.
+
 # Usage
 
 ## node.js
diff --git a/src/address.js b/src/address.js
index c99e4bd..a4e6a63 100644
--- a/src/address.js
+++ b/src/address.js
@@ -12,7 +12,7 @@ var Address = function (bytes, version) {
     }
     else if (typeof bytes === 'string') {
         this.hash =
-              bytes.length <= 34     ? base58.checkDecode(bytes)
+              bytes.length <= 35     ? base58.checkDecode(bytes)
             : bytes.length <= 40     ? conv.hexToBytes(bytes)
             :                          util.error('Bad input');
 
diff --git a/src/script.js b/src/script.js
index d630727..1b48500 100644
--- a/src/script.js
+++ b/src/script.js
@@ -2,6 +2,7 @@ var Opcode = require('./opcode');
 var util = require('./util');
 var conv = require('./convert');
 var Address = require('./address');
+var network = require('./network');
 
 var Script = function(data) {
     this.buffer = data || [];
@@ -295,20 +296,20 @@ Script.prototype.writeBytes = function(data) {
 Script.createOutputScript = function(address) {
     var script = new Script();
     address = new Address(address);
-    // Standard pay-to-pubkey-hash
-    if (!address.version) {
+    if (address.version == network.mainnet.p2shVersion || address.version == network.testnet.p2shVersion) {
+        // Standard pay-to-script-hash
+        script.writeOp(Opcode.map.OP_HASH160);
+        script.writeBytes(address.hash);
+        script.writeOp(Opcode.map.OP_EQUAL);
+    }
+    else {
+        // Standard pay-to-pubkey-hash
         script.writeOp(Opcode.map.OP_DUP);
         script.writeOp(Opcode.map.OP_HASH160);
         script.writeBytes(address.hash);
         script.writeOp(Opcode.map.OP_EQUALVERIFY);
         script.writeOp(Opcode.map.OP_CHECKSIG);
     }
-    // Standard pay-to-script-hash
-    else {
-        script.writeOp(Opcode.map.OP_HASH160);
-        script.writeBytes(address.hash);
-        script.writeOp(Opcode.map.OP_EQUAL);
-    }
     return script;
 };
 
diff --git a/test/address.js b/test/address.js
index 40de751..e5a505a 100644
--- a/test/address.js
+++ b/test/address.js
@@ -1,6 +1,7 @@
 /* global describe, it */
 var assert = require('assert');
 var Address = require('../src/address.js');
+var network = require('../src/network.js');
 
 describe('Address', function() {
     describe('toString', function() {
@@ -12,41 +13,47 @@ describe('Address', function() {
 
     describe('validate', function() {
         it('validates known good addresses', function() {
-            function validate(addr) {
+            function validate(addr, expectedVersion) {
                 assert.ok(Address.validate(addr));
+                var address = new Address(addr);
+                assert.ok(address.version == expectedVersion);
             }
 
-            validate('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
-            // validate('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', 'mainnet');
-            validate('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef');
-            // validate('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', 'testnet');
+            validate('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', network.mainnet.addressVersion);
+            validate('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', network.testnet.addressVersion);
 
-            validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP');
-            validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y');
-            validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs');
-            validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez');
-            validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd');
+            validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP', network.mainnet.addressVersion);
+            validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y', network.mainnet.addressVersion);
+            validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs', network.mainnet.addressVersion);
+            validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez', network.mainnet.addressVersion);
+            validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd', network.mainnet.addressVersion);
 
             // p2sh addresses
-            validate('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt');
-            // validate('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt', 'mainnet');
-            validate('2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7');
-            // validate('2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7', 'testnet');
+            validate('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt', network.mainnet.p2shVersion);
+            validate('2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7', network.testnet.p2shVersion);
         })
 
         it('does not validate illegal examples', function() {
             function invalid(addr) {
                 assert.ok(!Address.validate(addr));
             }
+            function invalidNetwork(addr, unexpectedVersion) {
+                assert.ok(Address.validate(addr)); //must be a valid address itself
+                if(addr.length >= 34 && unexpectedVersion !== undefined) {
+                  var address = new Address(addr);
+                  if(unexpectedVersion !== undefined)
+                      assert.ok(address.version != unexpectedVersion);
+                }
+            }
 
-            invalid('');
-            invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhe');
-
-            // invalid('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', 'testnet');
-            // invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', 'mainnet');
-
-            // invalid base58 string
-            invalid('%%@');
+            invalid(''); //empty should be invalid
+            invalid('%%@'); // invalid base58 string
+            invalid('1A1zP1eP5QGefi2DzPTf2L5SLmv7DivfNz'); // bad address (doesn't checksum)
+            invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhe'); // bad address (doesn't checksum)
+            
+            //and test for the wrong networks
+            invalidNetwork('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', network.mainnet.addressVersion);
+            invalidNetwork('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', network.testnet.addressVersion);
         })
     })
 })