From 3a15f0c6ba2c943ec080ebef24accd557fc3ad8f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 2 Mar 2015 18:32:24 +1100 Subject: [PATCH 01/64] tests: add scriptHash(pubKeyHash) test fixture --- test/fixtures/transaction_builder.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 1845a703b..a1c5529f3 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -44,6 +44,28 @@ } ] }, + { + "description": "Transaction w/ scriptHash(pubKeyHash) -> pubKeyHash", + "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000085483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817981976a914751e76e8199196d454941c45d1b3a323f1433bd688acffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "redeemScript": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 10000 + } + ] + }, { "description": "Transaction w/ scriptHash(multisig 2-of-2) -> pubKeyHash", "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd1b0100483045022100b7a9bab60c4307349de9571ce0bd26ebb9d68d4e9ab3f9173e1f736f1390a04a022020931ff70e87033cdd94bdf434e865993b2258065c5c222a53f29d077bcfa4480147304402206d79ad83f1ab12fc9feee9e66412de842fcbf8de0632beb4433d469f24f0fb4e022079e6df186582f2686a3292bde8e50dac36cb9bec3991995fe331e1daef7df8a4014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000", From af3491822e3cf225f27aadef86133641d304289b Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 3 Mar 2015 09:53:57 +1100 Subject: [PATCH 02/64] scripts: multisigInput only uses scriptPubKey for validation, OP_0 validation not necessary --- src/scripts.js | 9 ++------- test/fixtures/scripts.json | 20 ++++---------------- test/scripts.js | 3 +-- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/scripts.js b/src/scripts.js index 387618429..047bc1653 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -253,13 +253,8 @@ function multisigInput (signatures, scriptPubKey) { var m = mOp - (ops.OP_1 - 1) var n = nOp - (ops.OP_1 - 1) - var count = 0 - signatures.forEach(function (signature) { - count += (signature !== ops.OP_0) - }) - - assert(count >= m, 'Not enough signatures provided') - assert(count <= n, 'Too many signatures provided') + assert(signatures.length >= m, 'Not enough signatures provided') + assert(signatures.length <= n, 'Too many signatures provided') } return Script.fromChunks([].concat(ops.OP_0, signatures)) diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json index e79a6e76a..8bd22a9b4 100644 --- a/test/fixtures/scripts.json +++ b/test/fixtures/scripts.json @@ -173,31 +173,19 @@ { "description": "Not enough signatures provided", "type": "multisig", - "pubKeys": [ - "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340" - ], - "signatures": [ - null, - null - ] + "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG", + "signatures": [] }, { "exception": "Not enough signatures provided", - "pubKeys": [ - "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1", - "0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a" - ], + "scriptPubKey": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG", "signatures": [ "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801" ] }, { "exception": "Too many signatures provided", - "pubKeys": [ - "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1", - "0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a" - ], + "scriptPubKey": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG", "signatures": [ "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801", "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501", diff --git a/test/scripts.js b/test/scripts.js index ccfee0b13..41069cddf 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -192,8 +192,7 @@ describe('Scripts', function () { }) fixtures.invalid.multisigInput.forEach(function (f) { - var pubKeys = f.pubKeys.map(ECPubKey.fromHex) - var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) + var scriptPubKey = Script.fromASM(f.scriptPubKey) it('throws on ' + f.exception, function () { var signatures = f.signatures.map(function (signature) { From c79fecffa3ded9ee26db8c777b72a58d09ed8a48 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 3 Mar 2015 09:54:55 +1100 Subject: [PATCH 03/64] tests: add failing test for transaction builder multisig --- test/fixtures/transaction_builder.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index a1c5529f3..68c83c3a7 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -141,6 +141,31 @@ } ] }, + { + "description": "Transaction w/ scriptHash(multisig 2-of-3)", + "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd5e0100483045022100eec19e061cad41610f9b42d2b06638b6b0fec3da0de9c6858e7f8c06053979900220622936dd47e202b2ad17639cda680e52334d407149252959936bb1f38e4acc52014830450221009aac215157a74a18234fd06be27448dccee809986bbf93be457a9262f0c69a9402203ff41d7c757f0e8951e4471f205087ecff499f986400ab18210eaad9a628e33c014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG" + }, + { + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ] + }, { "description": "Transaction w/ scriptHash(pubKey) -> pubKeyHash", "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006c47304402201115644b134932c8a7a8e925769d130a801288d477130e2bf6fadda20b33754d02202ecefbf63844d7cb2d5868539c39f973fe019f72e5c31a707836c0d61ef317db012321033e29aea1168a835d5e386c292082db7b7807172a10ec634ad34226f36d79e70facffffffff0100f90295000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", From bcf8d0177dfb9b7c859b010aec695293372bf764 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 3 Mar 2015 09:55:17 +1100 Subject: [PATCH 04/64] TxBuilder: fix OP_0 in buildComplete --- src/transaction_builder.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 924f177e5..827f386c3 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -242,10 +242,15 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { }) // fill in blanks with OP_0 - for (var i = 0; i < msSignatures.length; ++i) { - if (msSignatures[i]) continue - - msSignatures[i] = ops.OP_0 + if (allowIncomplete) { + for (var i = 0; i < msSignatures.length; ++i) { + if (msSignatures[i]) continue + + msSignatures[i] = ops.OP_0 + } + } else { + // Array.prototype.filter returns non-sparse array + msSignatures = msSignatures.filter(function (x) { return x }) } var redeemScript = allowIncomplete ? undefined : input.redeemScript From cdcbb2ccb4828135e797f6d7caffdfc218819ac2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 3 Mar 2015 10:43:33 +1100 Subject: [PATCH 05/64] tests: fix inconsistent key compression --- test/fixtures/transaction_builder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 68c83c3a7..d3a6ef0fb 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -150,7 +150,7 @@ "vout": 0, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG" }, { From c52420a0037b9d2647bc1e1e935c373f6dd05df7 Mon Sep 17 00:00:00 2001 From: Ruben de Vries Date: Tue, 3 Mar 2015 11:22:42 +0100 Subject: [PATCH 06/64] change 2of2 integration test to 2of3 --- test/integration/multisig.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/integration/multisig.js b/test/integration/multisig.js index fabaad998..80ed051b9 100644 --- a/test/integration/multisig.js +++ b/test/integration/multisig.js @@ -19,18 +19,19 @@ describe('bitcoinjs-lib (multisig)', function () { assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') }) - it('can spend from a 2-of-2 multsig P2SH address', function (done) { + it('can spend from a 2-of-3 multsig P2SH address', function (done) { this.timeout(20000) var privKeys = [ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', - '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT' + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe' ].map(bitcoin.ECKey.fromWIF) var pubKeys = privKeys.map(function (x) { return x.pub }) - var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 2 + var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3 var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString() @@ -57,10 +58,9 @@ describe('bitcoinjs-lib (multisig)', function () { txb.addInput(unspent.txId, unspent.vout) txb.addOutput(targetAddress, 1e4) - // sign w/ each private key - privKeys.forEach(function (privKey) { - txb.sign(0, privKey, redeemScript) - }) + // sign with 1st and 3rd key + txb.sign(0, privKeys[0], redeemScript) + txb.sign(0, privKeys[2], redeemScript) // broadcast our transaction blockchain.transactions.propagate(txb.build().toHex(), function (err) { From 2f100e0eae1291c9f7755bd2fffbbde630d19000 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 20:32:08 +1100 Subject: [PATCH 07/64] tests: add failing pushDataInt fixtures --- test/bufferutils.js | 19 +++++-- test/fixtures/bufferutils.json | 48 +++++++++++------ test/fixtures/script.json | 94 +++++++++++++++++++--------------- test/fixtures/transaction.json | 51 ++++++++++++++++++ test/script.js | 2 +- test/transaction.js | 41 +++++++-------- 6 files changed, 172 insertions(+), 83 deletions(-) diff --git a/test/bufferutils.js b/test/bufferutils.js index 485447b2e..c97e0bcce 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -32,6 +32,17 @@ describe('bufferutils', function () { assert.equal(d.size, buffer.length) }) }) + + fixtures.invalid.readPushDataInt.forEach(function (f) { + if (!f.hexPD) return + + it('decodes ' + f.hexPD + ' as null', function () { + var buffer = new Buffer(f.hexPD, 'hex') + + var n = bufferutils.readPushDataInt(buffer, 0) + assert.equal(n, null) + }) + }) }) describe('readUInt64LE', function () { @@ -44,7 +55,7 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.forEach(function (f) { + fixtures.invalid.readUInt64LE.forEach(function (f) { it('throws on ' + f.description, function () { var buffer = new Buffer(f.hex64, 'hex') @@ -66,7 +77,7 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.forEach(function (f) { + fixtures.invalid.readUInt64LE.forEach(function (f) { it('throws on ' + f.description, function () { var buffer = new Buffer(f.hexVI, 'hex') @@ -151,7 +162,7 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.forEach(function (f) { + fixtures.invalid.readUInt64LE.forEach(function (f) { it('throws on ' + f.description, function () { var buffer = new Buffer(8) buffer.fill(0) @@ -174,7 +185,7 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.forEach(function (f) { + fixtures.invalid.readUInt64LE.forEach(function (f) { it('throws on ' + f.description, function () { var buffer = new Buffer(9) buffer.fill(0) diff --git a/test/fixtures/bufferutils.json b/test/fixtures/bufferutils.json index 8c6881d1b..baa003fe4 100644 --- a/test/fixtures/bufferutils.json +++ b/test/fixtures/bufferutils.json @@ -82,20 +82,36 @@ "hexVI": "ffffffffffffff1f00" } ], - "invalid": [ - { - "description": "n === 2^53", - "exception": "value is larger than maximum value for type", - "hex64": "0000000000002000", - "hexVI": "ff0000000000000020", - "dec": 9007199254740992 - }, - { - "description": "n > 2^53", - "exception": "value is larger than maximum value for type", - "hex64": "0100000000002000", - "hexVI": "ff0100000000000020", - "dec": 9007199254740993 - } - ] + "invalid": { + "readUInt64LE": [ + { + "description": "n === 2^53", + "exception": "value is larger than maximum value for type", + "hex64": "0000000000002000", + "hexVI": "ff0000000000000020", + "dec": 9007199254740992 + }, + { + "description": "n > 2^53", + "exception": "value is larger than maximum value for type", + "hex64": "0100000000002000", + "hexVI": "ff0100000000000020", + "dec": 9007199254740993 + } + ], + "readPushDataInt": [ + { + "description": "OP_PUSHDATA1, no size", + "hexPD": "4c" + }, + { + "description": "OP_PUSHDATA2, no size", + "hexPD": "4d" + }, + { + "description": "OP_PUSHDATA4, no size", + "hexPD": "4e" + } + ] + } } diff --git a/test/fixtures/script.json b/test/fixtures/script.json index e06f9f077..714976cb8 100644 --- a/test/fixtures/script.json +++ b/test/fixtures/script.json @@ -1,86 +1,96 @@ { "valid": [ { + "asm": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95 OP_CHECKSIG", "description": "pay-to-PubKey", - "hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac", - "type": "pubkey", "hash": "26e645ab170255f2a0a82d29e48f35b14ae7c826", - "pubKey": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95", - "asm": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95 OP_CHECKSIG", - "scriptPubKey": true + "hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac", + "pubKey": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95" }, { + "asm": "OP_HASH160 e8c300c87986efa84c37c0519929019ef86eb5b4 OP_EQUAL", "description": "P2SH ScriptPubKey", - "hex": "a914e8c300c87986efa84c37c0519929019ef86eb5b487", - "type": "scripthash", "hash": "0ba47b56a573bab4b430ad6ed3ec79270e04b066", - "asm": "OP_HASH160 e8c300c87986efa84c37c0519929019ef86eb5b4 OP_EQUAL", - "scriptPubKey": true + "hex": "a914e8c300c87986efa84c37c0519929019ef86eb5b487" }, { + "asm": "OP_DUP OP_HASH160 5a3acbc7bbcc97c5ff16f5909c9d7d3fadb293a8 OP_EQUALVERIFY OP_CHECKSIG", "description": "PubKeyHash ScriptPubKey", - "hex": "76a9145a3acbc7bbcc97c5ff16f5909c9d7d3fadb293a888ac", - "type": "pubkeyhash", "hash": "a5313f33d5c7b81674b35f7f3febc3522ef234db", - "asm": "OP_DUP OP_HASH160 5a3acbc7bbcc97c5ff16f5909c9d7d3fadb293a8 OP_EQUALVERIFY OP_CHECKSIG", - "scriptPubKey": true + "hex": "76a9145a3acbc7bbcc97c5ff16f5909c9d7d3fadb293a888ac" }, { + "asm": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301 040cd2d2ce17a1e9b2b3b2cb294d40eecf305a25b7e7bfdafae6bb2639f4ee399b3637706c3d377ec4ab781355add443ae864b134c5e523001c442186ea60f0eb8", "description": "pubKeyHash scriptSig", - "hex": "48304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f30141040cd2d2ce17a1e9b2b3b2cb294d40eecf305a25b7e7bfdafae6bb2639f4ee399b3637706c3d377ec4ab781355add443ae864b134c5e523001c442186ea60f0eb8", - "type": "pubkeyhash", "hash": "b9bac2a5c5c29bb27c382d41fa3d179c646c78fd", - "asm": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301 040cd2d2ce17a1e9b2b3b2cb294d40eecf305a25b7e7bfdafae6bb2639f4ee399b3637706c3d377ec4ab781355add443ae864b134c5e523001c442186ea60f0eb8", - "scriptPubKey": false + "hex": "48304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f30141040cd2d2ce17a1e9b2b3b2cb294d40eecf305a25b7e7bfdafae6bb2639f4ee399b3637706c3d377ec4ab781355add443ae864b134c5e523001c442186ea60f0eb8" }, { + "asm": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301", "description": "pubKey scriptSig", - "hex": "48304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301", - "type": "pubkey", "hash": "44d9982c3e79452e02ef5816976a0e20a0ec1cba", - "signature": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301", - "asm": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301", - "scriptPubKey": false + "hex": "48304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301", + "signature": "304502206becda98cecf7a545d1a640221438ff8912d9b505ede67e0138485111099f696022100ccd616072501310acba10feb97cecc918e21c8e92760cd35144efec7622938f301" }, { + "asm": "OP_TRUE 032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca33016 02308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a OP_2 OP_CHECKMULTISIG", "description": "Valid multisig script", - "hex": "5121032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca330162102308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a52ae", - "type": "multisig", "hash": "f1c98f0b74ecabcf78ae20dfa224bb6666051fbe", - "asm": "OP_TRUE 032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca33016 02308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a OP_2 OP_CHECKMULTISIG", - "scriptPubKey": true + "hex": "5121032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca330162102308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a52ae" }, { + "asm": "OP_0 304402202b29881db1b4cc128442d955e906d41c77365ed9a8392b584be12d980b236459022009da4bc60d09280aa26f4f981bfbed94eb7263d92920961e48a7f3f0991895b101 3045022100871708a7597c1dbebff2a5527a56a1f2b49d73e35cd825a07285f5f29f5766d8022003bd7ac25334e9a6d6020cc8ba1be67a8c70dca8e7063ea0547d79c45b9bc12601", "description": "mutisig scriptSig", - "hex": "0047304402202b29881db1b4cc128442d955e906d41c77365ed9a8392b584be12d980b236459022009da4bc60d09280aa26f4f981bfbed94eb7263d92920961e48a7f3f0991895b101483045022100871708a7597c1dbebff2a5527a56a1f2b49d73e35cd825a07285f5f29f5766d8022003bd7ac25334e9a6d6020cc8ba1be67a8c70dca8e7063ea0547d79c45b9bc12601", - "type": "multisig", "hash": "b1ef3ae2c77b356eff81049aad7dfd2eeb34c6f5", - "asm": "OP_0 304402202b29881db1b4cc128442d955e906d41c77365ed9a8392b584be12d980b236459022009da4bc60d09280aa26f4f981bfbed94eb7263d92920961e48a7f3f0991895b101 3045022100871708a7597c1dbebff2a5527a56a1f2b49d73e35cd825a07285f5f29f5766d8022003bd7ac25334e9a6d6020cc8ba1be67a8c70dca8e7063ea0547d79c45b9bc12601", - "scriptPubKey": false + "hex": "0047304402202b29881db1b4cc128442d955e906d41c77365ed9a8392b584be12d980b236459022009da4bc60d09280aa26f4f981bfbed94eb7263d92920961e48a7f3f0991895b101483045022100871708a7597c1dbebff2a5527a56a1f2b49d73e35cd825a07285f5f29f5766d8022003bd7ac25334e9a6d6020cc8ba1be67a8c70dca8e7063ea0547d79c45b9bc12601" }, { + "asm": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474", "description": "OP_RETURN script", - "hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474", - "type": "nulldata", "hash": "ec88f016655477663455fe6a8e83508c348ea145", - "asm": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474", - "scriptPubKey": true + "hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474" }, { + "asm": "OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL", "description": "Non standard script", - "hex": "aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087", - "type": "nonstandard", "hash": "3823382e70d1930989813d3459988e0d7c2861d8", - "asm": "OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL", - "scriptPubKey": true + "hex": "aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087" }, { + "asm": "OP_0 OP_0 OP_0 OP_CHECKMULTISIG", "description": "Invalid multisig script", - "hex": "000000ae", - "type": "nonstandard", "hash": "62ede8963f9387544935f168745262f703dab1fb", - "asm": "OP_0 OP_0 OP_0 OP_CHECKMULTISIG", - "scriptPubKey": true + "hex": "000000ae" + }, + { + "asm": "", + "description": "Not enough data: OP_1", + "hash": "c51b66bced5e4491001bd702669770dccf440982", + "hex": "01" + }, + { + "asm": "", + "description": "Not enough data: OP_2", + "hash": "d48ce86c698f246829921ba9fb2a844ae2adba67", + "hex": "0201" + }, + { + "asm": "", + "description": "Not enough data: OP_PUSHDATA1 0x02", + "hash": "b663ef01a96ff65bec84a3fb14688d6ff7fc617c", + "hex": "4c0201" + }, + { + "asm": "", + "description": "Not enough data: OP_PUSHDATA2 0xffff", + "hash": "b4d2fac2836232e59d7b1628f64f24bce3cb4478", + "hex": "4dffff01" + }, + { + "asm": "", + "description": "Not enough data: OP_PUSHDATA4 0xffffffff", + "hash": "941db1ca32faf29e1338fb966bb56d98fbce4823", + "hex": "4effffffff01" } ] } diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json index 043dfed03..97108181c 100644 --- a/test/fixtures/transaction.json +++ b/test/fixtures/transaction.json @@ -173,6 +173,57 @@ ], "locktime": 0 } + }, + { + "description": "Transaction that ignores script chunking rules - Bug #367", + "id": "ebc9fa1196a59e192352d76c0f6e73167046b9d37b8302b6bb6968dfd279b767", + "hash": "67b779d2df6869bbb602837bd3b9467016736e0f6cd75223199ea59611fac9eb", + "hex": "01000000019ac03d5ae6a875d970128ef9086cef276a1919684a6988023cc7254691d97e6d010000006b4830450221009d41dc793ba24e65f571473d40b299b6459087cea1509f0d381740b1ac863cb6022039c425906fcaf51b2b84d8092569fb3213de43abaff2180e2a799d4fcb4dd0aa012102d5ede09a8ae667d0f855ef90325e27f6ce35bbe60a1e6e87af7f5b3c652140fdffffffff080100000000000000010101000000000000000202010100000000000000014c0100000000000000034c02010100000000000000014d0100000000000000044dffff010100000000000000014e0100000000000000064effffffff0100000000", + "raw": { + "version": 1, + "locktime": 0, + "ins": [ + { + "hash": "9ac03d5ae6a875d970128ef9086cef276a1919684a6988023cc7254691d97e6d", + "index": 1, + "script": "30450221009d41dc793ba24e65f571473d40b299b6459087cea1509f0d381740b1ac863cb6022039c425906fcaf51b2b84d8092569fb3213de43abaff2180e2a799d4fcb4dd0aa01 02d5ede09a8ae667d0f855ef90325e27f6ce35bbe60a1e6e87af7f5b3c652140fd" + } + ], + "outs": [ + { + "data": "01", + "value": 1 + }, + { + "data": "0201", + "value": 1 + }, + { + "data": "4c", + "value": 1 + }, + { + "data": "4c0201", + "value": 1 + }, + { + "data": "4d", + "value": 1 + }, + { + "data": "4dffff01", + "value": 1 + }, + { + "data": "4e", + "value": 1 + }, + { + "data": "4effffffff01", + "value": 1 + } + ] + } } ], "invalid": { diff --git a/test/script.js b/test/script.js index 7017522e4..1af2c1c01 100644 --- a/test/script.js +++ b/test/script.js @@ -44,7 +44,7 @@ describe('Script', function () { describe('getHash', function () { fixtures.valid.forEach(function (f) { - it('produces a HASH160 of "' + f.asm + '"', function () { + it('produces a HASH160 of ' + f.description, function () { var script = Script.fromHex(f.hex) assert.equal(script.getHash().toString('hex'), f.hash) diff --git a/test/transaction.js b/test/transaction.js index 4a64493f1..f177318aa 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -18,7 +18,8 @@ describe('Transaction', function () { var script if (txIn.data) { - script = new Script(new Buffer(txIn.data, 'hex'), []) + var data = new Buffer(txIn.data, 'hex') + script = new Script(data, []) } else if (txIn.script) { script = Script.fromASM(txIn.script) } @@ -27,7 +28,16 @@ describe('Transaction', function () { }) raw.outs.forEach(function (txOut) { - tx.addOutput(Script.fromASM(txOut.script), txOut.value) + var script + + if (txOut.data) { + var data = new Buffer(txOut.data, 'hex') + script = new Script(data, []) + } else if (txOut.script) { + script = Script.fromASM(txOut.script) + } + + tx.addOutput(script, txOut.value) }) return tx @@ -35,10 +45,10 @@ describe('Transaction', function () { describe('fromBuffer/fromHex', function () { fixtures.valid.forEach(function (f) { - it('imports ' + f.id + ' correctly', function () { + it('imports ' + f.description + ' (' + f.id + ')', function () { var actual = Transaction.fromHex(f.hex) - assert.deepEqual(actual.toHex(), f.hex) + assert.equal(actual.toHex(), f.hex, actual.toHex()) }) }) @@ -53,10 +63,10 @@ describe('Transaction', function () { describe('toBuffer/toHex', function () { fixtures.valid.forEach(function (f) { - it('exports ' + f.id + ' correctly', function () { + it('exports ' + f.description + ' (' + f.id + ')', function () { var actual = fromRaw(f.raw) - assert.deepEqual(actual.toHex(), f.hex) + assert.equal(actual.toHex(), f.hex, actual.toHex()) }) }) }) @@ -108,19 +118,10 @@ describe('Transaction', function () { }) describe('addOutput', function () { - fixtures.valid.forEach(function (f) { - it('should add the outputs for ' + f.id + ' correctly', function () { - var tx = new Transaction() - - f.raw.outs.forEach(function (txOut, i) { - var scriptPubKey = Script.fromASM(txOut.script) - var j = tx.addOutput(scriptPubKey, txOut.value) - - assert.equal(i, j) - assert.equal(tx.outs[i].script, scriptPubKey) - assert.equal(tx.outs[i].value, txOut.value) - }) - }) + it('returns an index', function () { + var tx = new Transaction() + assert.equal(tx.addOutput(Script.EMPTY, 0), 0) + assert.equal(tx.addOutput(Script.EMPTY, 0), 1) }) }) @@ -158,7 +159,7 @@ describe('Transaction', function () { it('should return the hash for ' + f.id, function () { var tx = Transaction.fromHex(f.hex) - assert.deepEqual(tx.getHash().toString('hex'), f.hash) + assert.equal(tx.getHash().toString('hex'), f.hash) }) }) }) From ec66ca9b1a379dabc2ff9a516e3ba9d46c451fb2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 20:48:28 +1100 Subject: [PATCH 08/64] bufferutils/script: allow for invalid pushDatInts, fixes #367 --- src/bufferutils.js | 3 +++ src/script.js | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bufferutils.js b/src/bufferutils.js index afe03e622..773e5021e 100644 --- a/src/bufferutils.js +++ b/src/bufferutils.js @@ -27,16 +27,19 @@ function readPushDataInt (buffer, offset) { // 8 bit } else if (opcode === opcodes.OP_PUSHDATA1) { + if (offset + 2 > buffer.length) return null number = buffer.readUInt8(offset + 1) size = 2 // 16 bit } else if (opcode === opcodes.OP_PUSHDATA2) { + if (offset + 3 > buffer.length) return null number = buffer.readUInt16LE(offset + 1) size = 3 // 32 bit } else { + if (offset + 5 > buffer.length) return null assert.equal(opcode, opcodes.OP_PUSHDATA4, 'Unexpected opcode') number = buffer.readUInt32LE(offset + 1) diff --git a/src/script.js b/src/script.js index b35bfdf14..6ac9f151a 100644 --- a/src/script.js +++ b/src/script.js @@ -38,8 +38,11 @@ Script.fromBuffer = function (buffer) { // data chunk if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) { var d = bufferutils.readPushDataInt(buffer, i) - i += d.size + // did reading a pushDataInt fail? return non-chunked script + if (d === null) return new Script(buffer, []) + + i += d.size var data = buffer.slice(i, i + d.number) i += d.number From d00ec9af291c0bc659c23ef246692b4bc4c07d70 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 21:00:07 +1100 Subject: [PATCH 09/64] scripts: fix isScriptHashInput classification --- src/scripts.js | 11 ++++------- test/fixtures/scripts.json | 2 +- test/scripts.js | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/scripts.js b/src/scripts.js index 387618429..e5f391657 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -73,15 +73,12 @@ function isScriptHashInput (script, allowIncomplete) { if (!Buffer.isBuffer(lastChunk)) return false var scriptSig = Script.fromChunks(script.chunks.slice(0, -1)) - var scriptPubKey + var redeemScript = Script.fromBuffer(lastChunk) - try { - scriptPubKey = Script.fromBuffer(lastChunk) - } catch (e) { - return false - } + // is redeemScript a valid script? + if (redeemScript.chunks.length === 0) return false - return classifyInput(scriptSig, allowIncomplete) === classifyOutput(scriptPubKey) + return classifyInput(scriptSig, allowIncomplete) === classifyOutput(redeemScript) } function isScriptHashOutput (script) { diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json index e79a6e76a..a702f1d5d 100644 --- a/test/fixtures/scripts.json +++ b/test/fixtures/scripts.json @@ -113,7 +113,7 @@ "scriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED" }, { - "description": "signature forms invalid script", + "description": "redeemScript is a signature, therefore not a valid script", "scriptSig": "OP_0 3045022100e12b17b3a4c80c401a1687487bd2bafee9e5f1f8f1ffc6180ce186672ad7b43a02205e316d1e5e71822f5ef301b694e578fa9c94af4f5f098c952c833f4691307f4e01" } ], diff --git a/test/scripts.js b/test/scripts.js index ccfee0b13..0ad6c2698 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -86,7 +86,7 @@ describe('Scripts', function () { fixtures.invalid[inputFnName].forEach(function (f) { if (inputFn && f.scriptSig) { - it('returns false for ' + f.scriptSig, function () { + it('returns false for ' + f.description + ' (' + f.scriptSig + ')', function () { var script = Script.fromASM(f.scriptSig) assert.equal(inputFn(script), false) @@ -112,7 +112,7 @@ describe('Scripts', function () { fixtures.invalid[outputFnName].forEach(function (f) { if (outputFn && f.scriptPubKey) { - it('returns false for ' + f.scriptPubKey, function () { + it('returns false for ' + f.description + ' (' + f.scriptPubKey + ')', function () { var script = Script.fromASM(f.scriptPubKey) assert.equal(outputFn(script), false) From d904e4424c3ec2517fb5c87a459dbdc7d89aadd9 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 21:25:00 +1100 Subject: [PATCH 10/64] tests: add failing scripts by cross-verifying ASM/Hex --- test/script.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/script.js b/test/script.js index 1af2c1c01..a20220633 100644 --- a/test/script.js +++ b/test/script.js @@ -28,8 +28,13 @@ describe('Script', function () { describe('fromASM/toASM', function () { fixtures.valid.forEach(function (f) { + if (!f.asm) return + it('decodes/encodes ' + f.description, function () { - assert.equal(Script.fromASM(f.asm).toASM(), f.asm) + var script = Script.fromASM(f.asm) + + assert.equal(script.toASM(), f.asm) + assert.equal(script.toHex(), f.hex) }) }) }) @@ -37,7 +42,10 @@ describe('Script', function () { describe('fromHex/toHex', function () { fixtures.valid.forEach(function (f) { it('decodes/encodes ' + f.description, function () { - assert.equal(Script.fromHex(f.hex).toHex(), f.hex) + var script = Script.fromHex(f.hex) + + assert.equal(script.toASM(), f.asm) + assert.equal(script.toHex(), f.hex) }) }) }) From b6622b4cffa76577a7a6dff50edc76f0e50ee30f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 21:28:48 +1100 Subject: [PATCH 11/64] script: return malformed script if returned pushDataOut out of range --- src/script.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/script.js b/src/script.js index 6ac9f151a..141fb1fc9 100644 --- a/src/script.js +++ b/src/script.js @@ -41,8 +41,11 @@ Script.fromBuffer = function (buffer) { // did reading a pushDataInt fail? return non-chunked script if (d === null) return new Script(buffer, []) - i += d.size + + // attempt to read too much data? + if (i + d.number > buffer.length) return new Script(buffer, []) + var data = buffer.slice(i, i + d.number) i += d.number From 4333217bdd7c1972e272c9154698697ed92fd542 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 4 Mar 2015 21:30:31 +1100 Subject: [PATCH 12/64] tests: add example non-standard scripthash --- test/fixtures/scripts.json | 6 ++++++ test/scripts.js | 34 ++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json index a702f1d5d..57d48bf14 100644 --- a/test/fixtures/scripts.json +++ b/test/fixtures/scripts.json @@ -98,6 +98,12 @@ "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", "redeemScriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801", "scriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" + }, + { + "type": "scripthash", + "redeemScript": "OP_0", + "redeemScriptSig": "OP_0", + "scriptSigHex": "000100" } ], "invalid": { diff --git a/test/scripts.js b/test/scripts.js index 0ad6c2698..35cccdbc2 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -64,9 +64,15 @@ describe('Scripts', function () { var expected = type.toLowerCase() === f.type if (inputFn && f.scriptSig) { - it('returns ' + expected + ' for ' + f.scriptSig, function () { - var script = Script.fromASM(f.scriptSig) + var script + + if (f.scriptSig) { + script = Script.fromASM(f.scriptSig) + } else { + script = Script.fromHex(f.scriptSigHex) + } + it('returns ' + expected + ' for ' + f.scriptSig, function () { assert.equal(inputFn(script), expected) }) @@ -74,8 +80,6 @@ describe('Scripts', function () { var expectedIncomplete = type.toLowerCase() === f.typeIncomplete it('returns ' + expected + ' for ' + f.scriptSig, function () { - var script = Script.fromASM(f.scriptSig) - assert.equal(inputFn(script, true), expectedIncomplete) }) } @@ -85,9 +89,15 @@ describe('Scripts', function () { if (!(inputFnName in fixtures.invalid)) return fixtures.invalid[inputFnName].forEach(function (f) { - if (inputFn && f.scriptSig) { - it('returns false for ' + f.description + ' (' + f.scriptSig + ')', function () { - var script = Script.fromASM(f.scriptSig) + if (inputFn && (f.scriptSig || f.scriptSigHex)) { + it('returns false for ' + f.description + ' (' + (f.scriptSig || f.scriptSigHex) + ')', function () { + var script + + if (f.scriptSig) { + script = Script.fromASM(f.scriptSig) + } else { + script = Script.fromHex(f.scriptSigHex) + } assert.equal(inputFn(script), false) }) @@ -240,7 +250,11 @@ describe('Scripts', function () { it('returns ' + f.scriptSig, function () { var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript) - assert.equal(scriptSig.toASM(), f.scriptSig) + if (f.scriptSig) { + assert.equal(scriptSig.toASM(), f.scriptSig) + } else { + assert.equal(scriptSig.toHex(), f.scriptSigHex) + } }) }) }) @@ -248,10 +262,10 @@ describe('Scripts', function () { describe('scriptHashOutput', function () { fixtures.valid.forEach(function (f) { if (f.type !== 'scripthash') return - - var redeemScript = Script.fromASM(f.redeemScript) + if (!f.scriptPubKey) return it('returns ' + f.scriptPubKey, function () { + var redeemScript = Script.fromASM(f.redeemScript) var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash()) assert.equal(scriptPubKey.toASM(), f.scriptPubKey) From 837424ed1681bedc9acf8c00a4ac605aa990f788 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 5 Mar 2015 01:14:48 +1100 Subject: [PATCH 13/64] tests: add bitcoin core block fixtures Data from https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp --- test/bitcoin.core.js | 16 +++++++++++++++- test/fixtures/core/blocks.json | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/core/blocks.json diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js index ee7d4e88e..33066653e 100644 --- a/test/bitcoin.core.js +++ b/test/bitcoin.core.js @@ -6,15 +6,18 @@ var base58check = require('bs58check') var Bitcoin = require('../') var Address = Bitcoin.Address -var networks = Bitcoin.networks +var Block = Bitcoin.Block var ECKey = Bitcoin.ECKey var ECSignature = Bitcoin.ECSignature var Transaction = Bitcoin.Transaction var Script = Bitcoin.Script +var networks = Bitcoin.networks + var base58_encode_decode = require('./fixtures/core/base58_encode_decode.json') var base58_keys_invalid = require('./fixtures/core/base58_keys_invalid.json') var base58_keys_valid = require('./fixtures/core/base58_keys_valid.json') +var blocks_valid = require('./fixtures/core/blocks.json') var sig_canonical = require('./fixtures/core/sig_canonical.json') var sig_noncanonical = require('./fixtures/core/sig_noncanonical.json') var sighash = require('./fixtures/core/sighash.json') @@ -134,6 +137,17 @@ describe('Bitcoin-core', function () { }) }) + describe('Block', function () { + blocks_valid.forEach(function (f) { + it('fromHex can parse ' + f.id, function () { + var block = Block.fromHex(f.hex) + + assert.equal(block.getId(), f.id) + assert.equal(block.transactions.length, f.transactions) + }) + }) + }) + // tx_valid describe('Transaction', function () { tx_valid.forEach(function (f) { diff --git a/test/fixtures/core/blocks.json b/test/fixtures/core/blocks.json new file mode 100644 index 000000000..1a769ae62 --- /dev/null +++ b/test/fixtures/core/blocks.json @@ -0,0 +1,27 @@ +[ + { + "id": "0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af", + "transactions": 9, + "hex": "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000" + }, + { + "id": "000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6", + "transactions": 4, + "hex": "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + }, + { + "id": "000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6", + "transactions": 4, + "hex": "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + }, + { + "id": "000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45", + "transactions": 1, + "hex": "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000" + }, + { + "id": "000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4", + "transactions": 7, + "hex": "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + } +] From 29b93b8a5c393a21865a359d2491faec5664d2e8 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 5 Mar 2015 19:16:22 +1100 Subject: [PATCH 14/64] integration: change 2-of-3 to 2-of-4 and update README --- README.md | 2 +- test/integration/multisig.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 045332e77..3529f5279 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ The below examples are implemented as integration tests, they should be very eas - [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L17) - [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L24) - [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8) -- [Spend from a 2-of-2 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22) +- [Spend from a 2-of-4 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22) - [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7) - [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42) - [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L44) diff --git a/test/integration/multisig.js b/test/integration/multisig.js index 80ed051b9..32be5e2ae 100644 --- a/test/integration/multisig.js +++ b/test/integration/multisig.js @@ -19,19 +19,20 @@ describe('bitcoinjs-lib (multisig)', function () { assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') }) - it('can spend from a 2-of-3 multsig P2SH address', function (done) { + it('can spend from a 2-of-4 multsig P2SH address', function (done) { this.timeout(20000) var privKeys = [ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', - '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe' + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', + '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7' ].map(bitcoin.ECKey.fromWIF) var pubKeys = privKeys.map(function (x) { return x.pub }) - var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3 + var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 4 var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) var address = bitcoin.Address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet).toString() From 000625c191ada0583739a080aaf756961ba3a917 Mon Sep 17 00:00:00 2001 From: Ruben de Vries Date: Tue, 3 Mar 2015 11:51:37 +0100 Subject: [PATCH 15/64] prefill signatures with OP_0s and place signatures in correct order in txb.sign when it's not already prefilled with OP_0s --- src/transaction_builder.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 827f386c3..a960d73ef 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -238,7 +238,7 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { case 'multisig': { // Array.prototype.map is sparse-compatible var msSignatures = input.signatures.map(function (signature) { - return signature.toScriptSignature(input.hashType) + return signature && signature.toScriptSignature(input.hashType) }) // fill in blanks with OP_0 @@ -368,13 +368,33 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash input.signatures = input.signatures || [] } + var signatureScript = input.redeemScript || input.prevOutScript + var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType) + + if (input.scriptType === 'multisig' && input.redeemScript && input.signatures.length !== input.pubKeys.length) { + // store signatures locally + var _signatures = input.signatures.slice() + + // loop over pubKeys to set their respective signature or set it to OP_0 + input.signatures = input.pubKeys.map(function (pubKey) { + var signature = null + _signatures.forEach(function (_signature, _sigIdx) { + // check if the signature is not null / false / OP_0 and verify if it belongs to the pubKey + if (!signature && _signature && pubKey.verify(signatureHash, _signature)) { + // use .splice to remove the signature from the list, so we won't verify it again + signature = _signatures.splice(_sigIdx, 1)[0] + } + }) + + return signature || ops.OP_0 + }) + } + // enforce in order signing of public keys assert(input.pubKeys.some(function (pubKey, i) { if (!privKey.pub.Q.equals(pubKey.Q)) return false assert(!input.signatures[i], 'Signature already exists') - var signatureScript = input.redeemScript || input.prevOutScript - var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType) var signature = privKey.sign(signatureHash) input.signatures[i] = signature From 745eace950ba3939f1580d633442df49f8d60e41 Mon Sep 17 00:00:00 2001 From: Ruben de Vries Date: Tue, 3 Mar 2015 11:50:46 +0100 Subject: [PATCH 16/64] add tests for various PS2H multisig signing scenarios redid P2SH multisig tests to use fixtures --- test/fixtures/transaction_builder.json | 272 +++++++++++++++++++++++++ test/transaction_builder.js | 92 ++++++--- 2 files changed, 339 insertions(+), 25 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index d3a6ef0fb..46066ddd5 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -234,6 +234,278 @@ } ] } + ], + "multisig": [ + { + "description": "P2SH 2of2 multisig, signed in correct order", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + }, + { + "pubKeyIndex": 1, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of2 multisig, signed in shuffled order", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 1, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + }, + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of2 multisig, manually messed up order of signatures", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + }, + { + "pubKeyIndex": 1, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of3 multisig, signed by key 1 and 2", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", + "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + }, + { + "pubKeyIndex": 1, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301004cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff463014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of3 multisig, signed by key 1 and 3", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", + "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + }, + { + "pubKeyIndex": 2, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of3 multisig, signed by key 3 and 1", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", + "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 2, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + }, + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of3 multisig, signed by key 1 and 3, manually messed up order of signatures", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", + "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + }, + { + "pubKeyIndex": 2, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + }, + { + "description": "P2SH 2of3 multisig, signed by key 3 and 1, manually removing OP_0s", + "inputs": [ + { + "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", + "vout": 0, + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", + "pubKeys": [ + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", + "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" + ], + "n": 2, + "signs": [ + { + "pubKeyIndex": 2, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "removeOp0s": true + }, + { + "pubKeyIndex": 0, + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ], + "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", + "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + } ] }, "invalid": { diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 350011be2..21f1a39fc 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,9 +1,9 @@ /* global describe, it, beforeEach */ var assert = require('assert') - var Address = require('../src/address') var BigInteger = require('bigi') +var bitcoin = require('../src') var ECKey = require('../src/eckey') var Script = require('../src/script') var Transaction = require('../src/transaction') @@ -222,6 +222,72 @@ describe('TransactionBuilder', function () { }) }) + describe('multisig', function () { + fixtures.valid.multisig.forEach(function (f) { + it(f.description, function () { + var signs = 0 + f.inputs.forEach(function (input) { + txb.addInput(input.txId, input.vout) + signs = Math.max(signs, input.signs.length) + }) + f.outputs.forEach(function (output) { + txb.addOutput(Script.fromASM(output.script), output.value) + }) + + f.inputs.forEach(function (input) { + var redeemScript = bitcoin.scripts.multisigOutput(input.n, input.pubKeys.map(bitcoin.ECPubKey.fromHex)) + assert.equal(redeemScript.toASM(), input.redeemScript) + }) + + var tx + var forceFixMultisigSigOrder = false + + for (var i = 0; i < signs; i++) { + if (tx) { + txb = TransactionBuilder.fromTransaction(tx) + } + + f.inputs.forEach(function (input, index) { + var privKey = bitcoin.ECKey.fromWIF(input.signs[i].privKey) + var redeemScript = bitcoin.Script.fromASM(input.redeemScript) + txb.sign(index, privKey, redeemScript, null, forceFixMultisigSigOrder) + }) + + tx = txb.buildIncomplete() + + f.inputs.forEach(function (input, index) { + assert(bitcoin.scripts.isCanonicalSignature(tx.ins[index].script.chunks[input.signs[i].pubKeyIndex + 1])) + assert(tx.ins[index].script.chunks.slice(1, -1).every(function (chunk) { + return chunk === bitcoin.opcodes.OP_0 || bitcoin.scripts.isCanonicalSignature(chunk) + })) + }) + + forceFixMultisigSigOrder = false + + // manually mess up the signatures + f.inputs.forEach(function (input, index) { + // remove all OP_0s + if (input.signs[i].removeOp0s) { + tx.ins[index].script.chunks = tx.ins[index].script.chunks.filter(function (chunk) { + return chunk !== bitcoin.opcodes.OP_0 + }) + + // we removed one OP_0 too many, gotta add it back + tx.ins[index].script.chunks.unshift(bitcoin.opcodes.OP_0) + } + }) + } + + assert.equal(tx.toHex(), f.txHexIncomplete, 'txHexIncomplete') + + tx = txb.build() + + assert.equal(tx.toHex(), f.txHexComplete, 'txHexComplete') + + }) + }) + }) + describe('fromTransaction', function () { fixtures.valid.build.forEach(function (f) { it('builds the correct TransactionBuilder for ' + f.description, function () { @@ -242,29 +308,5 @@ describe('TransactionBuilder', function () { }) }) - it('works for the out-of-order P2SH multisig case', function () { - var privKeys = [ - '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', - '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx' - ].map(ECKey.fromWIF) - var redeemScript = Script.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG') - - txb.addInput('4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf', 0) - txb.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 10000) - txb.sign(0, privKeys[0], redeemScript) - - var tx = txb.buildIncomplete() - - // in another galaxy... - // ... far, far away - var txb2 = TransactionBuilder.fromTransaction(tx) - - // [you should] verify that Transaction is what you want... - // ... then sign it - txb2.sign(0, privKeys[1], redeemScript) - var tx2 = txb2.build() - - assert.equal(tx2.toHex(), '0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c01004830450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a8014830450221009418caa5bc18da87b188a180125c0cf06dce6092f75b2d3c01a29493466800fd02206ead65e7ca6e0f17eefe6f78457c084eab59af7c9882be1437de2e7116358eb9014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000') - }) }) }) From e8a8dfe2feaba1c76fcab2c76e67c90868193ea1 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 6 Mar 2015 09:27:01 +1100 Subject: [PATCH 17/64] README: update crypto example line numbers --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3529f5279..19992e523 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,9 @@ The below examples are implemented as integration tests, they should be very eas - [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8) - [Spend from a 2-of-4 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22) - [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7) -- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L42) -- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L44) -- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L90) +- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L44) +- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L46) +- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L92) ## Projects utilizing BitcoinJS From 3e44c4131b67e65108e1b8fed28149314fd80172 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 10 Mar 2015 20:04:52 +1100 Subject: [PATCH 18/64] README: add blocktrail --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 19992e523..c6610dea1 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ The below examples are implemented as integration tests, they should be very eas - [BitAddress](https://www.bitaddress.org) - [Blockchain.info](https://blockchain.info/wallet) +- [Blocktrail](https://www.blocktrail.com/) - [Brainwallet](https://brainwallet.github.io) - [Coinkite](https://coinkite.com) - [Coinpunk](https://coinpunk.com) From 4d08ae5a8a5a29ce9431a229d334bc6bee0e3847 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 10 Mar 2015 20:17:11 +1100 Subject: [PATCH 19/64] tests: clean up unused variables --- test/transaction_builder.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 21f1a39fc..31dbacba3 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -230,6 +230,7 @@ describe('TransactionBuilder', function () { txb.addInput(input.txId, input.vout) signs = Math.max(signs, input.signs.length) }) + f.outputs.forEach(function (output) { txb.addOutput(Script.fromASM(output.script), output.value) }) @@ -240,7 +241,6 @@ describe('TransactionBuilder', function () { }) var tx - var forceFixMultisigSigOrder = false for (var i = 0; i < signs; i++) { if (tx) { @@ -250,7 +250,7 @@ describe('TransactionBuilder', function () { f.inputs.forEach(function (input, index) { var privKey = bitcoin.ECKey.fromWIF(input.signs[i].privKey) var redeemScript = bitcoin.Script.fromASM(input.redeemScript) - txb.sign(index, privKey, redeemScript, null, forceFixMultisigSigOrder) + txb.sign(index, privKey, redeemScript) }) tx = txb.buildIncomplete() @@ -262,8 +262,6 @@ describe('TransactionBuilder', function () { })) }) - forceFixMultisigSigOrder = false - // manually mess up the signatures f.inputs.forEach(function (input, index) { // remove all OP_0s @@ -281,9 +279,7 @@ describe('TransactionBuilder', function () { assert.equal(tx.toHex(), f.txHexIncomplete, 'txHexIncomplete') tx = txb.build() - assert.equal(tx.toHex(), f.txHexComplete, 'txHexComplete') - }) }) }) From 7cd60aaba333690e8301bea47bdf711b2d3a715e Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 11 Mar 2015 11:11:05 +1100 Subject: [PATCH 20/64] tests: remove unnecessary script tests from TxBuilder --- test/fixtures/transaction_builder.json | 45 -------------------------- test/transaction_builder.js | 6 ---- 2 files changed, 51 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 46066ddd5..f51c9c6f3 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -243,11 +243,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" - ], - "n": 2, "signs": [ { "pubKeyIndex": 0, @@ -276,11 +271,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" - ], - "n": 2, "signs": [ { "pubKeyIndex": 1, @@ -309,11 +299,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a" - ], - "n": 2, "signs": [ { "pubKeyIndex": 0, @@ -342,12 +327,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", - "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" - ], - "n": 2, "signs": [ { "pubKeyIndex": 0, @@ -376,12 +355,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", - "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" - ], - "n": 2, "signs": [ { "pubKeyIndex": 0, @@ -410,12 +383,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", - "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" - ], - "n": 2, "signs": [ { "pubKeyIndex": 2, @@ -444,12 +411,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", - "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" - ], - "n": 2, "signs": [ { "pubKeyIndex": 0, @@ -478,12 +439,6 @@ "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf", "vout": 0, "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG", - "pubKeys": [ - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", - "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672" - ], - "n": 2, "signs": [ { "pubKeyIndex": 2, diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 31dbacba3..8e57c9fa3 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -235,11 +235,6 @@ describe('TransactionBuilder', function () { txb.addOutput(Script.fromASM(output.script), output.value) }) - f.inputs.forEach(function (input) { - var redeemScript = bitcoin.scripts.multisigOutput(input.n, input.pubKeys.map(bitcoin.ECPubKey.fromHex)) - assert.equal(redeemScript.toASM(), input.redeemScript) - }) - var tx for (var i = 0; i < signs; i++) { @@ -303,6 +298,5 @@ describe('TransactionBuilder', function () { }, new RegExp(f.exception)) }) }) - }) }) From e80f4803d9cf13c1210d929353af0a9b9a879f66 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 11 Mar 2015 11:51:01 +1100 Subject: [PATCH 21/64] tests: refactor multisig test construction --- test/fixtures/transaction_builder.json | 4 +- test/transaction_builder.js | 69 ++++++++++++-------------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index f51c9c6f3..982396903 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -442,10 +442,10 @@ "signs": [ { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", - "removeOp0s": true + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" }, { + "filterOP_0": true, "pubKeyIndex": 0, "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" } diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 8e57c9fa3..5cefebe60 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,9 +1,11 @@ /* global describe, it, beforeEach */ var assert = require('assert') +var ops = require('../src/opcodes') +var scripts = require('../src/scripts') + var Address = require('../src/address') var BigInteger = require('bigi') -var bitcoin = require('../src') var ECKey = require('../src/eckey') var Script = require('../src/script') var Transaction = require('../src/transaction') @@ -225,51 +227,44 @@ describe('TransactionBuilder', function () { describe('multisig', function () { fixtures.valid.multisig.forEach(function (f) { it(f.description, function () { - var signs = 0 - f.inputs.forEach(function (input) { - txb.addInput(input.txId, input.vout) - signs = Math.max(signs, input.signs.length) - }) - - f.outputs.forEach(function (output) { - txb.addOutput(Script.fromASM(output.script), output.value) - }) + construct(txb, f, false) var tx - for (var i = 0; i < signs; i++) { - if (tx) { - txb = TransactionBuilder.fromTransaction(tx) - } + f.inputs.forEach(function (input, i) { + var redeemScript = Script.fromASM(input.redeemScript) - f.inputs.forEach(function (input, index) { - var privKey = bitcoin.ECKey.fromWIF(input.signs[i].privKey) - var redeemScript = bitcoin.Script.fromASM(input.redeemScript) - txb.sign(index, privKey, redeemScript) - }) - - tx = txb.buildIncomplete() + input.signs.forEach(function (sign) { + // rebuild the transaction each-time after the first + if (tx) { + // do we filter OP_0's beforehand? + if (sign.filterOP_0) { + var scriptSig = tx.ins[i].script + + // ignore OP_0 on the front, ignore redeemScript + var signatures = scriptSig.chunks.slice(1, -1).filter(function(x) { return x !== ops.OP_0 }) + + // rebuild/replace the scriptSig without them + var replacement = scripts.scriptHashInput(scripts.multisigInput(signatures), redeemScript) + tx.ins[i].script = replacement + } + + // now import it + txb = TransactionBuilder.fromTransaction(tx) + } - f.inputs.forEach(function (input, index) { - assert(bitcoin.scripts.isCanonicalSignature(tx.ins[index].script.chunks[input.signs[i].pubKeyIndex + 1])) - assert(tx.ins[index].script.chunks.slice(1, -1).every(function (chunk) { - return chunk === bitcoin.opcodes.OP_0 || bitcoin.scripts.isCanonicalSignature(chunk) - })) - }) + var privKey = ECKey.fromWIF(sign.privKey) + txb.sign(i, privKey, redeemScript, sign.hashType) - // manually mess up the signatures - f.inputs.forEach(function (input, index) { - // remove all OP_0s - if (input.signs[i].removeOp0s) { - tx.ins[index].script.chunks = tx.ins[index].script.chunks.filter(function (chunk) { - return chunk !== bitcoin.opcodes.OP_0 - }) + // update the tx + tx = txb.buildIncomplete() - // we removed one OP_0 too many, gotta add it back - tx.ins[index].script.chunks.unshift(bitcoin.opcodes.OP_0) + // now verify the serialized transaction is as expected + if (sign.txHexIncomplete) { + assert.equal(txb.buildIncomplete(), sign.txHexIncomplete) } }) - } + }) assert.equal(tx.toHex(), f.txHexIncomplete, 'txHexIncomplete') From 69eb58c78374a25c41fd4986b474bedc5376747f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 11 Mar 2015 11:32:27 +1100 Subject: [PATCH 22/64] tests: ignore txHexIncomplete, instead check scriptSig after each signature --- test/fixtures/transaction_builder.json | 73 +++++++++++++++----------- test/transaction_builder.js | 13 +++-- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 982396903..b3f91ce2b 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -246,11 +246,13 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] } @@ -261,8 +263,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of2 multisig, signed in shuffled order", @@ -274,11 +275,13 @@ "signs": [ { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "scriptSig": "OP_0 OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] } @@ -289,8 +292,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of2 multisig, manually messed up order of signatures", @@ -302,11 +304,13 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] } @@ -317,8 +321,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of3 multisig, signed by key 1 and 2", @@ -330,11 +333,13 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } @@ -345,8 +350,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301004cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff463014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff463014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of3 multisig, signed by key 1 and 3", @@ -358,11 +362,13 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } @@ -373,8 +379,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of3 multisig, signed by key 3 and 1", @@ -386,11 +391,13 @@ "signs": [ { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } @@ -401,8 +408,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of3 multisig, signed by key 1 and 3, manually messed up order of signatures", @@ -414,11 +420,13 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } @@ -429,8 +437,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" }, { "description": "P2SH 2of3 multisig, signed by key 3 and 1, manually removing OP_0s", @@ -442,12 +449,15 @@ "signs": [ { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "filterOP_0": true, "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae", + "scriptSigFiltered": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } @@ -458,8 +468,7 @@ "value": 1000 } ], - "txHexIncomplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5f0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d0100483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000", - "txHexComplete": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" + "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000" } ] }, diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 5cefebe60..8d89bdff9 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -246,6 +246,9 @@ describe('TransactionBuilder', function () { // rebuild/replace the scriptSig without them var replacement = scripts.scriptHashInput(scripts.multisigInput(signatures), redeemScript) + assert.equal(replacement.toASM(), sign.scriptSigFiltered) + sign.scriptSigFiltered = replacement.toASM() + tx.ins[i].script = replacement } @@ -259,17 +262,13 @@ describe('TransactionBuilder', function () { // update the tx tx = txb.buildIncomplete() - // now verify the serialized transaction is as expected - if (sign.txHexIncomplete) { - assert.equal(txb.buildIncomplete(), sign.txHexIncomplete) - } + // now verify the serialized scriptSig is as expected + assert.equal(tx.ins[i].script.toASM(), sign.scriptSig) }) }) - assert.equal(tx.toHex(), f.txHexIncomplete, 'txHexIncomplete') - tx = txb.build() - assert.equal(tx.toHex(), f.txHexComplete, 'txHexComplete') + assert.equal(tx.toHex(), f.txHex) }) }) }) From a29761cc8c2224e3862042723325f5b794a1f3a6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 11 Mar 2015 12:42:56 +1100 Subject: [PATCH 23/64] tests: fix standard styling --- test/transaction_builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 8d89bdff9..651b25544 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -242,7 +242,7 @@ describe('TransactionBuilder', function () { var scriptSig = tx.ins[i].script // ignore OP_0 on the front, ignore redeemScript - var signatures = scriptSig.chunks.slice(1, -1).filter(function(x) { return x !== ops.OP_0 }) + var signatures = scriptSig.chunks.slice(1, -1).filter(function (x) { return x !== ops.OP_0 }) // rebuild/replace the scriptSig without them var replacement = scripts.scriptHashInput(scripts.multisigInput(signatures), redeemScript) From 4660b84c2dbb2f00858baecb598d1d45ed1401c8 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 10 Mar 2015 20:34:13 +1100 Subject: [PATCH 24/64] txbuilder: refactor for clarity --- src/transaction_builder.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index a960d73ef..52de58d72 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -371,22 +371,20 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash var signatureScript = input.redeemScript || input.prevOutScript var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType) + // enforce signature order matches public keys if (input.scriptType === 'multisig' && input.redeemScript && input.signatures.length !== input.pubKeys.length) { - // store signatures locally - var _signatures = input.signatures.slice() - - // loop over pubKeys to set their respective signature or set it to OP_0 input.signatures = input.pubKeys.map(function (pubKey) { - var signature = null - _signatures.forEach(function (_signature, _sigIdx) { - // check if the signature is not null / false / OP_0 and verify if it belongs to the pubKey - if (!signature && _signature && pubKey.verify(signatureHash, _signature)) { - // use .splice to remove the signature from the list, so we won't verify it again - signature = _signatures.splice(_sigIdx, 1)[0] - } + var match + + // check for any matching signatures + input.signatures.some(function (signature) { + if (!pubKey.verify(signatureHash, signature)) return false + match = signature + + return true }) - return signature || ops.OP_0 + return match || undefined }) } From 6c02e1692ac42cbc8432f51d0a56ef4a389edcc3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 13 Mar 2015 15:42:13 +1100 Subject: [PATCH 25/64] txbuilder: re-add verification optimizations --- src/transaction_builder.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 52de58d72..f860f9535 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -373,14 +373,20 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash // enforce signature order matches public keys if (input.scriptType === 'multisig' && input.redeemScript && input.signatures.length !== input.pubKeys.length) { + // maintain a local copy of unmatched signatures + var unmatched = input.signatures.slice() + input.signatures = input.pubKeys.map(function (pubKey) { var match // check for any matching signatures - input.signatures.some(function (signature) { + unmatched.some(function (signature, i) { if (!pubKey.verify(signatureHash, signature)) return false match = signature + // remove matched signature from unmatched + unmatched.splice(i, 1) + return true }) From 57856a0a258eab73b45355c008a2b0c8a28d1bd2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:26:16 +1100 Subject: [PATCH 26/64] tests: test autodetect in networks, fixed networks in HDNode --- test/hdnode.js | 6 +++++- test/network.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/hdnode.js b/test/hdnode.js index 342f0f5ff..1cbfd7c52 100644 --- a/test/hdnode.js +++ b/test/hdnode.js @@ -144,17 +144,21 @@ describe('HDNode', function () { describe('fromBase58', function () { fixtures.valid.forEach(function (f) { it('imports ' + f.master.base58 + ' (public) correctly', function () { + var network = networks[f.network] var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.toBase58(), f.master.base58) + assert.equal(hd.network, network) }) }) fixtures.valid.forEach(function (f) { it('imports ' + f.master.base58Priv + ' (private) correctly', function () { - var hd = HDNode.fromBase58(f.master.base58Priv) + var network = networks[f.network] + var hd = HDNode.fromBase58(f.master.base58Priv, network) assert.equal(hd.toBase58(), f.master.base58Priv) + assert.equal(hd.network, network) }) }) diff --git a/test/network.js b/test/network.js index aef09e0e2..79c928853 100644 --- a/test/network.js +++ b/test/network.js @@ -27,7 +27,7 @@ describe('networks', function () { var extb58 = f.bip32[name] it('resolves ' + extb58 + ' to ' + f.network, function () { - assert.equal(HDNode.fromBase58(extb58, network).network, network) + assert.equal(HDNode.fromBase58(extb58).network, network) }) }) }) From 281ecdc06ee68cf602e0f8ea618ca2d63d3972b6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:33:56 +1100 Subject: [PATCH 27/64] networks: remove failing tests, cannot be supported anyway --- test/fixtures/network.json | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/test/fixtures/network.json b/test/fixtures/network.json index b638221c9..eae59567f 100644 --- a/test/fixtures/network.json +++ b/test/fixtures/network.json @@ -29,40 +29,12 @@ "public": "dgub8kXBZ7ymNWy2S8Q3jNgVjFUm5ZJ3QLLaSTdAA89ukSv7Q6MSXwE14b7Nv6eDpE9JJXinTKc8LeLVu19uDPrm5uJuhpKNzV2kAgncwo6bNpP" } }, - { - "network": "viacoin", - "bip32": { - "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", - "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" - } - }, - { - "network": "viacointestnet", - "bip32": { - "private": "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m", - "public": "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp" - } - }, - { - "network": "gamerscoin", - "bip32": { - "private": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k", - "public": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491" - } - }, { "network": "jumbucks", "bip32": { "private": "jprv5eCacBgN4Bz4zYxgVQ7RDt1a3eREhEaj8KjAcJ7YwogxGo2rmBF5kvAQS53JwZpo5wnUmJ9Q7kB6b2gQ1MzC6yaTc188hr6hXZ5t8Ruria1", "public": "jpub1sBw1hDFtZYND339bReRb1xJbgFj6hJaVYemQgXAW9Dw9bN1JiZLJiUtHLgcTTEs1UgRGFAYm3XQPYsYJbpqj1aYPhrMsNcJHfgdAhvFZBB" } - }, - { - "network": "zetacoin", - "bip32": { - "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", - "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" - } } ], "estimateFee": [ From 886d38ebee0ab4c5cf021efa70a6f6e4234ff3de Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:34:36 +1100 Subject: [PATCH 28/64] tests: rename network->networks --- test/{network.js => networks.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{network.js => networks.js} (100%) diff --git a/test/network.js b/test/networks.js similarity index 100% rename from test/network.js rename to test/networks.js From 6a551d9e1ea41b727be9782bd90f2edbc976de5f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 10:37:28 +1100 Subject: [PATCH 29/64] networks: s/magicPrefix/messagePrefix, adds magic constant --- src/networks.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/networks.js b/src/networks.js index 7395aa4b3..3a5ffc581 100644 --- a/src/networks.js +++ b/src/networks.js @@ -3,7 +3,8 @@ var networks = { bitcoin: { - magicPrefix: '\x18Bitcoin Signed Message:\n', + magic: 0xd9b4bef9, + messagePrefix: '\x18Bitcoin Signed Message:\n', bip32: { public: 0x0488b21e, private: 0x0488ade4 @@ -16,7 +17,8 @@ var networks = { estimateFee: estimateFee('bitcoin') }, testnet: { - magicPrefix: '\x18Bitcoin Signed Message:\n', + magic: 0xd9b4bef9, + messagePrefix: '\x18Bitcoin Signed Message:\n', bip32: { public: 0x043587cf, private: 0x04358394 @@ -29,7 +31,8 @@ var networks = { estimateFee: estimateFee('testnet') }, litecoin: { - magicPrefix: '\x19Litecoin Signed Message:\n', + magic: 0xd9b4bef9, + messagePrefix: '\x19Litecoin Signed Message:\n', bip32: { public: 0x019da462, private: 0x019d9cfe @@ -43,7 +46,7 @@ var networks = { estimateFee: estimateFee('litecoin') }, dogecoin: { - magicPrefix: '\x19Dogecoin Signed Message:\n', + messagePrefix: '\x19Dogecoin Signed Message:\n', bip32: { public: 0x02facafd, private: 0x02fac398 @@ -57,7 +60,7 @@ var networks = { estimateFee: estimateFee('dogecoin') }, viacoin: { - magicPrefix: '\x18Viacoin Signed Message:\n', + messagePrefix: '\x18Viacoin Signed Message:\n', bip32: { public: 0x0488b21e, private: 0x0488ade4 @@ -71,7 +74,7 @@ var networks = { estimateFee: estimateFee('viacoin') }, viacointestnet: { - magicPrefix: '\x18Viacoin Signed Message:\n', + messagePrefix: '\x18Viacoin Signed Message:\n', bip32: { public: 0x043587cf, private: 0x04358394 @@ -85,7 +88,7 @@ var networks = { estimateFee: estimateFee('viacointestnet') }, gamerscoin: { - magicPrefix: '\x19Gamerscoin Signed Message:\n', + messagePrefix: '\x19Gamerscoin Signed Message:\n', bip32: { public: 0x019da462, private: 0x019d9cfe @@ -99,7 +102,7 @@ var networks = { estimateFee: estimateFee('gamerscoin') }, jumbucks: { - magicPrefix: '\x19Jumbucks Signed Message:\n', + messagePrefix: '\x19Jumbucks Signed Message:\n', bip32: { public: 0x037a689a, private: 0x037a6460 @@ -113,7 +116,7 @@ var networks = { estimateFee: estimateFee('jumbucks') }, zetacoin: { - magicPrefix: '\x18Zetacoin Signed Message:\n', + messagePrefix: '\x18Zetacoin Signed Message:\n', bip32: { public: 0x0488b21e, private: 0x0488ade4 @@ -146,4 +149,11 @@ function estimateFee (type) { } } +// FIXME: 1.5.3 compatibility patch(s) +for (var networkName in networks) { + var network = networks[networkName] + + network.magicPrefix = network.messagePrefix +} + module.exports = networks From c3a39444e39cd3ce9044fbb889abbeba0d26e001 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 10:38:20 +1100 Subject: [PATCH 30/64] networks: extract estimateFee as a bind --- src/networks.js | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/src/networks.js b/src/networks.js index 3a5ffc581..264ce8f31 100644 --- a/src/networks.js +++ b/src/networks.js @@ -13,8 +13,7 @@ var networks = { scriptHash: 0x05, wif: 0x80, dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162 - feePerKb: 10000, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53 - estimateFee: estimateFee('bitcoin') + feePerKb: 10000 // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53 }, testnet: { magic: 0xd9b4bef9, @@ -27,8 +26,7 @@ var networks = { scriptHash: 0xc4, wif: 0xef, dustThreshold: 546, - feePerKb: 10000, - estimateFee: estimateFee('testnet') + feePerKb: 10000 }, litecoin: { magic: 0xd9b4bef9, @@ -42,8 +40,7 @@ var networks = { wif: 0xb0, dustThreshold: 0, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365 dustSoftThreshold: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.h#L53 - feePerKb: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L56 - estimateFee: estimateFee('litecoin') + feePerKb: 100000 // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L56 }, dogecoin: { messagePrefix: '\x19Dogecoin Signed Message:\n', @@ -56,8 +53,7 @@ var networks = { wif: 0x9e, dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62 - feePerKb: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58 - estimateFee: estimateFee('dogecoin') + feePerKb: 100000000 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58 }, viacoin: { messagePrefix: '\x18Viacoin Signed Message:\n', @@ -70,8 +66,7 @@ var networks = { wif: 0xc7, dustThreshold: 560, dustSoftThreshold: 100000, - feePerKb: 100000, // - estimateFee: estimateFee('viacoin') + feePerKb: 100000 }, viacointestnet: { messagePrefix: '\x18Viacoin Signed Message:\n', @@ -84,8 +79,7 @@ var networks = { wif: 0xff, dustThreshold: 560, dustSoftThreshold: 100000, - feePerKb: 100000, - estimateFee: estimateFee('viacointestnet') + feePerKb: 100000 }, gamerscoin: { messagePrefix: '\x19Gamerscoin Signed Message:\n', @@ -98,8 +92,7 @@ var networks = { wif: 0xA6, dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363 dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51 - feePerKb: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54 - estimateFee: estimateFee('gamerscoin') + feePerKb: 100000 // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54 }, jumbucks: { messagePrefix: '\x19Jumbucks Signed Message:\n', @@ -112,8 +105,7 @@ var networks = { wif: 0xab, dustThreshold: 0, dustSoftThreshold: 10000, - feePerKb: 10000, - estimateFee: estimateFee('jumbucks') + feePerKb: 10000 }, zetacoin: { messagePrefix: '\x18Zetacoin Signed Message:\n', @@ -125,34 +117,35 @@ var networks = { scriptHash: 0x09, wif: 0xe0, dustThreshold: 546, // https://github.com/zetacoin/zetacoin/blob/master/src/core.h#L159 - feePerKb: 10000, // https://github.com/zetacoin/zetacoin/blob/master/src/main.cpp#L54 - estimateFee: estimateFee('zetacoin') + feePerKb: 10000 // https://github.com/zetacoin/zetacoin/blob/master/src/main.cpp#L54 } } -function estimateFee (type) { - return function (tx) { - var network = networks[type] - var baseFee = network.feePerKb - var byteSize = tx.toBuffer().length +function estimateFee (tx, network) { + var baseFee = network.feePerKb + var byteSize = tx.toBuffer().length - var fee = baseFee * Math.ceil(byteSize / 1000) - if (network.dustSoftThreshold === undefined) return fee + var fee = baseFee * Math.ceil(byteSize / 1000) + if (network.dustSoftThreshold === undefined) return fee - tx.outs.forEach(function (e) { - if (e.value < network.dustSoftThreshold) { - fee += baseFee - } - }) + tx.outs.forEach(function (e) { + if (e.value < network.dustSoftThreshold) { + fee += baseFee + } + }) - return fee - } + return fee } // FIXME: 1.5.3 compatibility patch(s) +function patchEstimateFee (network, tx) { + return estimateFee(tx, network) +} + for (var networkName in networks) { var network = networks[networkName] + network.estimateFee = patchEstimateFee.bind(null, network) network.magicPrefix = network.messagePrefix } From 9cda36fc76109149442ec2d57adafc11bebb8be5 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 10:50:47 +1100 Subject: [PATCH 31/64] Transaction: extract byteLength calculation to prototype method --- src/transaction.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index fa1b18a7d..6e8fc6c7b 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -137,6 +137,22 @@ Transaction.prototype.addOutput = function (scriptPubKey, value) { }) - 1) } +Transaction.prototype.byteLength = function () { + function scriptSize (script) { + var length = script.buffer.length + + return bufferutils.varIntSize(length) + length + } + + return ( + 8 + + bufferutils.varIntSize(this.ins.length) + + bufferutils.varIntSize(this.outs.length) + + this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + + this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0) + ) +} + Transaction.prototype.clone = function () { var newTx = new Transaction() newTx.version = this.version @@ -215,19 +231,7 @@ Transaction.prototype.getId = function () { } Transaction.prototype.toBuffer = function () { - function scriptSize (script) { - var length = script.buffer.length - - return bufferutils.varIntSize(length) + length - } - - var buffer = new Buffer( - 8 + - bufferutils.varIntSize(this.ins.length) + - bufferutils.varIntSize(this.outs.length) + - this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + - this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0) - ) + var buffer = new Buffer(this.byteLength()) var offset = 0 function writeSlice (slice) { From 607b3b79833f8b62bf1d80aadae6692a50abf511 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 10:51:21 +1100 Subject: [PATCH 32/64] networks: use byteLength over toBuffer --- src/networks.js | 2 +- test/networks.js | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/networks.js b/src/networks.js index 264ce8f31..d4ba24e2d 100644 --- a/src/networks.js +++ b/src/networks.js @@ -123,7 +123,7 @@ var networks = { function estimateFee (tx, network) { var baseFee = network.feePerKb - var byteSize = tx.toBuffer().length + var byteSize = tx.byteLength() var fee = baseFee * Math.ceil(byteSize / 1000) if (network.dustSoftThreshold === undefined) return fee diff --git a/test/networks.js b/test/networks.js index 79c928853..ead69d8bf 100644 --- a/test/networks.js +++ b/test/networks.js @@ -10,13 +10,13 @@ var Transaction = require('../src/transaction') var fixtures = require('./fixtures/network') describe('networks', function () { - var txToBuffer + var txByteLength before(function () { - txToBuffer = sinon.stub(Transaction.prototype, 'toBuffer') + txByteLength = sinon.stub(Transaction.prototype, 'byteLength') }) after(function () { - Transaction.prototype.toBuffer.restore() + Transaction.prototype.byteLength.restore() }) describe('constants', function () { @@ -39,8 +39,7 @@ describe('networks', function () { var network = networks[f.network] it('calculates the fee correctly for ' + f.description, function () { - var buffer = new Buffer(f.txSize) - txToBuffer.returns(buffer) + txByteLength.returns(f.txSize) var estimateFee = network.estimateFee var tx = new Transaction() From 1079bf95c1095f7fb018f6e4757277d83b7b9d07 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 10:57:39 +1100 Subject: [PATCH 33/64] message: use messagePrefix naming over magicPrefix --- src/message.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/message.js b/src/message.js index ecb1f1858..a210c766e 100644 --- a/src/message.js +++ b/src/message.js @@ -11,11 +11,11 @@ var ecurve = require('ecurve') var ecparams = ecurve.getCurveByName('secp256k1') function magicHash (message, network) { - var magicPrefix = new Buffer(network.magicPrefix) + var messagePrefix = new Buffer(network.messagePrefix) var messageBuffer = new Buffer(message) var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length) - var buffer = Buffer.concat([magicPrefix, lengthBuffer, messageBuffer]) + var buffer = Buffer.concat([messagePrefix, lengthBuffer, messageBuffer]) return crypto.hash256(buffer) } From fc8dd65c0e5e87b963a0d849ec807b5377065506 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:03:19 +1100 Subject: [PATCH 34/64] networks: name e variable in loop --- src/networks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/networks.js b/src/networks.js index d4ba24e2d..083684014 100644 --- a/src/networks.js +++ b/src/networks.js @@ -128,8 +128,8 @@ function estimateFee (tx, network) { var fee = baseFee * Math.ceil(byteSize / 1000) if (network.dustSoftThreshold === undefined) return fee - tx.outs.forEach(function (e) { - if (e.value < network.dustSoftThreshold) { + tx.outs.forEach(function (output) { + if (output.value < network.dustSoftThreshold) { fee += baseFee } }) From 063b0369887d55285bf78ce7036376a8bafa01d6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:14:29 +1100 Subject: [PATCH 35/64] networks: remove magicPrefix double up --- src/networks.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/networks.js b/src/networks.js index 083684014..f2d6bc530 100644 --- a/src/networks.js +++ b/src/networks.js @@ -146,7 +146,6 @@ for (var networkName in networks) { var network = networks[networkName] network.estimateFee = patchEstimateFee.bind(null, network) - network.magicPrefix = network.messagePrefix } module.exports = networks From 0e0a12da279d501a7c2a10b0480ab664e52cea5c Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 13:53:28 +1100 Subject: [PATCH 36/64] txbuilder: fix #374 null inputs --- src/transaction_builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index f860f9535..f4d9923f3 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -113,7 +113,7 @@ TransactionBuilder.fromTransaction = function (transaction) { assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported') // Ignore empty scripts - if (txIn.script.buffer.length === 0) return + if (txIn.script.buffer.length === 0) return {} return extractInput(txIn) }) From 889ed9b92a308ad5e430984b3371100cef35b64a Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 16:00:24 +1100 Subject: [PATCH 37/64] package: update typeforce to 1.0.0, mocha/standard to latest --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index fd4259be2..b49f59ac4 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "bigi": "^1.4.0", "bs58check": "^1.0.4", "ecurve": "^1.0.0", - "typeforce": "^0.1.0" + "typeforce": "^1.0.0" }, "devDependencies": { "async": "^0.9.0", @@ -57,9 +57,9 @@ "cb-helloblock": "^0.4.10", "coveralls": "^2.11.2", "istanbul": "^0.3.5", - "mocha": "^2.1.0", + "mocha": "^2.2.0", "mocha-lcov-reporter": "0.0.1", "sinon": "^1.12.2", - "standard": "^2.7.3" + "standard": "^2.11.0" } } From 5fadfcc4359607aa462af0eedc68a0a3d322317c Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 16:27:11 +1100 Subject: [PATCH 38/64] package: remove unnecessary dev dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index b49f59ac4..917a4237e 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "coveralls": "^2.11.2", "istanbul": "^0.3.5", "mocha": "^2.2.0", - "mocha-lcov-reporter": "0.0.1", "sinon": "^1.12.2", "standard": "^2.11.0" } From e939aa057659c51efdc106200cf123dcec7ba182 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 16:27:25 +1100 Subject: [PATCH 39/64] package: use cb-helloblock 0.4.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 917a4237e..6e6a229b2 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "async": "^0.9.0", "browserify": "^9.0.3", "bs58": "^2.0.1", - "cb-helloblock": "^0.4.10", + "cb-helloblock": "^0.4.13", "coveralls": "^2.11.2", "istanbul": "^0.3.5", "mocha": "^2.2.0", From 7d2e1cd3badd2640a70f63acedb3b9d4d0394107 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 11:38:41 +1100 Subject: [PATCH 40/64] networks: remove exhaustive non-top 5 networks --- src/networks.js | 64 -------------------------------------- test/fixtures/network.json | 7 ----- 2 files changed, 71 deletions(-) diff --git a/src/networks.js b/src/networks.js index f2d6bc530..ddd5c00f5 100644 --- a/src/networks.js +++ b/src/networks.js @@ -54,70 +54,6 @@ var networks = { dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62 feePerKb: 100000000 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58 - }, - viacoin: { - messagePrefix: '\x18Viacoin Signed Message:\n', - bip32: { - public: 0x0488b21e, - private: 0x0488ade4 - }, - pubKeyHash: 0x47, - scriptHash: 0x21, - wif: 0xc7, - dustThreshold: 560, - dustSoftThreshold: 100000, - feePerKb: 100000 - }, - viacointestnet: { - messagePrefix: '\x18Viacoin Signed Message:\n', - bip32: { - public: 0x043587cf, - private: 0x04358394 - }, - pubKeyHash: 0x7f, - scriptHash: 0xc4, - wif: 0xff, - dustThreshold: 560, - dustSoftThreshold: 100000, - feePerKb: 100000 - }, - gamerscoin: { - messagePrefix: '\x19Gamerscoin Signed Message:\n', - bip32: { - public: 0x019da462, - private: 0x019d9cfe - }, - pubKeyHash: 0x26, - scriptHash: 0x05, - wif: 0xA6, - dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363 - dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51 - feePerKb: 100000 // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54 - }, - jumbucks: { - messagePrefix: '\x19Jumbucks Signed Message:\n', - bip32: { - public: 0x037a689a, - private: 0x037a6460 - }, - pubKeyHash: 0x2b, - scriptHash: 0x05, - wif: 0xab, - dustThreshold: 0, - dustSoftThreshold: 10000, - feePerKb: 10000 - }, - zetacoin: { - messagePrefix: '\x18Zetacoin Signed Message:\n', - bip32: { - public: 0x0488b21e, - private: 0x0488ade4 - }, - pubKeyHash: 0x50, - scriptHash: 0x09, - wif: 0xe0, - dustThreshold: 546, // https://github.com/zetacoin/zetacoin/blob/master/src/core.h#L159 - feePerKb: 10000 // https://github.com/zetacoin/zetacoin/blob/master/src/main.cpp#L54 } } diff --git a/test/fixtures/network.json b/test/fixtures/network.json index eae59567f..58737ad2a 100644 --- a/test/fixtures/network.json +++ b/test/fixtures/network.json @@ -28,13 +28,6 @@ "private": "dgpv51eADS3spNJh9Gjth94XcPwAczvQaDJs9rqx11kvxKs6r3Ek8AgERHhjLs6mzXQFHRzQqGwqdeoDkZmr8jQMBfi43b7sT3sx3cCSk5fGeUR", "public": "dgub8kXBZ7ymNWy2S8Q3jNgVjFUm5ZJ3QLLaSTdAA89ukSv7Q6MSXwE14b7Nv6eDpE9JJXinTKc8LeLVu19uDPrm5uJuhpKNzV2kAgncwo6bNpP" } - }, - { - "network": "jumbucks", - "bip32": { - "private": "jprv5eCacBgN4Bz4zYxgVQ7RDt1a3eREhEaj8KjAcJ7YwogxGo2rmBF5kvAQS53JwZpo5wnUmJ9Q7kB6b2gQ1MzC6yaTc188hr6hXZ5t8Ruria1", - "public": "jpub1sBw1hDFtZYND339bReRb1xJbgFj6hJaVYemQgXAW9Dw9bN1JiZLJiUtHLgcTTEs1UgRGFAYm3XQPYsYJbpqj1aYPhrMsNcJHfgdAhvFZBB" - } } ], "estimateFee": [ From bd464d7cb51e21a555b83a177d2a3bc79eccde86 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 16 Mar 2015 12:35:49 +1100 Subject: [PATCH 41/64] networks: remove estimateFee entirely --- src/networks.js | 45 ++---------- test/fixtures/network.json | 144 ++++++++----------------------------- test/networks.js | 45 ++---------- 3 files changed, 41 insertions(+), 193 deletions(-) diff --git a/src/networks.js b/src/networks.js index ddd5c00f5..d694bf767 100644 --- a/src/networks.js +++ b/src/networks.js @@ -1,7 +1,7 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 -var networks = { +module.exports = { bitcoin: { magic: 0xd9b4bef9, messagePrefix: '\x18Bitcoin Signed Message:\n', @@ -12,8 +12,7 @@ var networks = { pubKeyHash: 0x00, scriptHash: 0x05, wif: 0x80, - dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162 - feePerKb: 10000 // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53 + dustThreshold: 546 // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162 }, testnet: { magic: 0xd9b4bef9, @@ -25,8 +24,7 @@ var networks = { pubKeyHash: 0x6f, scriptHash: 0xc4, wif: 0xef, - dustThreshold: 546, - feePerKb: 10000 + dustThreshold: 546 }, litecoin: { magic: 0xd9b4bef9, @@ -38,9 +36,7 @@ var networks = { pubKeyHash: 0x30, scriptHash: 0x05, wif: 0xb0, - dustThreshold: 0, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365 - dustSoftThreshold: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.h#L53 - feePerKb: 100000 // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L56 + dustThreshold: 0 // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365 }, dogecoin: { messagePrefix: '\x19Dogecoin Signed Message:\n', @@ -51,37 +47,6 @@ var networks = { pubKeyHash: 0x1e, scriptHash: 0x16, wif: 0x9e, - dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 - dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62 - feePerKb: 100000000 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58 + dustThreshold: 0 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 } } - -function estimateFee (tx, network) { - var baseFee = network.feePerKb - var byteSize = tx.byteLength() - - var fee = baseFee * Math.ceil(byteSize / 1000) - if (network.dustSoftThreshold === undefined) return fee - - tx.outs.forEach(function (output) { - if (output.value < network.dustSoftThreshold) { - fee += baseFee - } - }) - - return fee -} - -// FIXME: 1.5.3 compatibility patch(s) -function patchEstimateFee (network, tx) { - return estimateFee(tx, network) -} - -for (var networkName in networks) { - var network = networks[networkName] - - network.estimateFee = patchEstimateFee.bind(null, network) -} - -module.exports = networks diff --git a/test/fixtures/network.json b/test/fixtures/network.json index 58737ad2a..e542aadf4 100644 --- a/test/fixtures/network.json +++ b/test/fixtures/network.json @@ -1,116 +1,30 @@ -{ - "valid": { - "constants": [ - { - "network": "bitcoin", - "bip32": { - "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", - "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" - } - }, - { - "network": "testnet", - "bip32": { - "private": "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m", - "public": "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp" - } - }, - { - "network": "litecoin", - "bip32": { - "private": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k", - "public": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491" - } - }, - { - "network": "dogecoin", - "bip32": { - "private": "dgpv51eADS3spNJh9Gjth94XcPwAczvQaDJs9rqx11kvxKs6r3Ek8AgERHhjLs6mzXQFHRzQqGwqdeoDkZmr8jQMBfi43b7sT3sx3cCSk5fGeUR", - "public": "dgub8kXBZ7ymNWy2S8Q3jNgVjFUm5ZJ3QLLaSTdAA89ukSv7Q6MSXwE14b7Nv6eDpE9JJXinTKc8LeLVu19uDPrm5uJuhpKNzV2kAgncwo6bNpP" - } - } - ], - "estimateFee": [ - { - "description": "when txSize < 1kb", - "network": "bitcoin", - "txSize": 1, - "fee": 10000 - }, - { - "description": "when txSize >= 1kb", - "network": "bitcoin", - "txSize": 1000, - "fee": 10000 - }, - { - "description": "rounding", - "network": "bitcoin", - "txSize": 2800, - "fee": 30000 - }, - { - "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used", - "network": "dogecoin", - "txSize": 1000, - "outputs": [ - { - "value": 100000000 - } - ], - "fee": 100000000 - }, - { - "description": "when not every outputs.value > DUST_SOFT_LIMIT", - "network": "dogecoin", - "txSize": 1000, - "outputs": [ - { - "value": 99999999 - }, - { - "value": 99999999 - } - ], - "fee": 300000000 - }, - { - "description": "rounding", - "network": "dogecoin", - "txSize": 2800, - "fee": 300000000 - }, - { - "description": "when outputs.value > DUST_SOFT_LIMIT, feePerKb is used", - "network": "litecoin", - "txSize": 1000, - "outputs": [ - { - "value": 100000 - } - ], - "fee": 100000 - }, - { - "description": "when not every outputs.value > DUST_SOFT_LIMIT", - "network": "litecoin", - "txSize": 1000, - "outputs": [ - { - "value": 99999 - }, - { - "value": 99999 - } - ], - "fee": 300000 - }, - { - "description": "rounding", - "network": "litecoin", - "txSize": 2800, - "fee": 300000 - } - ] +[ + { + "network": "bitcoin", + "bip32": { + "private": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", + "public": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" + } + }, + { + "network": "testnet", + "bip32": { + "private": "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m", + "public": "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp" + } + }, + { + "network": "litecoin", + "bip32": { + "private": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k", + "public": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491" + } + }, + { + "network": "dogecoin", + "bip32": { + "private": "dgpv51eADS3spNJh9Gjth94XcPwAczvQaDJs9rqx11kvxKs6r3Ek8AgERHhjLs6mzXQFHRzQqGwqdeoDkZmr8jQMBfi43b7sT3sx3cCSk5fGeUR", + "public": "dgub8kXBZ7ymNWy2S8Q3jNgVjFUm5ZJ3QLLaSTdAA89ukSv7Q6MSXwE14b7Nv6eDpE9JJXinTKc8LeLVu19uDPrm5uJuhpKNzV2kAgncwo6bNpP" + } } -} +] diff --git a/test/networks.js b/test/networks.js index ead69d8bf..3c9762d0c 100644 --- a/test/networks.js +++ b/test/networks.js @@ -1,52 +1,21 @@ -/* global describe, it, before, after */ +/* global describe, it */ var assert = require('assert') var networks = require('../src/networks') -var sinon = require('sinon') var HDNode = require('../src/hdnode') -var Transaction = require('../src/transaction') var fixtures = require('./fixtures/network') describe('networks', function () { - var txByteLength - before(function () { - txByteLength = sinon.stub(Transaction.prototype, 'byteLength') - }) - - after(function () { - Transaction.prototype.byteLength.restore() - }) - - describe('constants', function () { - fixtures.valid.constants.forEach(function (f) { - var network = networks[f.network] - - Object.keys(f.bip32).forEach(function (name) { - var extb58 = f.bip32[name] - - it('resolves ' + extb58 + ' to ' + f.network, function () { - assert.equal(HDNode.fromBase58(extb58).network, network) - }) - }) - }) - }) - - describe('estimateFee', function () { - fixtures.valid.estimateFee.forEach(function (f) { - describe('(' + f.network + ')', function () { - var network = networks[f.network] - - it('calculates the fee correctly for ' + f.description, function () { - txByteLength.returns(f.txSize) + fixtures.forEach(function (f) { + var network = networks[f.network] - var estimateFee = network.estimateFee - var tx = new Transaction() - tx.outs = f.outputs || [] + Object.keys(f.bip32).forEach(function (name) { + var extb58 = f.bip32[name] - assert.equal(estimateFee(tx), f.fee) - }) + it(extb58 + ' auto-detects ' + f.network, function () { + assert.equal(HDNode.fromBase58(extb58).network, network) }) }) }) From b5c42303fffa88b4a9d4af41553c682f9e246ef2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 17 Mar 2015 12:31:53 +1100 Subject: [PATCH 42/64] crypto: use packages directly --- package.json | 5 ++++- src/crypto.js | 8 ++++---- src/ecdsa.js | 18 +++++++++--------- src/eckey.js | 6 +++--- src/hdnode.js | 6 +++--- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 6e6a229b2..454bf6d1c 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,11 @@ }, "dependencies": { "bigi": "^1.4.0", - "bs58check": "^1.0.4", + "bs58check": "^1.0.5", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.3", "ecurve": "^1.0.0", + "randombytes": "^2.0.1", "typeforce": "^1.0.0" }, "devDependencies": { diff --git a/src/crypto.js b/src/crypto.js index dec8a79bf..3c1cb7386 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -1,4 +1,4 @@ -var crypto = require('crypto') +var createHash = require('create-hash') function hash160 (buffer) { return ripemd160(sha256(buffer)) @@ -9,15 +9,15 @@ function hash256 (buffer) { } function ripemd160 (buffer) { - return crypto.createHash('rmd160').update(buffer).digest() + return createHash('rmd160').update(buffer).digest() } function sha1 (buffer) { - return crypto.createHash('sha1').update(buffer).digest() + return createHash('sha1').update(buffer).digest() } function sha256 (buffer) { - return crypto.createHash('sha256').update(buffer).digest() + return createHash('sha256').update(buffer).digest() } module.exports = { diff --git a/src/ecdsa.js b/src/ecdsa.js index 0455d198b..c88add3f5 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -1,5 +1,5 @@ var assert = require('assert') -var crypto = require('crypto') +var createHmac = require('create-hmac') var typeForce = require('typeforce') var BigInteger = require('bigi') @@ -29,7 +29,7 @@ function deterministicGenerateK (curve, hash, d, checkSig) { k.fill(0) // Step D - k = crypto.createHmac('sha256', k) + k = createHmac('sha256', k) .update(v) .update(ZERO) .update(x) @@ -37,10 +37,10 @@ function deterministicGenerateK (curve, hash, d, checkSig) { .digest() // Step E - v = crypto.createHmac('sha256', k).update(v).digest() + v = createHmac('sha256', k).update(v).digest() // Step F - k = crypto.createHmac('sha256', k) + k = createHmac('sha256', k) .update(v) .update(ONE) .update(x) @@ -48,26 +48,26 @@ function deterministicGenerateK (curve, hash, d, checkSig) { .digest() // Step G - v = crypto.createHmac('sha256', k).update(v).digest() + v = createHmac('sha256', k).update(v).digest() // Step H1/H2a, ignored as tlen === qlen (256 bit) // Step H2b - v = crypto.createHmac('sha256', k).update(v).digest() + v = createHmac('sha256', k).update(v).digest() var T = BigInteger.fromBuffer(v) // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) { - k = crypto.createHmac('sha256', k) + k = createHmac('sha256', k) .update(v) .update(ZERO) .digest() - v = crypto.createHmac('sha256', k).update(v).digest() + v = createHmac('sha256', k).update(v).digest() // Step H1/H2a, again, ignored as tlen === qlen (256 bit) // Step H2b again - v = crypto.createHmac('sha256', k).update(v).digest() + v = createHmac('sha256', k).update(v).digest() T = BigInteger.fromBuffer(v) } diff --git a/src/eckey.js b/src/eckey.js index af7fda20b..06bed6a51 100644 --- a/src/eckey.js +++ b/src/eckey.js @@ -1,9 +1,9 @@ var assert = require('assert') var base58check = require('bs58check') -var crypto = require('crypto') var ecdsa = require('./ecdsa') -var typeForce = require('typeforce') var networks = require('./networks') +var randomBytes = require('randombytes') +var typeForce = require('typeforce') var BigInteger = require('bigi') var ECPubKey = require('./ecpubkey') @@ -47,7 +47,7 @@ ECKey.fromWIF = function (string) { } ECKey.makeRandom = function (compressed, rng) { - rng = rng || crypto.randomBytes + rng = rng || randomBytes var buffer = rng(32) typeForce('Buffer', buffer) diff --git a/src/hdnode.js b/src/hdnode.js index f0aa61399..9152e1dac 100644 --- a/src/hdnode.js +++ b/src/hdnode.js @@ -1,7 +1,7 @@ var assert = require('assert') var base58check = require('bs58check') var bcrypto = require('./crypto') -var crypto = require('crypto') +var createHmac = require('create-hmac') var typeForce = require('typeforce') var networks = require('./networks') @@ -62,7 +62,7 @@ HDNode.fromSeedBuffer = function (seed, network) { assert(seed.length >= 16, 'Seed should be at least 128 bits') assert(seed.length <= 64, 'Seed should be at most 512 bits') - var I = crypto.createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() + var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() var IL = I.slice(0, 32) var IR = I.slice(32) @@ -225,7 +225,7 @@ HDNode.prototype.derive = function (index) { ]) } - var I = crypto.createHmac('sha512', this.chainCode).update(data).digest() + var I = createHmac('sha512', this.chainCode).update(data).digest() var IL = I.slice(0, 32) var IR = I.slice(32) From 64e206ca7af9b6e9bd29c4d6bdef6def7be4cc5c Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Wed, 18 Mar 2015 23:30:04 +0800 Subject: [PATCH 43/64] crypto: fix test randomBytes stub --- package.json | 1 + test/eckey.js | 33 +++++++++++++-------------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 454bf6d1c..fd14bf992 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "coveralls": "^2.11.2", "istanbul": "^0.3.5", "mocha": "^2.2.0", + "proxyquire": "^1.4.0", "sinon": "^1.12.2", "standard": "^2.11.0" } diff --git a/test/eckey.js b/test/eckey.js index 16ce3d0cb..e3dbe4415 100644 --- a/test/eckey.js +++ b/test/eckey.js @@ -2,10 +2,10 @@ /* eslint-disable no-new */ var assert = require('assert') -var crypto = require('crypto') var ecurve = require('ecurve') var networks = require('../src/networks') -var sinon = require('sinon') +var proxyquire = require('proxyquire') +var randomBytes = require('randombytes') var BigInteger = require('bigi') var ECKey = require('../src/eckey') @@ -101,25 +101,13 @@ describe('ECKey', function () { var exPrivKey = ECKey.fromWIF(exWIF) var exBuffer = exPrivKey.d.toBuffer(32) - describe('uses default crypto RNG', function () { - beforeEach(function () { - sinon.stub(crypto, 'randomBytes').returns(exBuffer) - }) - - afterEach(function () { - crypto.randomBytes.restore() - }) + it("uses the RNG provided by the 'randombytes' module by default", function () { + var stub = { randombytes: function() { return exBuffer } } + var ProxiedECKey = proxyquire('../src/eckey', stub) - it('generates a ECKey', function () { - var privKey = ECKey.makeRandom() - - assert.equal(privKey.toWIF(), exWIF) - }) + var privKey = ProxiedECKey.makeRandom() - it('supports compression', function () { - assert.equal(ECKey.makeRandom(true).pub.compressed, true) - assert.equal(ECKey.makeRandom(false).pub.compressed, false) - }) + assert.equal(privKey.toWIF(), exWIF) }) it('allows a custom RNG to be used', function () { @@ -130,10 +118,15 @@ describe('ECKey', function () { var privKey = ECKey.makeRandom(undefined, rng) assert.equal(privKey.toWIF(), exWIF) }) + + it('supports compression', function () { + assert.equal(ECKey.makeRandom(true).pub.compressed, true) + assert.equal(ECKey.makeRandom(false).pub.compressed, false) + }) }) describe('signing', function () { - var hash = crypto.randomBytes(32) + var hash = randomBytes(32) var priv = ECKey.makeRandom() var signature = priv.sign(hash) From 689f444bdf423af9a5241eabfd96c9c98573f363 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 19 Mar 2015 11:08:56 +1100 Subject: [PATCH 44/64] tests: fix standard format adherence --- test/eckey.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/eckey.js b/test/eckey.js index e3dbe4415..0e56fb54b 100644 --- a/test/eckey.js +++ b/test/eckey.js @@ -1,10 +1,10 @@ -/* global describe, it, beforeEach, afterEach */ +/* global describe, it */ /* eslint-disable no-new */ var assert = require('assert') var ecurve = require('ecurve') var networks = require('../src/networks') -var proxyquire = require('proxyquire') +var proxyquire = require('proxyquire') var randomBytes = require('randombytes') var BigInteger = require('bigi') @@ -102,7 +102,7 @@ describe('ECKey', function () { var exBuffer = exPrivKey.d.toBuffer(32) it("uses the RNG provided by the 'randombytes' module by default", function () { - var stub = { randombytes: function() { return exBuffer } } + var stub = { randombytes: function () { return exBuffer } } var ProxiedECKey = proxyquire('../src/eckey', stub) var privKey = ProxiedECKey.makeRandom() From b55874718a5ead88778d844339bb60ccbc9253a8 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 19 Mar 2015 11:15:51 +1100 Subject: [PATCH 45/64] integration: use an rng for the example over mocking --- test/integration/basic.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/integration/basic.js b/test/integration/basic.js index 069a535e0..7a7688975 100644 --- a/test/integration/basic.js +++ b/test/integration/basic.js @@ -3,21 +3,18 @@ var assert = require('assert') var bigi = require('bigi') var bitcoin = require('../../') -var crypto = require('crypto') -var sinon = require('sinon') describe('bitcoinjs-lib (basic)', function () { - it('can generate a random bitcoin address', sinon.test(function () { + it('can generate a random bitcoin address', function () { // for testing only - this.mock(crypto).expects('randomBytes') - .onCall(0).returns(new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')) + function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } - // generate random key - var key = bitcoin.ECKey.makeRandom() + // generate random key (custom rng for testing only) + var key = bitcoin.ECKey.makeRandom(undefined, rng) var address = key.pub.getAddress().toString() assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') - })) + }) it('can generate an address from a SHA256 hash', function () { var hash = bitcoin.crypto.sha256('correct horse battery staple') From 7559ee880d6945eb7b3b554543e0ae66314b315d Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 17 Oct 2014 13:31:01 +1100 Subject: [PATCH 46/64] add ECPair module --- src/ecpair.js | 142 +++++++++++++++++++++++ test/ecpair.js | 234 ++++++++++++++++++++++++++++++++++++++ test/fixtures/ecpair.json | 102 +++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 src/ecpair.js create mode 100644 test/ecpair.js create mode 100644 test/fixtures/ecpair.json diff --git a/src/ecpair.js b/src/ecpair.js new file mode 100644 index 000000000..b4ecf485f --- /dev/null +++ b/src/ecpair.js @@ -0,0 +1,142 @@ +var assert = require('assert') +var base58check = require('bs58check') +var bcrypto = require('./crypto') +var ecdsa = require('./ecdsa') +var ecurve = require('ecurve') +var networks = require('./networks') +var randomBytes = require('randombytes') +var typeForce = require('typeforce') + +var Address = require('./address') +var BigInteger = require('bigi') + +function findNetworkByWIFVersion (version) { + for (var networkName in networks) { + var network = networks[networkName] + + if (network.wif === version) return network + } + + assert(false, 'Unknown network') +} + +function ECPair (d, Q, options) { + options = options || {} + + var compressed = options.compressed === undefined ? true : options.compressed + var network = options.network === undefined ? networks.bitcoin : options.network + + typeForce('Boolean', compressed) + assert('pubKeyHash' in network, 'Unknown pubKeyHash constants for network') + + if (d) { + assert(d.signum() > 0, 'Private key must be greater than 0') + assert(d.compareTo(ECPair.curve.n) < 0, 'Private key must be less than the curve order') + + assert(!Q, 'Unexpected publicKey parameter') + Q = ECPair.curve.G.multiply(d) + + // enforce Q is a public key if no private key given + } else { + typeForce('Point', Q) + } + + this.compressed = compressed + this.d = d + this.Q = Q + this.network = network +} + +// Public access to secp256k1 curve +ECPair.curve = ecurve.getCurveByName('secp256k1') + +ECPair.fromPublicKeyBuffer = function (buffer, network) { + var Q = ecurve.Point.decodeFrom(ECPair.curve, buffer) + + return new ECPair(null, Q, { + compressed: Q.compressed, + network: network + }) +} + +ECPair.fromWIF = function (string) { + var payload = base58check.decode(string) + var version = payload.readUInt8(0) + var compressed + + if (payload.length === 34) { + assert.strictEqual(payload[33], 0x01, 'Invalid compression flag') + + // truncate the version/compression bytes + payload = payload.slice(1, -1) + compressed = true + + // no compression flag + } else { + assert.equal(payload.length, 33, 'Invalid WIF payload length') + + // Truncate the version byte + payload = payload.slice(1) + compressed = false + } + + var network = findNetworkByWIFVersion(version) + var d = BigInteger.fromBuffer(payload) + + return new ECPair(d, null, { + compressed: compressed, + network: network + }) +} + +ECPair.makeRandom = function (options) { + options = options || {} + + var rng = options.rng || randomBytes + var buffer = rng(32) + typeForce('Buffer', buffer) + assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG') + + var d = BigInteger.fromBuffer(buffer) + d = d.mod(ECPair.curve.n) + + return new ECPair(d, null, options) +} + +ECPair.prototype.toWIF = function () { + assert(this.d, 'Missing private key') + + var bufferLen = this.compressed ? 34 : 33 + var buffer = new Buffer(bufferLen) + + buffer.writeUInt8(this.network.wif, 0) + this.d.toBuffer(32).copy(buffer, 1) + + if (this.compressed) { + buffer.writeUInt8(0x01, 33) + } + + return base58check.encode(buffer) +} + +ECPair.prototype.getAddress = function () { + var pubKey = this.getPublicKeyBuffer() + + return new Address(bcrypto.hash160(pubKey), this.network.pubKeyHash) +} + +ECPair.prototype.getPublicKeyBuffer = function () { + return this.Q.getEncoded(this.compressed) +} + +ECPair.prototype.sign = function (hash) { + assert(this.d, 'Missing private key') + + return ecdsa.sign(ECPair.curve, hash, this.d) +} + +ECPair.prototype.verify = function (hash, signature) { + return ecdsa.verify(ECPair.curve, hash, signature, this.Q) +} + +module.exports = ECPair diff --git a/test/ecpair.js b/test/ecpair.js new file mode 100644 index 000000000..9135284d7 --- /dev/null +++ b/test/ecpair.js @@ -0,0 +1,234 @@ +/* global describe, it, beforeEach */ +/* eslint-disable no-new */ + +var assert = require('assert') +var ecdsa = require('../src/ecdsa') +var ecurve = require('ecurve') +var networks = require('../src/networks') +var proxyquire = require('proxyquire') +var sinon = require('sinon') + +var BigInteger = require('bigi') +var ECPair = require('../src/ecpair') + +var fixtures = require('./fixtures/ecpair.json') + +describe('ECPair', function () { + describe('constructor', function () { + it('defaults to compressed', function () { + var keyPair = new ECPair(BigInteger.ONE) + + assert.equal(keyPair.compressed, true) + }) + + it('supports the uncompressed option', function () { + var keyPair = new ECPair(BigInteger.ONE, null, { + compressed: false + }) + + assert.equal(keyPair.compressed, false) + }) + + it('supports the network option', function () { + var keyPair = new ECPair(BigInteger.ONE, null, { + compressed: false, + network: networks.testnet + }) + + assert.equal(keyPair.network, networks.testnet) + }) + + it('throws if compressed option is not a bool', function () { + assert.throws(function () { + new ECPair(null, null, { + compressed: 2 + }, /Expected Boolean, got 2/) + }) + }) + + it('throws if public and private key given', function () { + var qBuffer = new Buffer('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 'hex') + var Q = ecurve.Point.decodeFrom(ECPair.curve, qBuffer) + + assert.throws(function () { + new ECPair(BigInteger.ONE, Q) + }, /Unexpected publicKey parameter/) + }) + + it('throws if network is missing pubKeyHash constants', function () { + assert.throws(function () { + new ECPair(null, null, { + network: {} + }, /Unknown pubKeyHash constants for network/) + }) + }) + + fixtures.valid.forEach(function (f) { + it('calculates the public point for ' + f.WIF, function () { + var d = new BigInteger(f.d) + var keyPair = new ECPair(d, null, { + compressed: f.compressed + }) + + assert.equal(keyPair.getPublicKeyBuffer().toString('hex'), f.Q) + }) + }) + + fixtures.invalid.constructor.forEach(function (f) { + it('throws on ' + f.d, function () { + var d = new BigInteger(f.d) + + assert.throws(function () { + new ECPair(d) + }, new RegExp(f.exception)) + }) + }) + }) + + describe('getPublicKeyBuffer', function () { + var keyPair + + beforeEach(function () { + keyPair = new ECPair(BigInteger.ONE) + }) + + it('wraps Q.getEncoded', sinon.test(function () { + this.mock(keyPair.Q).expects('getEncoded') + .once().calledWith(keyPair.compressed) + + keyPair.getPublicKeyBuffer() + })) + }) + + describe('fromWIF', function () { + fixtures.valid.forEach(function (f) { + it('imports ' + f.WIF + ' correctly', function () { + var keyPair = ECPair.fromWIF(f.WIF) + + assert.equal(keyPair.d.toString(), f.d) + assert.equal(keyPair.compressed, f.compressed) + assert.equal(keyPair.network, networks[f.network]) + }) + }) + + fixtures.invalid.fromWIF.forEach(function (f) { + it('throws on ' + f.string, function () { + assert.throws(function () { + ECPair.fromWIF(f.string) + }, new RegExp(f.exception)) + }) + }) + }) + + describe('toWIF', function () { + fixtures.valid.forEach(function (f) { + it('exports ' + f.WIF + ' correctly', function () { + var keyPair = ECPair.fromWIF(f.WIF) + var result = keyPair.toWIF() + + assert.equal(result, f.WIF) + }) + }) + }) + + describe('makeRandom', function () { + var d = new Buffer('0404040404040404040404040404040404040404040404040404040404040404', 'hex') + var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' + + describe('uses randombytes RNG', function () { + it('generates a ECPair', function () { + var stub = { randombytes: function () { return d } } + var ProxiedECPair = proxyquire('../src/ecpair', stub) + + var keyPair = ProxiedECPair.makeRandom() + assert.equal(keyPair.toWIF(), exWIF) + }) + + it('passes the options param', sinon.test(function () { + var options = { + compressed: true + } + + // FIXME: waiting on https://github.com/cjohansen/Sinon.JS/issues/613 +// this.mock(ECPair).expects('constructor') +// .once().calledWith(options) + + ECPair.makeRandom(options) + })) + }) + + it('allows a custom RNG to be used', function () { + var keyPair = ECPair.makeRandom({ + rng: function (size) { return d.slice(0, size) } + }) + + assert.equal(keyPair.toWIF(), exWIF) + }) + }) + + describe('getAddress', function () { + fixtures.valid.forEach(function (f) { + it('returns ' + f.address + ' for ' + f.WIF, function () { + var keyPair = ECPair.fromWIF(f.WIF) + + assert.equal(keyPair.getAddress().toString(), f.address) + }) + }) + }) + + describe('ecdsa wrappers', function () { + var keyPair, hash + + beforeEach(function () { + keyPair = ECPair.makeRandom() + hash = new Buffer(32) + }) + + it('uses the secp256k1 curve by default', function () { + var secp256k1 = ecurve.getCurveByName('secp256k1') + + for (var property in secp256k1) { + // FIXME: circular structures in ecurve + if (property === 'G') continue + if (property === 'infinity') continue + + var actual = ECPair.curve[property] + var expected = secp256k1[property] + + assert.deepEqual(actual, expected) + } + }) + + describe('signing', function () { + it('wraps ecdsa.sign', sinon.test(function () { + this.mock(ecdsa).expects('sign') + .once().calledWith(ECPair.curve, hash, keyPair.d) + + keyPair.sign(hash) + })) + + it('throws if no private key is found', function () { + keyPair.d = null + + assert.throws(function () { + keyPair.sign(hash) + }, /Missing private key/) + }) + }) + + describe('verify', function () { + var signature + + beforeEach(function () { + signature = keyPair.sign(hash) + }) + + it('wraps ecdsa.verify', sinon.test(function () { + this.mock(ecdsa).expects('verify') + .once().calledWith(ECPair.curve, hash, signature, keyPair.Q) + + keyPair.verify(hash, signature) + })) + }) + }) +}) diff --git a/test/fixtures/ecpair.json b/test/fixtures/ecpair.json new file mode 100644 index 000000000..bc117e618 --- /dev/null +++ b/test/fixtures/ecpair.json @@ -0,0 +1,102 @@ +{ + "valid": [ + { + "d": "1", + "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "compressed": true, + "network": "bitcoin", + "address": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", + "WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + }, + { + "d": "1", + "Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "compressed": false, + "network": "bitcoin", + "address": "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm", + "WIF": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf" + }, + { + "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102", + "Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340", + "compressed": true, + "network": "bitcoin", + "address": "1MasfEKgSiaSeri2C6kgznaqBNtyrZPhNq", + "WIF": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o" + }, + { + "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", + "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34", + "compressed": true, + "network": "bitcoin", + "address": "1LwwMWdSEMHJ2dMhSvAHZ3g95tG2UBv9jg", + "WIF": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx" + }, + { + "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", + "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6", + "compressed": false, + "network": "bitcoin", + "address": "1zXcfvKCLgsFdJDYPuqpu1sF3q92tnnUM", + "WIF": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh" + }, + { + "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", + "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34", + "compressed": true, + "network": "testnet", + "address": "n1TteZiR3NiYojqKAV8fNxtTwsrjM7kVdj", + "WIF": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv" + }, + { + "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", + "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6", + "compressed": false, + "network": "testnet", + "address": "mgWUuj1J1N882jmqFxtDepEC73Rr22E9GU", + "WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj" + }, + { + "d": "115792089237316195423570985008687907852837564279074904382605163141518161494336", + "Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "compressed": true, + "network": "bitcoin", + "address": "1GrLCmVQXoyJXaPJQdqssNqwxvha1eUo2E", + "WIF": "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9" + } + ], + "invalid": { + "constructor": [ + { + "exception": "Private key must be greater than 0", + "d": "-1" + }, + { + "exception": "Private key must be greater than 0", + "d": "0" + }, + { + "exception": "Private key must be less than the curve order", + "d": "115792089237316195423570985008687907852837564279074904382605163141518161494337" + }, + { + "exception": "Private key must be less than the curve order", + "d": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + } + ], + "fromWIF": [ + { + "exception": "Invalid compression flag", + "string": "ju9rooVsmagsb4qmNyTysUSFB1GB6MdpD7eoGjUTPmZRAApJxRz" + }, + { + "exception": "Invalid WIF payload length", + "string": "7ZEtRQLhCsDQrd6ZKfmcESdXgas8ggZPN24ByEi5ey6VJW" + }, + { + "exception": "Invalid WIF payload length", + "string": "5qibUKwsnMo1qDiNp3prGaQkD2JfVJa8F8Na87H2CkMHvuVg6uKhw67Rh" + } + ] + } +} From 31832293ddb92f4b61e82e0756a16d6bcdb60ac8 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 19 Mar 2015 13:25:41 +1100 Subject: [PATCH 47/64] ECPair: lazily calculate Q --- src/ecpair.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ecpair.js b/src/ecpair.js index b4ecf485f..7f340b467 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -34,19 +34,28 @@ function ECPair (d, Q, options) { assert(d.compareTo(ECPair.curve.n) < 0, 'Private key must be less than the curve order') assert(!Q, 'Unexpected publicKey parameter') - Q = ECPair.curve.G.multiply(d) + this.d = d // enforce Q is a public key if no private key given } else { typeForce('Point', Q) + this.__Q = Q } this.compressed = compressed - this.d = d - this.Q = Q this.network = network } +Object.defineProperty(ECPair.prototype, 'Q', { + get: function() { + if (!this.__Q && this.d) { + this.__Q = ECPair.curve.G.multiply(this.d) + } + + return this.__Q + } +}) + // Public access to secp256k1 curve ECPair.curve = ecurve.getCurveByName('secp256k1') From 4c8b0f38eae6f4bb9f63fb9e77ee54964a41d5a3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 2 Mar 2015 16:48:36 +1100 Subject: [PATCH 48/64] replace ECKey/ECPubKey with ECPair --- src/hdnode.js | 91 ++++++++-------- src/index.js | 3 +- src/message.js | 17 +-- src/scripts.js | 15 ++- src/transaction_builder.js | 41 +++---- test/bitcoin.core.js | 27 +++-- test/eckey.js | 143 ------------------------- test/ecpubkey.js | 120 --------------------- test/fixtures/eckey.json | 102 ------------------ test/fixtures/ecpubkey.json | 19 ---- test/fixtures/transaction_builder.json | 94 ++++++++-------- test/hdnode.js | 115 +++++++------------- test/integration/advanced.js | 12 ++- test/integration/basic.js | 19 ++-- test/integration/crypto.js | 38 +++---- test/integration/multisig.js | 24 +++-- test/message.js | 10 +- test/networks.js | 2 +- test/scripts.js | 17 +-- test/transaction_builder.js | 27 ++--- 20 files changed, 266 insertions(+), 670 deletions(-) delete mode 100644 test/eckey.js delete mode 100644 test/ecpubkey.js delete mode 100644 test/fixtures/eckey.json delete mode 100644 test/fixtures/ecpubkey.json diff --git a/src/hdnode.js b/src/hdnode.js index 9152e1dac..49f5ae4e1 100644 --- a/src/hdnode.js +++ b/src/hdnode.js @@ -6,8 +6,7 @@ var typeForce = require('typeforce') var networks = require('./networks') var BigInteger = require('bigi') -var ECKey = require('./eckey') -var ECPubKey = require('./ecpubkey') +var ECPair = require('./ecpair') var ecurve = require('ecurve') var curve = ecurve.getCurveByName('secp256k1') @@ -24,32 +23,19 @@ function findBIP32NetworkByVersion (version) { assert(false, 'Could not find network for ' + version.toString(16)) } -function HDNode (K, chainCode, network) { - network = network || networks.bitcoin - +function HDNode (keyPair, chainCode) { + typeForce('ECPair', keyPair) typeForce('Buffer', chainCode) assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length) - assert(network.bip32, 'Unknown BIP32 constants for network') + assert('bip32' in keyPair.network, 'Unknown BIP32 constants for network') + assert.equal(keyPair.compressed, true, 'BIP32 only allows compressed keyPairs') + this.keyPair = keyPair this.chainCode = chainCode this.depth = 0 this.index = 0 this.parentFingerprint = 0x00000000 - this.network = network - - if (K instanceof BigInteger) { - this.privKey = new ECKey(K, true) - this.pubKey = this.privKey.pub - } else if (K instanceof ECKey) { - assert(K.pub.compressed, 'ECKey must be compressed') - this.privKey = K - } else if (K instanceof ECPubKey) { - assert(K.compressed, 'ECPubKey must be compressed') - this.pubKey = K - } else { - this.pubKey = new ECPubKey(K, true) - } } HDNode.MASTER_SECRET = new Buffer('Bitcoin seed') @@ -67,10 +53,13 @@ HDNode.fromSeedBuffer = function (seed, network) { var IR = I.slice(32) // In case IL is 0 or >= n, the master key is invalid - // This is handled by `new ECKey` in the HDNode constructor + // This is handled by the ECPair constructor var pIL = BigInteger.fromBuffer(IL) + var keyPair = new ECPair(pIL, null, { + network: network + }) - return new HDNode(pIL, IR, network) + return new HDNode(keyPair, IR) } HDNode.fromSeedHex = function (hex, network) { @@ -108,14 +97,17 @@ HDNode.fromBase58 = function (string, network) { // 32 bytes: the chain code var chainCode = buffer.slice(13, 45) - var data, hd + var data, keyPair - // 33 bytes: private key data (0x00 + k) + // 33 bytes: private key data (0x00 + k) if (version === network.bip32.private) { assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key') data = buffer.slice(46, 78) var d = BigInteger.fromBuffer(data) - hd = new HDNode(d, chainCode, network) + + keyPair = new ECPair(d, null, { + network: network + }) // 33 bytes: public key data (0x02 + X or 0x03 + X) } else { @@ -127,9 +119,12 @@ HDNode.fromBase58 = function (string, network) { // If not, the extended public key is invalid. curve.validate(Q) - hd = new HDNode(Q, chainCode, network) + keyPair = new ECPair(null, Q, { + network: network + }) } + var hd = new HDNode(keyPair, chainCode) hd.depth = depth hd.index = index hd.parentFingerprint = parentFingerprint @@ -138,7 +133,7 @@ HDNode.fromBase58 = function (string, network) { } HDNode.prototype.getIdentifier = function () { - return bcrypto.hash160(this.pubKey.toBuffer()) + return bcrypto.hash160(this.keyPair.getPublicKeyBuffer()) } HDNode.prototype.getFingerprint = function () { @@ -146,11 +141,15 @@ HDNode.prototype.getFingerprint = function () { } HDNode.prototype.getAddress = function () { - return this.pubKey.getAddress(this.network) + return this.keyPair.getAddress() } HDNode.prototype.neutered = function () { - var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network) + var neuteredKeyPair = new ECPair(null, this.keyPair.Q, { + network: this.keyPair.network + }) + + var neutered = new HDNode(neuteredKeyPair, this.chainCode) neutered.depth = this.depth neutered.index = this.index neutered.parentFingerprint = this.parentFingerprint @@ -162,7 +161,8 @@ HDNode.prototype.toBase58 = function (__isPrivate) { assert.strictEqual(__isPrivate, undefined, 'Unsupported argument in 2.0.0') // Version - var version = this.privKey ? this.network.bip32.private : this.network.bip32.public + var network = this.keyPair.network + var version = this.keyPair.d ? network.bip32.private : network.bip32.public var buffer = new Buffer(HDNode.LENGTH) // 4 bytes: version bytes @@ -182,16 +182,16 @@ HDNode.prototype.toBase58 = function (__isPrivate) { // 32 bytes: the chain code this.chainCode.copy(buffer, 13) - // 33 bytes: the private key, or - if (this.privKey) { + // 33 bytes: the public key or private key data + if (this.keyPair.d) { // 0x00 + k for private keys buffer.writeUInt8(0, 45) - this.privKey.d.toBuffer(32).copy(buffer, 46) + this.keyPair.d.toBuffer(32).copy(buffer, 46) // 33 bytes: the public key } else { // X9.62 encoding for public keys - this.pubKey.toBuffer().copy(buffer, 45) + this.keyPair.getPublicKeyBuffer().copy(buffer, 45) } return base58check.encode(buffer) @@ -207,11 +207,11 @@ HDNode.prototype.derive = function (index) { // Hardened child if (isHardened) { - assert(this.privKey, 'Could not derive hardened child key') + assert(this.keyPair.d, 'Could not derive hardened child key') // data = 0x00 || ser256(kpar) || ser32(index) data = Buffer.concat([ - this.privKey.d.toBuffer(33), + this.keyPair.d.toBuffer(33), indexBuffer ]) @@ -220,7 +220,7 @@ HDNode.prototype.derive = function (index) { // data = serP(point(kpar)) || ser32(index) // = serP(Kpar) || ser32(index) data = Buffer.concat([ - this.pubKey.toBuffer(), + this.keyPair.getPublicKeyBuffer(), indexBuffer ]) } @@ -237,32 +237,37 @@ HDNode.prototype.derive = function (index) { } // Private parent key -> private child key - var hd - if (this.privKey) { + var derivedKeyPair + if (this.keyPair.d) { // ki = parse256(IL) + kpar (mod n) - var ki = pIL.add(this.privKey.d).mod(curve.n) + var ki = pIL.add(this.keyPair.d).mod(curve.n) // In case ki == 0, proceed with the next value for i if (ki.signum() === 0) { return this.derive(index + 1) } - hd = new HDNode(ki, IR, this.network) + derivedKeyPair = new ECPair(ki, null, { + network: this.keyPair.network + }) // Public parent key -> public child key } else { // Ki = point(parse256(IL)) + Kpar // = G*IL + Kpar - var Ki = curve.G.multiply(pIL).add(this.pubKey.Q) + var Ki = curve.G.multiply(pIL).add(this.keyPair.Q) // In case Ki is the point at infinity, proceed with the next value for i if (curve.isInfinity(Ki)) { return this.derive(index + 1) } - hd = new HDNode(Ki, IR, this.network) + derivedKeyPair = new ECPair(null, Ki, { + network: this.keyPair.network + }) } + var hd = new HDNode(derivedKeyPair, IR) hd.depth = this.depth + 1 hd.index = index hd.parentFingerprint = this.getFingerprint().readUInt32BE(0) diff --git a/src/index.js b/src/index.js index 3b5317bce..2819bd299 100644 --- a/src/index.js +++ b/src/index.js @@ -4,8 +4,7 @@ module.exports = { bufferutils: require('./bufferutils'), crypto: require('./crypto'), ecdsa: require('./ecdsa'), - ECKey: require('./eckey'), - ECPubKey: require('./ecpubkey'), + ECPair: require('./ecpair'), ECSignature: require('./ecsignature'), message: require('./message'), opcodes: require('./opcodes'), diff --git a/src/message.js b/src/message.js index a210c766e..f3791feac 100644 --- a/src/message.js +++ b/src/message.js @@ -4,7 +4,7 @@ var ecdsa = require('./ecdsa') var networks = require('./networks') var BigInteger = require('bigi') -var ECPubKey = require('./ecpubkey') +var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') var ecurve = require('ecurve') @@ -19,15 +19,15 @@ function magicHash (message, network) { return crypto.hash256(buffer) } -function sign (privKey, message, network) { +function sign (keyPair, message, network) { network = network || networks.bitcoin var hash = magicHash(message, network) - var signature = privKey.sign(hash) + var signature = keyPair.sign(hash) var e = BigInteger.fromBuffer(hash) - var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, privKey.pub.Q) + var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, keyPair.Q) - return signature.toCompact(i, privKey.pub.compressed) + return signature.toCompact(i, keyPair.compressed) } // TODO: network could be implied from address @@ -42,9 +42,12 @@ function verify (address, signature, message, network) { var parsed = ECSignature.parseCompact(signature) var e = BigInteger.fromBuffer(hash) var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i) + var keyPair = new ECPair(null, Q, { + compressed: parsed.compressed, + network: network + }) - var pubKey = new ECPubKey(Q, parsed.compressed) - return pubKey.getAddress(network).toString() === address.toString() + return keyPair.getAddress().toString() === address.toString() } module.exports = { diff --git a/src/scripts.js b/src/scripts.js index 63d35020e..fde409f45 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -170,7 +170,7 @@ function classifyInput (script, allowIncomplete) { // {pubKey} OP_CHECKSIG function pubKeyOutput (pubKey) { return Script.fromChunks([ - pubKey.toBuffer(), + pubKey, ops.OP_CHECKSIG ]) } @@ -201,18 +201,14 @@ function scriptHashOutput (hash) { // m [pubKeys ...] n OP_CHECKMULTISIG function multisigOutput (m, pubKeys) { - typeForce(['ECPubKey'], pubKeys) + typeForce(['Buffer'], pubKeys) - assert(pubKeys.length >= m, 'Not enough pubKeys provided') - - var pubKeyBuffers = pubKeys.map(function (pubKey) { - return pubKey.toBuffer() - }) var n = pubKeys.length + assert(n >= m, 'Not enough pubKeys provided') return Script.fromChunks([].concat( (ops.OP_1 - 1) + m, - pubKeyBuffers, + pubKeys, (ops.OP_1 - 1) + n, ops.OP_CHECKMULTISIG )) @@ -228,8 +224,9 @@ function pubKeyInput (signature) { // {signature} {pubKey} function pubKeyHashInput (signature, pubKey) { typeForce('Buffer', signature) + typeForce('Buffer', pubKey) - return Script.fromChunks([signature, pubKey.toBuffer()]) + return Script.fromChunks([signature, pubKey]) } // {serialized scriptPubKey script} diff --git a/src/transaction_builder.js b/src/transaction_builder.js index f4d9923f3..a08af7202 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -1,9 +1,10 @@ var assert = require('assert') +var bufferutils = require('./bufferutils') var ops = require('./opcodes') var scripts = require('./scripts') var Address = require('./address') -var ECPubKey = require('./ecpubkey') +var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') var Script = require('./script') var Transaction = require('./transaction') @@ -33,9 +34,9 @@ function extractInput (txIn) { case 'pubkeyhash': { parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0]) hashType = parsed.hashType - pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])] + pubKeys = scriptSig.chunks.slice(1) signatures = [parsed.signature] - prevOutScript = pubKeys[0].getAddress().toOutputScript() + prevOutScript = ECPair.fromPublicKeyBuffer(pubKeys[0]).getAddress().toOutputScript() break } @@ -46,7 +47,7 @@ function extractInput (txIn) { signatures = [parsed.signature] if (redeemScript) { - pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])] + pubKeys = redeemScript.chunks.slice(0, 1) } break @@ -63,7 +64,7 @@ function extractInput (txIn) { }) if (redeemScript) { - pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + pubKeys = redeemScript.chunks.slice(1, -2) } break @@ -141,12 +142,12 @@ TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOu // if we can, extract pubKey information switch (prevOutType) { case 'multisig': { - input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + input.pubKeys = prevOutScript.chunks.slice(1, -2) break } case 'pubkey': { - input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) + input.pubKeys = prevOutScript.chunks.slice(0, 1) break } } @@ -280,7 +281,7 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { return tx } -TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hashType) { +TransactionBuilder.prototype.sign = function (index, keyPair, redeemScript, hashType) { assert(index in this.inputs, 'No input at index: ' + index) hashType = hashType || Transaction.SIGHASH_ALL @@ -292,6 +293,8 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash input.scriptType && input.signatures + var kpPubKey = keyPair.getPublicKeyBuffer() + // are we almost ready to sign? if (canSign) { // if redeemScript was provided, enforce consistency @@ -319,21 +322,21 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash var pubKeys = [] switch (scriptType) { case 'multisig': { - pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + pubKeys = redeemScript.chunks.slice(1, -2) break } case 'pubkeyhash': { var pkh1 = redeemScript.chunks[2] - var pkh2 = privKey.pub.getAddress().hash + var pkh2 = keyPair.getAddress().hash assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input') - pubKeys = [privKey.pub] + pubKeys = [kpPubKey] break } case 'pubkey': { - pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) + pubKeys = redeemScript.chunks.slice(0, 1) break } } @@ -357,9 +360,9 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash // we know nothin' Jon Snow, assume pubKeyHash } else { - input.prevOutScript = privKey.pub.getAddress().toOutputScript() + input.prevOutScript = keyPair.getAddress().toOutputScript() input.prevOutType = 'pubkeyhash' - input.pubKeys = [privKey.pub] + input.pubKeys = [kpPubKey] input.scriptType = input.prevOutType } } @@ -378,10 +381,11 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash input.signatures = input.pubKeys.map(function (pubKey) { var match + var keyPair2 = ECPair.fromPublicKeyBuffer(pubKey) // check for any matching signatures unmatched.some(function (signature, i) { - if (!pubKey.verify(signatureHash, signature)) return false + if (!keyPair2.verify(signatureHash, signature)) return false match = signature // remove matched signature from unmatched @@ -396,14 +400,15 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash // enforce in order signing of public keys assert(input.pubKeys.some(function (pubKey, i) { - if (!privKey.pub.Q.equals(pubKey.Q)) return false + if (!bufferutils.equal(kpPubKey, pubKey)) return false assert(!input.signatures[i], 'Signature already exists') - var signature = privKey.sign(signatureHash) + + var signature = keyPair.sign(signatureHash) input.signatures[i] = signature return true - }, this), 'privateKey cannot sign for this input') + }, this), 'key pair cannot sign for this input') } module.exports = TransactionBuilder diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js index 33066653e..bce7741cb 100644 --- a/test/bitcoin.core.js +++ b/test/bitcoin.core.js @@ -2,12 +2,11 @@ var assert = require('assert') var base58 = require('bs58') -var base58check = require('bs58check') var Bitcoin = require('../') var Address = Bitcoin.Address var Block = Bitcoin.Block -var ECKey = Bitcoin.ECKey +var ECPair = Bitcoin.ECPair var ECSignature = Bitcoin.ECSignature var Transaction = Bitcoin.Transaction var Script = Bitcoin.Script @@ -95,32 +94,31 @@ describe('Bitcoin-core', function () { }) // base58_keys_valid - describe('ECKey', function () { + describe('ECPair', function () { base58_keys_valid.forEach(function (f) { var string = f[0] var hex = f[1] var params = f[2] - var network = params.isTestnet ? networks.testnet : networks.bitcoin if (!params.isPrivkey) return - var privKey = ECKey.fromWIF(string) + var keyPair = ECPair.fromWIF(string) it('imports ' + string + ' correctly', function () { - assert.equal(privKey.d.toHex(), hex) - assert.equal(privKey.pub.compressed, params.isCompressed) + assert.equal(keyPair.d.toHex(), hex) + assert.equal(keyPair.compressed, params.isCompressed) }) it('exports ' + hex + ' to ' + string, function () { - assert.equal(privKey.toWIF(network), string) + assert.equal(keyPair.toWIF(), string) }) }) }) // base58_keys_invalid - describe('ECKey', function () { + describe('ECPair', function () { var allowedNetworks = [ - networks.bitcoin.wif, - networks.testnet.wif + networks.bitcoin, + networks.testnet ] base58_keys_invalid.forEach(function (f) { @@ -128,11 +126,10 @@ describe('Bitcoin-core', function () { it('throws on ' + string, function () { assert.throws(function () { - ECKey.fromWIF(string) - var version = base58check.decode(string).readUInt8(0) + var keyPair = ECPair.fromWIF(string) - assert.notEqual(allowedNetworks.indexOf(version), -1, 'Invalid network') - }, /Invalid (checksum|compression flag|network|WIF payload)/) + assert(allowedNetworks.indexOf(keyPair.network) > -1, 'Invalid network') + }, /(Invalid|Unknown) (checksum|compression flag|network|WIF payload)/) }) }) }) diff --git a/test/eckey.js b/test/eckey.js deleted file mode 100644 index 0e56fb54b..000000000 --- a/test/eckey.js +++ /dev/null @@ -1,143 +0,0 @@ -/* global describe, it */ -/* eslint-disable no-new */ - -var assert = require('assert') -var ecurve = require('ecurve') -var networks = require('../src/networks') -var proxyquire = require('proxyquire') -var randomBytes = require('randombytes') - -var BigInteger = require('bigi') -var ECKey = require('../src/eckey') - -var fixtures = require('./fixtures/eckey.json') - -describe('ECKey', function () { - describe('constructor', function () { - it('defaults to compressed', function () { - var privKey = new ECKey(BigInteger.ONE) - - assert.equal(privKey.pub.compressed, true) - }) - - it('supports the uncompressed flag', function () { - var privKey = new ECKey(BigInteger.ONE, false) - - assert.equal(privKey.pub.compressed, false) - }) - - fixtures.valid.forEach(function (f) { - it('calculates the matching pubKey for ' + f.d, function () { - var d = new BigInteger(f.d) - var privKey = new ECKey(d) - - assert.equal(privKey.pub.Q.toString(), f.Q) - }) - }) - - fixtures.invalid.constructor.forEach(function (f) { - it('throws on ' + f.d, function () { - var d = new BigInteger(f.d) - - assert.throws(function () { - new ECKey(d) - }, new RegExp(f.exception)) - }) - }) - }) - - it('uses the secp256k1 curve by default', function () { - var secp256k1 = ecurve.getCurveByName('secp256k1') - - for (var property in secp256k1) { - // FIXME: circular structures in ecurve - if (property === 'G') continue - if (property === 'infinity') continue - - var actual = ECKey.curve[property] - var expected = secp256k1[property] - - assert.deepEqual(actual, expected) - } - }) - - describe('fromWIF', function () { - fixtures.valid.forEach(function (f) { - f.WIFs.forEach(function (wif) { - it('imports ' + wif.string + ' correctly', function () { - var privKey = ECKey.fromWIF(wif.string) - - assert.equal(privKey.d.toString(), f.d) - assert.equal(privKey.pub.compressed, wif.compressed) - }) - }) - }) - - fixtures.invalid.WIF.forEach(function (f) { - it('throws on ' + f.string, function () { - assert.throws(function () { - ECKey.fromWIF(f.string) - }, new RegExp(f.exception)) - }) - }) - }) - - describe('toWIF', function () { - fixtures.valid.forEach(function (f) { - f.WIFs.forEach(function (wif) { - it('exports ' + wif.string + ' correctly', function () { - var privKey = ECKey.fromWIF(wif.string) - var network = networks[wif.network] - var result = privKey.toWIF(network) - - assert.equal(result, wif.string) - }) - }) - }) - }) - - describe('makeRandom', function () { - var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' - var exPrivKey = ECKey.fromWIF(exWIF) - var exBuffer = exPrivKey.d.toBuffer(32) - - it("uses the RNG provided by the 'randombytes' module by default", function () { - var stub = { randombytes: function () { return exBuffer } } - var ProxiedECKey = proxyquire('../src/eckey', stub) - - var privKey = ProxiedECKey.makeRandom() - - assert.equal(privKey.toWIF(), exWIF) - }) - - it('allows a custom RNG to be used', function () { - function rng (size) { - return exBuffer.slice(0, size) - } - - var privKey = ECKey.makeRandom(undefined, rng) - assert.equal(privKey.toWIF(), exWIF) - }) - - it('supports compression', function () { - assert.equal(ECKey.makeRandom(true).pub.compressed, true) - assert.equal(ECKey.makeRandom(false).pub.compressed, false) - }) - }) - - describe('signing', function () { - var hash = randomBytes(32) - var priv = ECKey.makeRandom() - var signature = priv.sign(hash) - - it('should verify against the public key', function () { - assert(priv.pub.verify(hash, signature)) - }) - - it('should not verify against the wrong public key', function () { - var priv2 = ECKey.makeRandom() - - assert(!priv2.pub.verify(hash, signature)) - }) - }) -}) diff --git a/test/ecpubkey.js b/test/ecpubkey.js deleted file mode 100644 index 76943ed3e..000000000 --- a/test/ecpubkey.js +++ /dev/null @@ -1,120 +0,0 @@ -/* global describe, it, beforeEach */ - -var assert = require('assert') -var crypto = require('../src/crypto') -var networks = require('../src/networks') - -var BigInteger = require('bigi') -var ECPubKey = require('../src/ecpubkey') - -var ecurve = require('ecurve') -var curve = ecurve.getCurveByName('secp256k1') - -var fixtures = require('./fixtures/ecpubkey.json') - -describe('ECPubKey', function () { - var Q - - beforeEach(function () { - Q = ecurve.Point.fromAffine( - curve, - new BigInteger(fixtures.Q.x), - new BigInteger(fixtures.Q.y) - ) - }) - - describe('constructor', function () { - it('defaults to compressed', function () { - var pubKey = new ECPubKey(Q) - - assert.equal(pubKey.compressed, true) - }) - - it('supports the uncompressed flag', function () { - var pubKey = new ECPubKey(Q, false) - - assert.equal(pubKey.compressed, false) - }) - }) - - it('uses the secp256k1 curve by default', function () { - var secp256k1 = ecurve.getCurveByName('secp256k1') - - for (var property in secp256k1) { - // FIXME: circular structures in ecurve - if (property === 'G') continue - if (property === 'infinity') continue - - var actual = ECPubKey.curve[property] - var expected = secp256k1[property] - - assert.deepEqual(actual, expected) - } - }) - - describe('fromHex/toHex', function () { - it('supports compressed points', function () { - var pubKey = ECPubKey.fromHex(fixtures.compressed.hex) - - assert(pubKey.Q.equals(Q)) - assert.equal(pubKey.toHex(), fixtures.compressed.hex) - assert.equal(pubKey.compressed, true) - }) - - it('supports uncompressed points', function () { - var pubKey = ECPubKey.fromHex(fixtures.uncompressed.hex) - - assert(pubKey.Q.equals(Q)) - assert.equal(pubKey.toHex(), fixtures.uncompressed.hex) - assert.equal(pubKey.compressed, false) - }) - }) - - describe('getAddress', function () { - it('calculates the expected hash (compressed)', function () { - var pubKey = new ECPubKey(Q, true) - var address = pubKey.getAddress() - - assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160) - }) - - it('calculates the expected hash (uncompressed)', function () { - var pubKey = new ECPubKey(Q, false) - var address = pubKey.getAddress() - - assert.equal(address.hash.toString('hex'), fixtures.uncompressed.hash160) - }) - - it('supports alternative networks', function () { - var pubKey = new ECPubKey(Q) - var address = pubKey.getAddress(networks.testnet) - - assert.equal(address.version, networks.testnet.pubKeyHash) - assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160) - }) - }) - - describe('verify', function () { - var pubKey, signature - beforeEach(function () { - pubKey = new ECPubKey(Q) - - signature = { - r: new BigInteger(fixtures.signature.r), - s: new BigInteger(fixtures.signature.s) - } - }) - - it('verifies a valid signature', function () { - var hash = crypto.sha256(fixtures.message) - - assert(pubKey.verify(hash, signature)) - }) - - it("doesn't verify the wrong signature", function () { - var hash = crypto.sha256('mushrooms') - - assert(!pubKey.verify(hash, signature)) - }) - }) -}) diff --git a/test/fixtures/eckey.json b/test/fixtures/eckey.json deleted file mode 100644 index 7d1c4a4c0..000000000 --- a/test/fixtures/eckey.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "valid": [ - { - "d": "1", - "Q": "(55066263022277343669578718895168534326250603453777594175500187360389116729240,32670510020758816978083085130507043184471273380659243275938904335757337482424)", - "WIFs": [ - { - "network": "bitcoin", - "string": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", - "compressed": true - }, - { - "network": "bitcoin", - "string": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf", - "compressed": false - } - ] - }, - { - "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102", - "Q": "(83225686012142088543596389522774768397204444195709443235253141114409346958144,23739058578904784236915560265041168694780215705543362357495033621678991351768)", - "WIFs": [ - { - "network": "bitcoin", - "string": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o", - "compressed": true - } - ] - }, - { - "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", - "Q": "(30095590000961171681152428142595206241714764354580127609094760797518133922356,93521207164355458151597931319591130635754976513751247168472016818884561919702)", - "WIFs": [ - { - "network": "bitcoin", - "string": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", - "compressed": true - }, - { - "network": "bitcoin", - "string": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh", - "compressed": false - }, - { - "network": "testnet", - "string": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv", - "compressed": true - }, - { - "network": "testnet", - "string": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj", - "compressed": false - } - ] - }, - { - "d": "115792089237316195423570985008687907852837564279074904382605163141518161494336", - "Q": "(55066263022277343669578718895168534326250603453777594175500187360389116729240,83121579216557378445487899878180864668798711284981320763518679672151497189239)", - "WIFs": [ - { - "network": "bitcoin", - "string": "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9", - "compressed": true - } - ] - } - ], - "invalid": { - "constructor": [ - { - "exception": "Private key must be greater than 0", - "d": "-1" - }, - { - "exception": "Private key must be greater than 0", - "d": "0" - }, - { - "exception": "Private key must be less than the curve order", - "d": "115792089237316195423570985008687907852837564279074904382605163141518161494337" - }, - { - "exception": "Private key must be less than the curve order", - "d": "115792089237316195423570985008687907853269984665640564039457584007913129639935" - } - ], - "WIF": [ - { - "exception": "Invalid compression flag", - "string": "ju9rooVsmagsb4qmNyTysUSFB1GB6MdpD7eoGjUTPmZRAApJxRz" - }, - { - "exception": "Invalid WIF payload length", - "string": "7ZEtRQLhCsDQrd6ZKfmcESdXgas8ggZPN24ByEi5ey6VJW" - }, - { - "exception": "Invalid WIF payload length", - "string": "5qibUKwsnMo1qDiNp3prGaQkD2JfVJa8F8Na87H2CkMHvuVg6uKhw67Rh" - } - ] - } -} diff --git a/test/fixtures/ecpubkey.json b/test/fixtures/ecpubkey.json deleted file mode 100644 index 87b8aa2ed..000000000 --- a/test/fixtures/ecpubkey.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Q": { - "x": "55066263022277343669578718895168534326250603453777594175500187360389116729240", - "y": "32670510020758816978083085130507043184471273380659243275938904335757337482424" - }, - "compressed": { - "hex": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - "hash160": "751e76e8199196d454941c45d1b3a323f1433bd6" - }, - "uncompressed": { - "hex": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - "hash160": "91b24bf9f5288532960ac687abb035127b1d28a5" - }, - "message": "vires in numeris", - "signature": { - "r": "68972263025625296948424563184904289678530916807200550828762374724416876919710", - "s": "43478152510424186005054433052302509227777805602212468112169549534899266476898" - } -} diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index b3f91ce2b..9fd03f3a1 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -10,7 +10,7 @@ "vout": 0, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" } ] } @@ -32,7 +32,7 @@ "prevTxScript": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG", "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" } ] } @@ -53,7 +53,7 @@ "vout": 0, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "redeemScript": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG" } ] @@ -75,11 +75,11 @@ "vout": 0, "signs": [ { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG" }, { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" } ] } @@ -101,10 +101,10 @@ "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", "signs": [ { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" }, { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" } ] } @@ -126,10 +126,10 @@ "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", "signs": [ { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT" }, { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" } ] } @@ -150,11 +150,11 @@ "vout": 0, "signs": [ { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG" }, { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe" } ] } @@ -176,7 +176,7 @@ "prevTxScript": "OP_HASH160 e89677d91455e541630d62c63718bef738b478b1 OP_EQUAL", "signs": [ { - "privKey": "KxLDMPtVM7sLSu2v5n1LybDibw6P9FFbL4pUwJ51UDm7rp5AmXWW", + "keyPair": "KxLDMPtVM7sLSu2v5n1LybDibw6P9FFbL4pUwJ51UDm7rp5AmXWW", "redeemScript": "033e29aea1168a835d5e386c292082db7b7807172a10ec634ad34226f36d79e70f OP_CHECKSIG" } ] @@ -198,7 +198,7 @@ "vout": 1, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" } ] } @@ -222,7 +222,7 @@ "sequence": 2147001, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" } ] } @@ -246,12 +246,12 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] @@ -275,12 +275,12 @@ "signs": [ { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "scriptSig": "OP_0 OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] @@ -304,12 +304,12 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae" } ] @@ -333,12 +333,12 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 1, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] @@ -362,12 +362,12 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] @@ -391,12 +391,12 @@ "signs": [ { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] @@ -420,12 +420,12 @@ "signs": [ { "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] @@ -449,13 +449,13 @@ "signs": [ { "pubKeyIndex": 2, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe", "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { "filterOP_0": true, "pubKeyIndex": 0, - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae", "scriptSigFiltered": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } @@ -522,7 +522,7 @@ "vout": 0, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" } ] }, @@ -556,10 +556,10 @@ "vout": 1, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" }, { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "throws": true } ] @@ -580,7 +580,7 @@ "vout": 1, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "redeemScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474", "throws": true } @@ -603,7 +603,7 @@ "prevTxScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL", "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "throws": true } ] @@ -625,11 +625,11 @@ "signs": [ { "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx" }, { "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "throws": true } ] @@ -651,11 +651,11 @@ "signs": [ { "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG", - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", "hashType": 4 }, { - "privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT", "hashType": 2, "throws": true } @@ -677,7 +677,7 @@ "vout": 1, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "redeemScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL", "throws": true } @@ -700,7 +700,7 @@ "prevTxScript": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG", "throws": true } @@ -723,11 +723,11 @@ "vout": 1, "signs": [ { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf", "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG" }, { - "privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf", "throws": true } ] @@ -741,15 +741,15 @@ ] }, { - "description": "Wrong private key for multisig redeemScript", - "exception": "privateKey cannot sign for this input", + "description": "Wrong key pair for multisig redeemScript", + "exception": "key pair cannot sign for this input", "inputs": [ { "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "vout": 1, "signs": [ { - "privKey": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG", "throws": true } @@ -772,7 +772,7 @@ "prevTxScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474", "signs": [ { - "privKey": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", + "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx", "throws": true } ] diff --git a/test/hdnode.js b/test/hdnode.js index 1cbfd7c52..46ff82bbe 100644 --- a/test/hdnode.js +++ b/test/hdnode.js @@ -3,96 +3,52 @@ var assert = require('assert') var networks = require('../src/networks') +var sinon = require('sinon') var BigInteger = require('bigi') -var ECKey = require('../src/eckey') -var ECPubKey = require('../src/ecpubkey') +var ECPair = require('../src/ecpair') var HDNode = require('../src/hdnode') -var ecurve = require('ecurve') -var curve = ecurve.getCurveByName('secp256k1') - var fixtures = require('./fixtures/hdnode.json') describe('HDNode', function () { describe('Constructor', function () { - var d = BigInteger.ONE - var Q = curve.G.multiply(d) - var chainCode = new Buffer(32) - chainCode.fill(1) - - it('calculates the publicKey from a BigInteger', function () { - var hd = new HDNode(d, chainCode) - - assert(hd.pubKey.Q.equals(Q)) - }) - - it('allows initialization directly from an ECKey', function () { - var ek = new ECKey(d) - var hd = new HDNode(ek, chainCode) - - assert.equal(hd.privKey, ek) - }) - - it('allows initialization directly from an ECPubKey', function () { - var ek = new ECPubKey(Q) - var hd = new HDNode(ek, chainCode) - - assert.equal(hd.pubKey, ek) - }) - - it('throws if ECKey is not compressed', function () { - var ek = new ECKey(d, false) - - assert.throws(function () { - new HDNode(ek, chainCode) - }, /ECKey must be compressed/) - }) - - it('throws if ECPubKey is not compressed', function () { - var ek = new ECPubKey(Q, false) + var keyPair, chainCode - assert.throws(function () { - new HDNode(ek, chainCode) - }, /ECPubKey must be compressed/) - }) + beforeEach(function () { + var d = BigInteger.ONE - it('only uses compressed points', function () { - var hd = new HDNode(Q, chainCode) - var hdP = new HDNode(d, chainCode) - - assert.strictEqual(hd.pubKey.compressed, true) - assert.strictEqual(hdP.pubKey.compressed, true) + keyPair = new ECPair(d, null) + chainCode = new Buffer(32) + chainCode.fill(1) }) it('has a default depth/index of 0', function () { - var hd = new HDNode(Q, chainCode) + var hd = new HDNode(keyPair, chainCode) assert.strictEqual(hd.depth, 0) assert.strictEqual(hd.index, 0) }) - it('defaults to the bitcoin network', function () { - var hd = new HDNode(Q, chainCode) - - assert.equal(hd.network, networks.bitcoin) - }) - - it('supports alternative networks', function () { - var hd = new HDNode(Q, chainCode, networks.testnet) + it('throws on uncompressed keyPair', function () { + keyPair.compressed = false - assert.equal(hd.network, networks.testnet) + assert.throws(function () { + new HDNode(keyPair, chainCode) + }, /BIP32 only allows compressed keyPairs/) }) it('throws when an invalid length chain code is given', function () { assert.throws(function () { - new HDNode(d, chainCode.slice(0, 20), networks.testnet) + new HDNode(keyPair, chainCode.slice(0, 20)) }, /Expected chainCode length of 32, got 20/) }) it('throws when an unknown network is given', function () { + keyPair.network = {} + assert.throws(function () { - new HDNode(d, chainCode, {}) + new HDNode(keyPair, chainCode) }, /Unknown BIP32 constants for network/) }) }) @@ -103,7 +59,7 @@ describe('HDNode', function () { var network = networks[f.network] var hd = HDNode.fromSeedHex(f.master.seed, network) - assert.equal(hd.privKey.toWIF(network), f.master.wif) + assert.equal(hd.keyPair.toWIF(), f.master.wif) assert.equal(hd.chainCode.toString('hex'), f.master.chainCode) }) }) @@ -148,7 +104,7 @@ describe('HDNode', function () { var hd = HDNode.fromBase58(f.master.base58) assert.equal(hd.toBase58(), f.master.base58) - assert.equal(hd.network, network) + assert.equal(hd.keyPair.network, network) }) }) @@ -158,7 +114,7 @@ describe('HDNode', function () { var hd = HDNode.fromBase58(f.master.base58Priv, network) assert.equal(hd.toBase58(), f.master.base58Priv) - assert.equal(hd.network, network) + assert.equal(hd.keyPair.network, network) }) }) @@ -194,13 +150,20 @@ describe('HDNode', function () { }) describe('getAddress', function () { - fixtures.valid.forEach(function (f) { - it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function () { - var hd = HDNode.fromBase58(f.master.base58) + var hd - assert.equal(hd.getAddress().toString(), f.master.address) - }) + beforeEach(function () { + var f = fixtures.valid[0] + + hd = HDNode.fromBase58(f.master.base58) }) + + it('wraps ECPair.getAddress', sinon.test(function () { + this.mock(hd.keyPair).expects('getAddress') + .once().returns('foobar') + + assert.equal(hd.getAddress(), 'foobar') + })) }) describe('neutered', function () { @@ -210,8 +173,8 @@ describe('HDNode', function () { var hd = HDNode.fromBase58(f.master.base58) var hdn = hd.neutered() - assert.equal(hdn.privKey, undefined) - assert.equal(hdn.pubKey.toHex(), hd.pubKey.toHex()) + assert.equal(hdn.keyPair.d, null) + assert.equal(hdn.keyPair.Q, hd.keyPair.Q) assert.equal(hdn.chainCode, hd.chainCode) assert.equal(hdn.depth, hd.depth) assert.equal(hdn.index, hd.index) @@ -219,9 +182,9 @@ describe('HDNode', function () { }) describe('derive', function () { - function verifyVector (hd, network, v, depth) { - assert.equal(hd.privKey.toWIF(network), v.wif) - assert.equal(hd.pubKey.toHex(), v.pubKey) + function verifyVector (hd, v, depth) { + assert.equal(hd.keyPair.toWIF(), v.wif) + assert.equal(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey) assert.equal(hd.chainCode.toString('hex'), v.chainCode) assert.equal(hd.depth, depth || 0) @@ -245,7 +208,7 @@ describe('HDNode', function () { hd = hd.derive(c.m) } - verifyVector(hd, network, c, i + 1) + verifyVector(hd, c, i + 1) }) }) }) diff --git a/test/integration/advanced.js b/test/integration/advanced.js index 3d2022851..45e52a742 100644 --- a/test/integration/advanced.js +++ b/test/integration/advanced.js @@ -6,10 +6,10 @@ var blockchain = new (require('cb-helloblock'))('testnet') describe('bitcoinjs-lib (advanced)', function () { it('can sign a Bitcoin message', function () { - var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') + var keyPair = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') var message = 'This is an example of a signed message.' - var signature = bitcoin.message.sign(key, message) + var signature = bitcoin.message.sign(keyPair, message) assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=') }) @@ -24,8 +24,10 @@ describe('bitcoinjs-lib (advanced)', function () { it('can create an OP_RETURN transaction', function (done) { this.timeout(20000) - var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') - var address = key.pub.getAddress(bitcoin.networks.testnet).toString() + var keyPair = bitcoin.ECPair.makeRandom({ + network: bitcoin.networks.testnet + }) + var address = keyPair.getAddress().toString() blockchain.addresses.__faucetWithdraw(address, 2e4, function (err) { if (err) return done(err) @@ -41,7 +43,7 @@ describe('bitcoinjs-lib (advanced)', function () { tx.addInput(unspent.txId, unspent.vout) tx.addOutput(dataScript, 1000) - tx.sign(0, key) + tx.sign(0, keyPair) var txBuilt = tx.build() diff --git a/test/integration/basic.js b/test/integration/basic.js index 7a7688975..6814fbb7b 100644 --- a/test/integration/basic.js +++ b/test/integration/basic.js @@ -9,9 +9,9 @@ describe('bitcoinjs-lib (basic)', function () { // for testing only function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } - // generate random key (custom rng for testing only) - var key = bitcoin.ECKey.makeRandom(undefined, rng) - var address = key.pub.getAddress().toString() + // generate random keyPair + var keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) + var address = keyPair.getAddress().toString() assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') }) @@ -20,25 +20,26 @@ describe('bitcoinjs-lib (basic)', function () { var hash = bitcoin.crypto.sha256('correct horse battery staple') var d = bigi.fromBuffer(hash) - var key = new bitcoin.ECKey(d) + var keyPair = new bitcoin.ECPair(d) + var address = keyPair.getAddress().toString() - assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') + assert.equal(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') }) it('can import an address via WIF', function () { - var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') - var address = key.pub.getAddress().toString() + var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + var address = keyPair.getAddress().toString() assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') }) it('can create a Transaction', function () { - var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') + var keyPair = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') var tx = new bitcoin.TransactionBuilder() tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0) tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) - tx.sign(0, key) + tx.sign(0, keyPair) assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000') }) diff --git a/test/integration/crypto.js b/test/integration/crypto.js index 631809235..8e69e44bf 100644 --- a/test/integration/crypto.js +++ b/test/integration/crypto.js @@ -9,17 +9,17 @@ var crypto = require('crypto') describe('bitcoinjs-lib (crypto)', function () { it('can generate a single-key stealth address', function () { - var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') + var receiver = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // XXX: ephemeral, must be random (and secret to sender) to preserve privacy - var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + var sender = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') - var G = bitcoin.ECKey.curve.G + var G = bitcoin.ECPair.curve.G var d = receiver.d // secret (receiver only) - var Q = receiver.pub.Q // shared + var Q = receiver.Q // shared var e = sender.d // secret (sender only) - var P = sender.pub.Q // shared + var P = sender.Q // shared // derived shared secret var eQ = Q.multiply(e) // sender @@ -35,7 +35,7 @@ describe('bitcoinjs-lib (crypto)', function () { assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded()) // derived shared-secret address - var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString() + var address = new bitcoin.ECPair(null, QprimeS).getAddress().toString() assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47') }) @@ -45,13 +45,14 @@ describe('bitcoinjs-lib (crypto)', function () { it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () { function recoverParent (master, child) { - assert(!master.privKey, 'You already have the parent private key') - assert(child.privKey, 'Missing child private key') + assert(!master.keyPair.d, 'You already have the parent private key') + assert(child.keyPair.d, 'Missing child private key') - var curve = bitcoin.ECKey.curve - var QP = master.pubKey.toBuffer() - var QP64 = QP.toString('base64') - var d1 = child.privKey.d + var curve = bitcoin.ECPair.curve + var QP = master.keyPair.Q + var serQP = master.keyPair.getPublicKeyBuffer() + + var d1 = child.keyPair.d var d2 var indexBuffer = new Buffer(4) @@ -60,7 +61,7 @@ describe('bitcoinjs-lib (crypto)', function () { indexBuffer.writeUInt32BE(i, 0) // calculate I - var data = Buffer.concat([QP, indexBuffer]) + var data = Buffer.concat([serQP, indexBuffer]) var I = crypto.createHmac('sha512', master.chainCode).update(data).digest() var IL = I.slice(0, 32) var pIL = bigi.fromBuffer(IL) @@ -68,11 +69,11 @@ describe('bitcoinjs-lib (crypto)', function () { // See hdnode.js:273 to understand d2 = d1.subtract(pIL).mod(curve.n) - var Qp = new bitcoin.ECKey(d2, true).pub.toBuffer() - if (Qp.toString('base64') === QP64) break + var Qp = new bitcoin.ECPair(d2).Q + if (Qp.equals(QP)) break } - var node = new bitcoin.HDNode(d2, master.chainCode, master.network) + var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network) node.depth = master.depth node.index = master.index node.masterFingerprint = master.masterFingerprint @@ -133,7 +134,7 @@ describe('bitcoinjs-lib (crypto)', function () { var prevOutScript = prevOut.outs[prevVout].script var scriptSignature = bitcoin.ECSignature.parseScriptSignature(script.chunks[0]) - var publicKey = bitcoin.ECPubKey.fromBuffer(script.chunks[1]) + var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(script.chunks[1]) var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType) assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m') @@ -151,7 +152,8 @@ describe('bitcoinjs-lib (crypto)', function () { async.parallel(tasks, function (err) { if (err) throw err - var n = bitcoin.ECKey.curve.n + + var n = bitcoin.ECPair.curve.n for (var i = 0; i < inputs.length; ++i) { for (var j = i + 1; j < inputs.length; ++j) { diff --git a/test/integration/multisig.js b/test/integration/multisig.js index 32be5e2ae..1392d95c8 100644 --- a/test/integration/multisig.js +++ b/test/integration/multisig.js @@ -10,11 +10,13 @@ describe('bitcoinjs-lib (multisig)', function () { '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9' - ].map(bitcoin.ECPubKey.fromHex) + ].map(function (hex) { + return new Buffer(hex, 'hex') + }) var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3 var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) - var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString() + var address = bitcoin.Address.fromOutputScript(scriptPubKey) assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') }) @@ -22,15 +24,13 @@ describe('bitcoinjs-lib (multisig)', function () { it('can spend from a 2-of-4 multsig P2SH address', function (done) { this.timeout(20000) - var privKeys = [ + var keyPairs = [ '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7' - ].map(bitcoin.ECKey.fromWIF) - var pubKeys = privKeys.map(function (x) { - return x.pub - }) + ].map(bitcoin.ECPair.fromWIF) + var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() }) var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 4 var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash()) @@ -44,7 +44,7 @@ describe('bitcoinjs-lib (multisig)', function () { blockchain.addresses.unspents(address, function (err, unspents) { if (err) return done(err) - // filter small unspents + // filter small unspents unspents = unspents.filter(function (unspent) { return unspent.value > 1e4 }) @@ -53,15 +53,17 @@ describe('bitcoinjs-lib (multisig)', function () { var unspent = unspents.pop() // make a random destination address - var targetAddress = bitcoin.ECKey.makeRandom().pub.getAddress(bitcoin.networks.testnet).toString() + var targetAddress = bitcoin.ECPair.makeRandom({ + network: bitcoin.networks.testnet + }).getAddress().toString() var txb = new bitcoin.TransactionBuilder() txb.addInput(unspent.txId, unspent.vout) txb.addOutput(targetAddress, 1e4) // sign with 1st and 3rd key - txb.sign(0, privKeys[0], redeemScript) - txb.sign(0, privKeys[2], redeemScript) + txb.sign(0, keyPairs[0], redeemScript) + txb.sign(0, keyPairs[2], redeemScript) // broadcast our transaction blockchain.transactions.propagate(txb.build().toHex(), function (err) { diff --git a/test/message.js b/test/message.js index e982a4533..28d69532b 100644 --- a/test/message.js +++ b/test/message.js @@ -6,7 +6,7 @@ var networks = require('../src/networks') var Address = require('../src/address') var BigInteger = require('bigi') -var ECKey = require('../src/eckey') +var ECPair = require('../src/ecpair') var fixtures = require('./fixtures/message.json') @@ -55,12 +55,14 @@ describe('message', function () { it(f.description, function () { var network = networks[f.network] - var privKey = new ECKey(new BigInteger(f.d), false) - var signature = message.sign(privKey, f.message, network) + var keyPair = new ECPair(new BigInteger(f.d), null, { + compressed: false + }) + var signature = message.sign(keyPair, f.message, network) assert.equal(signature.toString('base64'), f.signature) if (f.compressed) { - var compressedPrivKey = new ECKey(new BigInteger(f.d)) + var compressedPrivKey = new ECPair(new BigInteger(f.d)) var compressedSignature = message.sign(compressedPrivKey, f.message) assert.equal(compressedSignature.toString('base64'), f.compressed.signature) diff --git a/test/networks.js b/test/networks.js index 3c9762d0c..9a1ff4861 100644 --- a/test/networks.js +++ b/test/networks.js @@ -15,7 +15,7 @@ describe('networks', function () { var extb58 = f.bip32[name] it(extb58 + ' auto-detects ' + f.network, function () { - assert.equal(HDNode.fromBase58(extb58).network, network) + assert.equal(HDNode.fromBase58(extb58).keyPair.network, network) }) }) }) diff --git a/test/scripts.js b/test/scripts.js index 14421c8c9..a9e3bb489 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -4,7 +4,7 @@ var assert = require('assert') var ops = require('../src/opcodes') var scripts = require('../src/scripts') -var ECPubKey = require('../src/ecpubkey') +var ECPair = require('../src/ecpair') var Script = require('../src/script') var fixtures = require('./fixtures/scripts.json') @@ -150,8 +150,7 @@ describe('Scripts', function () { if (f.type !== 'pubkey') return it('returns ' + f.scriptPubKey, function () { - var pubKey = ECPubKey.fromHex(f.pubKey) - + var pubKey = new Buffer(f.pubKey, 'hex') var scriptPubKey = scripts.pubKeyOutput(pubKey) assert.equal(scriptPubKey.toASM(), f.scriptPubKey) }) @@ -162,7 +161,7 @@ describe('Scripts', function () { fixtures.valid.forEach(function (f) { if (f.type !== 'pubkeyhash') return - var pubKey = ECPubKey.fromHex(f.pubKey) + var pubKey = new Buffer(f.pubKey, 'hex') it('returns ' + f.scriptSig, function () { var signature = new Buffer(f.signature, 'hex') @@ -177,8 +176,8 @@ describe('Scripts', function () { fixtures.valid.forEach(function (f) { if (f.type !== 'pubkeyhash') return - var pubKey = ECPubKey.fromHex(f.pubKey) - var address = pubKey.getAddress() + var pubKey = new Buffer(f.pubKey, 'hex') + var address = ECPair.fromPublicKeyBuffer(pubKey).getAddress() it('returns ' + f.scriptPubKey, function () { var scriptPubKey = scripts.pubKeyHashOutput(address.hash) @@ -220,7 +219,7 @@ describe('Scripts', function () { fixtures.valid.forEach(function (f) { if (f.type !== 'multisig') return - var pubKeys = f.pubKeys.map(ECPubKey.fromHex) + var pubKeys = f.pubKeys.map(function (p) { return new Buffer(p, 'hex') }) var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys) it('returns ' + f.scriptPubKey, function () { @@ -229,7 +228,9 @@ describe('Scripts', function () { }) fixtures.invalid.multisigOutput.forEach(function (f) { - var pubKeys = f.pubKeys.map(ECPubKey.fromHex) + var pubKeys = f.pubKeys.map(function (p) { + return new Buffer(p, 'hex') + }) it('throws on ' + f.exception, function () { assert.throws(function () { diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 651b25544..4b9f25589 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -6,7 +6,7 @@ var scripts = require('../src/scripts') var Address = require('../src/address') var BigInteger = require('bigi') -var ECKey = require('../src/eckey') +var ECPair = require('../src/ecpair') var Script = require('../src/script') var Transaction = require('../src/transaction') var TransactionBuilder = require('../src/transaction_builder') @@ -33,14 +33,14 @@ function construct (txb, f, sign) { if (sign === undefined || sign) { f.inputs.forEach(function (input, index) { input.signs.forEach(function (sign) { - var privKey = ECKey.fromWIF(sign.privKey) + var keyPair = ECPair.fromWIF(sign.keyPair) var redeemScript if (sign.redeemScript) { redeemScript = Script.fromASM(sign.redeemScript) } - txb.sign(index, privKey, redeemScript, sign.hashType) + txb.sign(index, keyPair, redeemScript, sign.hashType) }) }) } @@ -58,7 +58,7 @@ function construct (txb, f, sign) { describe('TransactionBuilder', function () { var privAddress, privScript var prevTx, prevTxHash - var privKey + var keyPair var txb beforeEach(function () { @@ -69,8 +69,8 @@ describe('TransactionBuilder', function () { prevTx.addOutput(Address.fromBase58Check('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP').toOutputScript(), 1) prevTxHash = prevTx.getHash() - privKey = new ECKey(BigInteger.ONE, false) - privAddress = privKey.pub.getAddress() + keyPair = new ECPair(BigInteger.ONE) + privAddress = keyPair.getAddress() privScript = privAddress.toOutputScript() }) @@ -115,7 +115,7 @@ describe('TransactionBuilder', function () { it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(prevTxHash, 0) - txb.sign(0, privKey) + txb.sign(0, keyPair) assert.throws(function () { txb.addInput(prevTxHash, 0) @@ -154,7 +154,7 @@ describe('TransactionBuilder', function () { it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(prevTxHash, 0) txb.addOutput(privScript, 2000) - txb.sign(0, privKey) + txb.sign(0, keyPair) assert.throws(function () { txb.addOutput(privScript, 9000) @@ -169,7 +169,7 @@ describe('TransactionBuilder', function () { f.inputs.forEach(function (input, index) { input.signs.forEach(function (sign) { - var privKey = ECKey.fromWIF(sign.privKey) + var keyPair = ECPair.fromWIF(sign.keyPair) var redeemScript if (sign.redeemScript) { @@ -177,10 +177,11 @@ describe('TransactionBuilder', function () { } if (!sign.throws) { - txb.sign(index, privKey, redeemScript, sign.hashType) + txb.sign(index, keyPair, redeemScript, sign.hashType) + } else { assert.throws(function () { - txb.sign(index, privKey, redeemScript, sign.hashType) + txb.sign(index, keyPair, redeemScript, sign.hashType) }, new RegExp(f.exception)) } }) @@ -256,8 +257,8 @@ describe('TransactionBuilder', function () { txb = TransactionBuilder.fromTransaction(tx) } - var privKey = ECKey.fromWIF(sign.privKey) - txb.sign(i, privKey, redeemScript, sign.hashType) + var keyPair = ECPair.fromWIF(sign.keyPair) + txb.sign(i, keyPair, redeemScript, sign.hashType) // update the tx tx = txb.buildIncomplete() From e106d0273130fade4a66752b3e7d9a248709f6dd Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 19 Mar 2015 13:35:25 +1100 Subject: [PATCH 49/64] standard formatting fixes --- src/ecpair.js | 2 +- src/hdnode.js | 2 +- test/hdnode.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ecpair.js b/src/ecpair.js index 7f340b467..990c2dd6a 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -47,7 +47,7 @@ function ECPair (d, Q, options) { } Object.defineProperty(ECPair.prototype, 'Q', { - get: function() { + get: function () { if (!this.__Q && this.d) { this.__Q = ECPair.curve.G.multiply(this.d) } diff --git a/src/hdnode.js b/src/hdnode.js index 49f5ae4e1..6989b3eaa 100644 --- a/src/hdnode.js +++ b/src/hdnode.js @@ -99,7 +99,7 @@ HDNode.fromBase58 = function (string, network) { var chainCode = buffer.slice(13, 45) var data, keyPair - // 33 bytes: private key data (0x00 + k) + // 33 bytes: private key data (0x00 + k) if (version === network.bip32.private) { assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key') data = buffer.slice(46, 78) diff --git a/test/hdnode.js b/test/hdnode.js index 46ff82bbe..46833e894 100644 --- a/test/hdnode.js +++ b/test/hdnode.js @@ -1,4 +1,4 @@ -/* global describe, it */ +/* global describe, it, beforeEach */ /* eslint-disable no-new */ var assert = require('assert') From 5fee511ff5a7dfb3b8c17512923fb45aeab799f9 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 9 Apr 2015 15:29:05 +1000 Subject: [PATCH 50/64] rm ECKey/ECPubKey --- src/eckey.js | 84 ------------------------------------------------- src/ecpubkey.js | 56 --------------------------------- 2 files changed, 140 deletions(-) delete mode 100644 src/eckey.js delete mode 100644 src/ecpubkey.js diff --git a/src/eckey.js b/src/eckey.js deleted file mode 100644 index 06bed6a51..000000000 --- a/src/eckey.js +++ /dev/null @@ -1,84 +0,0 @@ -var assert = require('assert') -var base58check = require('bs58check') -var ecdsa = require('./ecdsa') -var networks = require('./networks') -var randomBytes = require('randombytes') -var typeForce = require('typeforce') - -var BigInteger = require('bigi') -var ECPubKey = require('./ecpubkey') - -var ecurve = require('ecurve') -var secp256k1 = ecurve.getCurveByName('secp256k1') - -function ECKey (d, compressed) { - assert(d.signum() > 0, 'Private key must be greater than 0') - assert(d.compareTo(ECKey.curve.n) < 0, 'Private key must be less than the curve order') - - var Q = ECKey.curve.G.multiply(d) - - this.d = d - this.pub = new ECPubKey(Q, compressed) -} - -// Constants -ECKey.curve = secp256k1 - -// Static constructors -ECKey.fromWIF = function (string) { - var payload = base58check.decode(string) - var compressed = false - - // Ignore the version byte - payload = payload.slice(1) - - if (payload.length === 33) { - assert.strictEqual(payload[32], 0x01, 'Invalid compression flag') - - // Truncate the compression flag - payload = payload.slice(0, -1) - compressed = true - } - - assert.equal(payload.length, 32, 'Invalid WIF payload length') - - var d = BigInteger.fromBuffer(payload) - return new ECKey(d, compressed) -} - -ECKey.makeRandom = function (compressed, rng) { - rng = rng || randomBytes - - var buffer = rng(32) - typeForce('Buffer', buffer) - assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG') - - var d = BigInteger.fromBuffer(buffer) - d = d.mod(ECKey.curve.n) - - return new ECKey(d, compressed) -} - -// Export functions -ECKey.prototype.toWIF = function (network) { - network = network || networks.bitcoin - - var bufferLen = this.pub.compressed ? 34 : 33 - var buffer = new Buffer(bufferLen) - - buffer.writeUInt8(network.wif, 0) - this.d.toBuffer(32).copy(buffer, 1) - - if (this.pub.compressed) { - buffer.writeUInt8(0x01, 33) - } - - return base58check.encode(buffer) -} - -// Operations -ECKey.prototype.sign = function (hash) { - return ecdsa.sign(ECKey.curve, hash, this.d) -} - -module.exports = ECKey diff --git a/src/ecpubkey.js b/src/ecpubkey.js deleted file mode 100644 index ecc37bc51..000000000 --- a/src/ecpubkey.js +++ /dev/null @@ -1,56 +0,0 @@ -var crypto = require('./crypto') -var ecdsa = require('./ecdsa') -var typeForce = require('typeforce') -var networks = require('./networks') - -var Address = require('./address') - -var ecurve = require('ecurve') -var secp256k1 = ecurve.getCurveByName('secp256k1') - -function ECPubKey (Q, compressed) { - if (compressed === undefined) { - compressed = true - } - - typeForce('Point', Q) - typeForce('Boolean', compressed) - - this.compressed = compressed - this.Q = Q -} - -// Constants -ECPubKey.curve = secp256k1 - -// Static constructors -ECPubKey.fromBuffer = function (buffer) { - var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer) - return new ECPubKey(Q, Q.compressed) -} - -ECPubKey.fromHex = function (hex) { - return ECPubKey.fromBuffer(new Buffer(hex, 'hex')) -} - -// Operations -ECPubKey.prototype.getAddress = function (network) { - network = network || networks.bitcoin - - return new Address(crypto.hash160(this.toBuffer()), network.pubKeyHash) -} - -ECPubKey.prototype.verify = function (hash, signature) { - return ecdsa.verify(ECPubKey.curve, hash, signature, this.Q) -} - -// Export functions -ECPubKey.prototype.toBuffer = function () { - return this.Q.getEncoded(this.compressed) -} - -ECPubKey.prototype.toHex = function () { - return this.toBuffer().toString('hex') -} - -module.exports = ECPubKey From 57932324ab7443091ae674026f908ebc3825ef67 Mon Sep 17 00:00:00 2001 From: Ruben de Vries Date: Thu, 9 Apr 2015 14:52:43 +0200 Subject: [PATCH 51/64] add a note about uglying (to avoid issues with typeForce) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c6610dea1..89fac42be 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,9 @@ You will then be able to load `foobar.js` into your browser, with each of the de **NOTE**: See our package.json for the currently supported version of browserify used by this repository. +**NOTE**: If you're planning to uglify/minify the javascript, make sure to exclude the following variable names from being mangled: +`['Buffer', 'BitInteger', 'Point', 'Script', 'ECPubKey', 'ECKey']` + ## Examples From 3ab6f3e2a25561ddee004d7fc846ebf03929a42d Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 10 Apr 2015 10:33:58 +1000 Subject: [PATCH 52/64] README: clarification that the issue is due to duck-typing --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 89fac42be..07cef0caa 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,9 @@ You will then be able to load `foobar.js` into your browser, with each of the de **NOTE**: See our package.json for the currently supported version of browserify used by this repository. -**NOTE**: If you're planning to uglify/minify the javascript, make sure to exclude the following variable names from being mangled: +**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled. `['Buffer', 'BitInteger', 'Point', 'Script', 'ECPubKey', 'ECKey']` +This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce). ## Examples From b9f9620207e0d7b7ccff1ff197171c5df6ad7cf9 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 10 Apr 2015 10:36:04 +1000 Subject: [PATCH 53/64] README: s/BitInteger/BigInteger, fix formatting --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 07cef0caa..317b03a57 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,7 @@ You will then be able to load `foobar.js` into your browser, with each of the de **NOTE**: See our package.json for the currently supported version of browserify used by this repository. -**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled. -`['Buffer', 'BitInteger', 'Point', 'Script', 'ECPubKey', 'ECKey']` +**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Buffer`, `BigInteger`, `Point`, `Script`, `ECPubKey` and `ECKey`. This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce). From d10808f9133ddb8e7b10dde8d7d06c6f180a73b6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 10 Apr 2015 10:38:09 +1000 Subject: [PATCH 54/64] package: change version to 2.0.0-pre Thanks @jprichardson for the suggestion --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd14bf992..6afea75f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "1.5.0", + "version": "2.0.0-pre", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "keywords": [ From 79d2a821673b2cfae7009e1a9bbbc182d27465b2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 10 Apr 2015 10:46:30 +1000 Subject: [PATCH 55/64] README: update to 2.0.0 type names --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 317b03a57..d3baab9bc 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ You will then be able to load `foobar.js` into your browser, with each of the de **NOTE**: See our package.json for the currently supported version of browserify used by this repository. -**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Buffer`, `BigInteger`, `Point`, `Script`, `ECPubKey` and `ECKey`. +**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`,`Boolean`, `Buffer`, `ECPair`, `Function`, `Number`, `Point` and `Script`. This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce). From bb514aa97cf74a2c47450900aa7ae13b13ed3970 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 10 Apr 2015 10:46:59 +1000 Subject: [PATCH 56/64] README: add missing space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3baab9bc..386146ee5 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ You will then be able to load `foobar.js` into your browser, with each of the de **NOTE**: See our package.json for the currently supported version of browserify used by this repository. -**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`,`Boolean`, `Buffer`, `ECPair`, `Function`, `Number`, `Point` and `Script`. +**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`, `Boolean`, `Buffer`, `ECPair`, `Function`, `Number`, `Point` and `Script`. This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce). From b0e1d0d9c3f16d09e8addeb5f803322c78144e18 Mon Sep 17 00:00:00 2001 From: JP Richardson Date: Wed, 15 Apr 2015 18:19:49 -0500 Subject: [PATCH 57/64] test/integration/basic: added litecoin example --- test/integration/basic.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/integration/basic.js b/test/integration/basic.js index 6814fbb7b..0bb68642f 100644 --- a/test/integration/basic.js +++ b/test/integration/basic.js @@ -26,6 +26,20 @@ describe('bitcoinjs-lib (basic)', function () { assert.equal(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') }) + it('can generate a random keypair for alternative networks', function () { + // for testing only + function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } + + var litecoin = bitcoin.networks.litecoin + + var keyPair = bitcoin.ECPair.makeRandom({ network: litecoin, rng: rng }) + var wif = keyPair.toWIF() + var address = keyPair.getAddress().toString() + + assert.equal(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') + assert.equal(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') + }) + it('can import an address via WIF', function () { var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') var address = keyPair.getAddress().toString() From 2126a305b7c1d757262eb57629b79ae282378cd3 Mon Sep 17 00:00:00 2001 From: JP Richardson Date: Wed, 15 Apr 2015 18:22:07 -0500 Subject: [PATCH 58/64] readme: added an example on how to generate an address and WIF for an alternative network --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 386146ee5..97d95c971 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,9 @@ The below examples are implemented as integration tests, they should be very eas - [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L8) - [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L20) -- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L29) -- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L36) +- [Generate a address and WIF for Litecoin](https://github.com/bitcoin/bitcoinjs-lib/blob/master/test/integration/basic.js#L29) +- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L43) +- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L50) - [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L9) - [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L17) - [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L24) From 185fd63a05e4401ed854fa23f91b54135017a1da Mon Sep 17 00:00:00 2001 From: Ben Holden-Crowther Date: Thu, 16 Apr 2015 15:47:01 +0100 Subject: [PATCH 59/64] Updated Copyright Date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 386146ee5..c15ca3021 100644 --- a/README.md +++ b/README.md @@ -162,5 +162,5 @@ This library is free and open-source software released under the MIT license. ## Copyright -BitcoinJS (c) 2011-2014 Bitcoinjs-lib contributors +BitcoinJS (c) 2011-2015 Bitcoinjs-lib contributors Released under MIT license From 75540b61169a7975944d8b5bc0e12dcbf50f838d Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 22 Apr 2015 10:17:14 +1000 Subject: [PATCH 60/64] bufferutils: remove equal, use Buffer.compare --- src/bufferutils.js | 11 ----------- src/transaction_builder.js | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/bufferutils.js b/src/bufferutils.js index 773e5021e..9f1c85edc 100644 --- a/src/bufferutils.js +++ b/src/bufferutils.js @@ -168,16 +168,6 @@ function varIntBuffer (i) { return buffer } -function equal (a, b) { - if (a.length !== b.length) return false - - for (var i = 0; i < a.length; ++i) { - if (a[i] !== b[i]) return false - } - - return true -} - function reverse (buffer) { var buffer2 = new Buffer(buffer) Array.prototype.reverse.call(buffer2) @@ -185,7 +175,6 @@ function reverse (buffer) { } module.exports = { - equal: equal, pushDataSize: pushDataSize, readPushDataInt: readPushDataInt, readUInt64LE: readUInt64LE, diff --git a/src/transaction_builder.js b/src/transaction_builder.js index a08af7202..763cd1ca9 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -400,7 +400,7 @@ TransactionBuilder.prototype.sign = function (index, keyPair, redeemScript, hash // enforce in order signing of public keys assert(input.pubKeys.some(function (pubKey, i) { - if (!bufferutils.equal(kpPubKey, pubKey)) return false + if (kpPubKey.compare(pubKey) !== 0) return false assert(!input.signatures[i], 'Signature already exists') @@ -408,7 +408,7 @@ TransactionBuilder.prototype.sign = function (index, keyPair, redeemScript, hash input.signatures[i] = signature return true - }, this), 'key pair cannot sign for this input') + }), 'key pair cannot sign for this input') } module.exports = TransactionBuilder From 706666024ebfa0dfaa06484215bc0c260d2aa247 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 22 Apr 2015 17:44:21 +1000 Subject: [PATCH 61/64] travis: node 0.12 only --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 26f05da87..7422a8bff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,7 @@ language: node_js before_install: - "npm install npm -g" node_js: - - "0.11" - - "0.10" + - "0.12" env: - TEST_SUITE=coveralls - TEST_SUITE=integration From 11bba2a8e7e5ba4cdf4e00ac3449d50e69f8aaf6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 27 Apr 2015 12:03:35 +1000 Subject: [PATCH 62/64] tests: remove bufferutils.equal tests --- test/bufferutils.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/bufferutils.js b/test/bufferutils.js index c97e0bcce..eaef22a7f 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -88,22 +88,6 @@ describe('bufferutils', function () { }) }) - describe('equal', function () { - fixtures.valid.forEach(function (f) { - describe('for ' + f.hexVI, function () { - fixtures.valid.forEach(function (f2) { - it('equates the string comparison: ' + f.hexVI + ' === ' + f2.hexVI, function () { - var a = new Buffer(f.hexVI, 'hex') - var b = new Buffer(f2.hexVI, 'hex') - var expected = f.hexVI === f2.hexVI - - assert.equal(bufferutils.equal(a, b), expected) - }) - }) - }) - }) - }) - describe('reverse', function () { fixtures.valid.forEach(function (f) { it('reverses ' + f.hex64 + ' correctly', function () { From f9b99fc0df5d36b11f9f4f5d7bf68baebc0e0477 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 27 Apr 2015 12:04:38 +1000 Subject: [PATCH 63/64] txbuilder: remove unused bufferutils import --- src/transaction_builder.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 763cd1ca9..cafcfc854 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -1,5 +1,4 @@ var assert = require('assert') -var bufferutils = require('./bufferutils') var ops = require('./opcodes') var scripts = require('./scripts') From 078e391fb974416e9903e3228626339462e6af55 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 28 Apr 2015 12:05:41 +1000 Subject: [PATCH 64/64] address: remove instantiable object --- src/address.js | 81 +++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/address.js b/src/address.js index 4d8c67a26..e10c675a5 100644 --- a/src/address.js +++ b/src/address.js @@ -1,62 +1,67 @@ var assert = require('assert') -var base58check = require('bs58check') -var typeForce = require('typeforce') +var bs58check = require('bs58check') var networks = require('./networks') var scripts = require('./scripts') -function findScriptTypeByVersion (version) { - for (var networkName in networks) { - var network = networks[networkName] +function fromOutputScript(script, network) { + var payload = new Buffer(21) + var hash, version - if (version === network.pubKeyHash) return 'pubkeyhash' - if (version === network.scriptHash) return 'scripthash' - } -} + if (scripts.isPubKeyHashOutput(script)) { + version = network.pubKeyHash + hash = script.chunks[2] -function Address (hash, version) { - typeForce('Buffer', hash) + } else if (scripts.isScriptHashOutput(script)) { + version = network.scriptHash + hash = script.chunks[1] - assert.strictEqual(hash.length, 20, 'Invalid hash length') - assert.strictEqual(version & 0xff, version, 'Invalid version byte') + } else { + assert(false, script.toASM() + ' has no matching Address') + } + + payload.writeUInt8(version, 0) + hash.copy(payload, 1) - this.hash = hash - this.version = version + return bs58check.encode(payload) } -Address.fromBase58Check = function (string) { - var payload = base58check.decode(string) +// FIXME: remove network search +function toOutputScript(address) { + var payload = bs58check.decode(address) var version = payload.readUInt8(0) var hash = payload.slice(1) - return new Address(hash, version) -} + for (var networkStr in networks) { + var network = networks[networkStr] -Address.fromOutputScript = function (script, network) { - network = network || networks.bitcoin + if (version === network.pubKeyHash) { + return scripts.pubKeyHashOutput(hash) - if (scripts.isPubKeyHashOutput(script)) return new Address(script.chunks[2], network.pubKeyHash) - if (scripts.isScriptHashOutput(script)) return new Address(script.chunks[1], network.scriptHash) + } else if (version === network.scriptHash) { + return scripts.scriptHashOutput(hash) + } + } - assert(false, script.toASM() + ' has no matching Address') + assert(false, address + ' has no matching Script') } -Address.prototype.toBase58Check = function () { - var payload = new Buffer(21) - payload.writeUInt8(this.version, 0) - this.hash.copy(payload, 1) +function validate(address, network) { + if (typeof network === 'string') network = networks[network] - return base58check.encode(payload) -} + try { var payload = bs58check.decode(address) + assert.equal(payload.length, 21) -Address.prototype.toOutputScript = function () { - var scriptType = findScriptTypeByVersion(this.version) + var version = payload.readUInt8(0) - if (scriptType === 'pubkeyhash') return scripts.pubKeyHashOutput(this.hash) - if (scriptType === 'scripthash') return scripts.scriptHashOutput(this.hash) + assert(version === network.pubKeyHash || version === network.scriptHash) - assert(false, this.toString() + ' has no matching Script') + } catch (e) { + throw new Error(address + ' is not a valid ' + network + ' address') + } } -Address.prototype.toString = Address.prototype.toBase58Check - -module.exports = Address +module.exports = { + fromOutputScript: fromOutputScript, + toOutputScript: toOutputScript, + validate: validate +}