From 16195cc6ce8144beb90b1c210d37bbce357a5bdb Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 23 Jul 2018 17:45:01 +1000 Subject: [PATCH 001/183] explicitly import mocha variables --- test/address.js | 3 +-- test/bitcoin.core.js | 3 +-- test/block.js | 3 +-- test/bufferutils.js | 3 +-- test/classify.js | 3 +-- test/crypto.js | 3 +-- test/ecpair.js | 2 +- test/integration/addresses.js | 3 +-- test/integration/bip32.js | 3 +-- test/integration/blocks.js | 2 +- test/integration/cltv.js | 3 +-- test/integration/crypto.js | 3 +-- test/integration/csv.js | 3 +-- test/integration/payments.js | 3 +-- test/integration/stealth.js | 3 +-- test/integration/transactions.js | 3 +-- test/payments.js | 3 +-- test/payments.utils.js | 6 +++--- test/script.js | 3 +-- test/script_number.js | 3 +-- test/script_signature.js | 3 +-- test/transaction.js | 3 +-- test/transaction_builder.js | 3 +-- test/types.js | 3 +-- 24 files changed, 26 insertions(+), 47 deletions(-) diff --git a/test/address.js b/test/address.js index 99955e7..a0f4df0 100644 --- a/test/address.js +++ b/test/address.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const baddress = require('../src/address') const bscript = require('../src/script') diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js index f0aecf7..560bf20 100644 --- a/test/bitcoin.core.js +++ b/test/bitcoin.core.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const base58 = require('bs58') const bitcoin = require('../') diff --git a/test/block.js b/test/block.js index 1da9de3..d9ff405 100644 --- a/test/block.js +++ b/test/block.js @@ -1,5 +1,4 @@ -/* global describe, it, beforeEach */ - +const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const Block = require('../src/block') diff --git a/test/bufferutils.js b/test/bufferutils.js index aa044af..5f2c39e 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bufferutils = require('../src/bufferutils') diff --git a/test/classify.js b/test/classify.js index f56647e..3efcc74 100644 --- a/test/classify.js +++ b/test/classify.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bscript = require('../src/script') const classify = require('../src/classify') diff --git a/test/crypto.js b/test/crypto.js index 18f2a37..3f7802a 100644 --- a/test/crypto.js +++ b/test/crypto.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bcrypto = require('../src/crypto') diff --git a/test/ecpair.js b/test/ecpair.js index fc215f1..3b5857f 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -1,6 +1,6 @@ -/* global describe, it, beforeEach */ /* eslint-disable no-new */ +const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const proxyquire = require('proxyquire') const hoodwink = require('hoodwink') diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 412e792..4bd71c8 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const dhttp = require('dhttp/200') diff --git a/test/integration/bip32.js b/test/integration/bip32.js index 3d2f12c..27a2da4 100644 --- a/test/integration/bip32.js +++ b/test/integration/bip32.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bip32 = require('bip32') const bip39 = require('bip39') diff --git a/test/integration/blocks.js b/test/integration/blocks.js index a0bdea3..915fd65 100644 --- a/test/integration/blocks.js +++ b/test/integration/blocks.js @@ -1,6 +1,6 @@ -/* global describe, it */ 'use strict' +const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') diff --git a/test/integration/cltv.js b/test/integration/cltv.js index 626c7e9..edd4b61 100644 --- a/test/integration/cltv.js +++ b/test/integration/cltv.js @@ -1,5 +1,4 @@ -/* global describe, it, before */ - +const { describe, it, before } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const regtestUtils = require('./_regtest') diff --git a/test/integration/crypto.js b/test/integration/crypto.js index 864f4e7..bc4a9bc 100644 --- a/test/integration/crypto.js +++ b/test/integration/crypto.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const BN = require('bn.js') const bitcoin = require('../../') diff --git a/test/integration/csv.js b/test/integration/csv.js index e0ad02f..f0db2e4 100644 --- a/test/integration/csv.js +++ b/test/integration/csv.js @@ -1,5 +1,4 @@ -/* global describe, it, before */ - +const { describe, it, before } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const regtestUtils = require('./_regtest') diff --git a/test/integration/payments.js b/test/integration/payments.js index d319f60..44acea2 100644 --- a/test/integration/payments.js +++ b/test/integration/payments.js @@ -1,7 +1,6 @@ -/* global describe, it */ - const bitcoin = require('../../') +const { describe, it } = require('mocha') const regtestUtils = require('./_regtest') const NETWORK = regtestUtils.network const keyPairs = [ diff --git a/test/integration/stealth.js b/test/integration/stealth.js index 813f48b..dd99d63 100644 --- a/test/integration/stealth.js +++ b/test/integration/stealth.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const ecc = require('tiny-secp256k1') diff --git a/test/integration/transactions.js b/test/integration/transactions.js index ef95d53..4d344a5 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const regtestUtils = require('./_regtest') diff --git a/test/payments.js b/test/payments.js index 3af6699..3c07bf3 100644 --- a/test/payments.js +++ b/test/payments.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const u = require('./payments.utils') diff --git a/test/payments.utils.js b/test/payments.utils.js index 6a7af32..219d086 100644 --- a/test/payments.utils.js +++ b/test/payments.utils.js @@ -1,6 +1,6 @@ -let t = require('assert') -let bscript = require('../src/script') -let bnetworks = require('../src/networks') +const t = require('assert') +const bscript = require('../src/script') +const bnetworks = require('../src/networks') function tryHex (x) { if (Buffer.isBuffer(x)) return x.toString('hex') diff --git a/test/script.js b/test/script.js index 269e18a..c2a60ad 100644 --- a/test/script.js +++ b/test/script.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bscript = require('../src/script') const minimalData = require('minimaldata') diff --git a/test/script_number.js b/test/script_number.js index d217ff1..bc8f395 100644 --- a/test/script_number.js +++ b/test/script_number.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const scriptNumber = require('../src/script_number') const fixtures = require('./fixtures/script_number.json') diff --git a/test/script_signature.js b/test/script_signature.js index 9908ebc..cee69bd 100644 --- a/test/script_signature.js +++ b/test/script_signature.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const bscriptSig = require('../src/script').signature const Buffer = require('safe-buffer').Buffer diff --git a/test/transaction.js b/test/transaction.js index e249631..f8b7de9 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -1,5 +1,4 @@ -/* global describe, it, beforeEach */ - +const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const bscript = require('../src/script') const fixtures = require('./fixtures/transaction') diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 34ec9da..88ab286 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,5 +1,4 @@ -/* global describe, it, beforeEach */ - +const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const baddress = require('../src/address') const bcrypto = require('../src/crypto') diff --git a/test/types.js b/test/types.js index adc6f35..d245d53 100644 --- a/test/types.js +++ b/test/types.js @@ -1,5 +1,4 @@ -/* global describe, it */ - +const { describe, it } = require('mocha') const assert = require('assert') const types = require('../src/types') const typeforce = require('typeforce') From cf9a35f59bc6346bf4c6bee9466c58683fd55f2b Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:14:11 +1000 Subject: [PATCH 002/183] payments: more const --- src/payments/p2pk.js | 18 +++++++++--------- src/payments/p2pkh.js | 11 ++++++----- src/payments/p2sh.js | 3 ++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 9cddc81..9e12749 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -1,10 +1,10 @@ -let lazy = require('./lazy') -let typef = require('typeforce') -let OPS = require('bitcoin-ops') -let ecc = require('tiny-secp256k1') +const lazy = require('./lazy') +const typef = require('typeforce') +const OPS = require('bitcoin-ops') +const ecc = require('tiny-secp256k1') -let bscript = require('../script') -let BITCOIN_NETWORK = require('../networks').bitcoin +const bscript = require('../script') +const BITCOIN_NETWORK = require('../networks').bitcoin // input: {signature} // output: {pubKey} OP_CHECKSIG @@ -27,10 +27,10 @@ function p2pk (a, opts) { input: typef.maybe(typef.Buffer) }, a) - let _chunks = lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) - let network = a.network || BITCOIN_NETWORK - let o = { network } + const network = a.network || BITCOIN_NETWORK + const o = { network } lazy.prop(o, 'output', function () { if (!a.pubkey) return diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 08a4329..0ab9fa0 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -106,18 +106,19 @@ function p2pkh (a, opts) { a.output[23] !== OPS.OP_EQUALVERIFY || a.output[24] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') - if (hash && !hash.equals(a.output.slice(3, 23))) throw new TypeError('Hash mismatch') - else hash = a.output.slice(3, 23) + const hash2 = a.output.slice(3, 23) + if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + else hash = hash2 } if (a.pubkey) { - let pkh = bcrypto.hash160(a.pubkey) + const pkh = bcrypto.hash160(a.pubkey) if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') else hash = pkh } if (a.input) { - let chunks = _chunks() + const chunks = _chunks() if (chunks.length !== 2) throw new TypeError('Input is invalid') if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature') if (!ecc.isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey') @@ -125,7 +126,7 @@ function p2pkh (a, opts) { if (a.signature && !a.signature.equals(chunks[0])) throw new TypeError('Signature mismatch') if (a.pubkey && !a.pubkey.equals(chunks[1])) throw new TypeError('Pubkey mismatch') - let pkh = bcrypto.hash160(chunks[1]) + const pkh = bcrypto.hash160(chunks[1]) if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') } } diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index 7b95a45..9c80b09 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -111,7 +111,7 @@ function p2sh (a, opts) { if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch') if (_address().hash.length !== 20) throw new TypeError('Invalid address') - else hash = _address().hash + hash = _address().hash } if (a.hash) { @@ -125,6 +125,7 @@ function p2sh (a, opts) { a.output[0] !== OPS.OP_HASH160 || a.output[1] !== 0x14 || a.output[22] !== OPS.OP_EQUAL) throw new TypeError('Output is invalid') + const hash2 = a.output.slice(2, 22) if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 From 54ec449a751faa55d607d70d02904ad27d6120c0 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:20:28 +1000 Subject: [PATCH 003/183] payments/p2sh: try not to rely on o. in validation --- src/payments/p2sh.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index 9c80b09..b642154 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -58,7 +58,7 @@ function p2sh (a, opts) { const _redeem = lazy.value(function () { const chunks = _chunks() return { - network: network, + network, output: chunks[chunks.length - 1], input: bscript.compile(chunks.slice(0, -1)), witness: a.witness || [] @@ -166,9 +166,10 @@ function p2sh (a, opts) { if (a.redeem) { if (a.redeem.network && a.redeem.network !== network) throw new TypeError('Network mismatch') - if (o.redeem) { - if (a.redeem.output && !a.redeem.output.equals(o.redeem.output)) throw new TypeError('Redeem.output mismatch') - if (a.redeem.input && !a.redeem.input.equals(o.redeem.input)) throw new TypeError('Redeem.input mismatch') + if (a.input) { + const redeem = _redeem() + if (a.redeem.output && !a.redeem.output.equals(redeem.output)) throw new TypeError('Redeem.output mismatch') + if (a.redeem.input && !a.redeem.input.equals(redeem.input)) throw new TypeError('Redeem.input mismatch') } checkRedeem(a.redeem) From 3ed77c4820d3e5ddf4bb38fe06da6d63ea67b22e Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:22:11 +1000 Subject: [PATCH 004/183] payments: cleanup --- src/payments/p2pk.js | 7 ++----- src/payments/p2wpkh.js | 1 - src/payments/p2wsh.js | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 9e12749..5f65030 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -58,13 +58,10 @@ function p2pk (a, opts) { // extended validation if (opts.validate) { - if (a.pubkey && a.output) { - if (!a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch') - } - if (a.output) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') if (!ecc.isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid') + if (a.pubkey && !a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch') } if (a.signature) { @@ -73,7 +70,7 @@ function p2pk (a, opts) { if (a.input) { if (_chunks().length !== 1) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(_chunks()[0])) throw new TypeError('Input has invalid signature') + if (!bscript.isCanonicalScriptSignature(o.signature)) throw new TypeError('Input has invalid signature') } } diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index ba42ba1..c47c354 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -93,7 +93,6 @@ function p2wpkh (a, opts) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') if (_address().data.length !== 20) throw new TypeError('Invalid address data') - // if (hash && !hash.equals(_address().data)) throw new TypeError('Hash mismatch') hash = _address().data } diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index c84d822..8c45022 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -122,7 +122,7 @@ function p2wsh (a, opts) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') if (_address().data.length !== 32) throw new TypeError('Invalid address data') - else hash = _address().data + hash = _address().data } if (a.hash) { From 55207e57427b30ae4380d30dd33e867ac6e1b773 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:44:02 +1000 Subject: [PATCH 005/183] tests/payments/p2pk*: add signature mismatch tests --- src/payments/p2pk.js | 2 +- test/fixtures/p2pk.json | 13 +++++++++++++ test/fixtures/p2pkh.json | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 5f65030..4073d52 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -65,7 +65,7 @@ function p2pk (a, opts) { } if (a.signature) { - if (a.input && !a.input.equals(o.input)) throw new TypeError('Input mismatch') + if (a.input && !a.input.equals(o.input)) throw new TypeError('Signature mismatch') } if (a.input) { diff --git a/test/fixtures/p2pk.json b/test/fixtures/p2pk.json index 7ede5f4..a07c5b8 100644 --- a/test/fixtures/p2pk.json +++ b/test/fixtures/p2pk.json @@ -116,6 +116,19 @@ "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", "input": "ffffffffffffffff" } + }, + { + "exception": "Input has invalid signature", + "arguments": { + "input": "30060201ff0201ff01" + } + }, + { + "exception": "Signature mismatch", + "arguments": { + "signature": "300602010002010001", + "input": "300602010302010301" + } } ], "dynamic": { diff --git a/test/fixtures/p2pkh.json b/test/fixtures/p2pkh.json index d16b181..118111d 100644 --- a/test/fixtures/p2pkh.json +++ b/test/fixtures/p2pkh.json @@ -204,6 +204,13 @@ "hash": "ffffffffffffffffffffffffffffffffffffffff", "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001" } + }, + { + "exception": "Signature mismatch", + "arguments": { + "signature": "300602010002010001", + "input": "300602010302010301 030000000000000000000000000000000000000000000000000000000000000001" + } } ], "dynamic": { From 1051946f0014b3ff701ec0f64e3ef0e579c0635f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:44:20 +1000 Subject: [PATCH 006/183] tests/payments/p2pk: fix wrong fixture names --- test/fixtures/p2pk.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fixtures/p2pk.json b/test/fixtures/p2pk.json index a07c5b8..a9e1063 100644 --- a/test/fixtures/p2pk.json +++ b/test/fixtures/p2pk.json @@ -7,7 +7,7 @@ }, "expected": { "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", - "signatures": null, + "signature": null, "input": null, "witness": null } @@ -19,7 +19,7 @@ }, "expected": { "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", - "signatures": null, + "signature": null, "input": null, "witness": null } From cd9e6d1d5e6bf219a86dc4bd555e1c26733cdcae Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 20:59:13 +1000 Subject: [PATCH 007/183] tests/p2wsh: add secondary stacksEqual test --- test/fixtures/p2wsh.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json index 9579f64..2f7b9cc 100644 --- a/test/fixtures/p2wsh.json +++ b/test/fixtures/p2wsh.json @@ -269,6 +269,20 @@ ] } }, + { + "exception": "Witness and redeem.witness mismatch", + "arguments": { + "redeem": { + "output": "OP_TRUE", + "witness": [ + "04000000ff" + ] + }, + "witness": [ + "04000000ee" + ] + } + }, { "exception": "Ambiguous witness source", "arguments": { From 89eb6fac03bc022b53b81ed4e103dfa509af92b1 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 21 Aug 2018 17:52:17 +1000 Subject: [PATCH 008/183] break test/transaction_builder contruct stages, add sequential example --- test/fixtures/transaction_builder.json | 22 ++++++ test/transaction_builder.js | 94 ++++++++++++++++---------- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 6896f30..7a3a8d2 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -1547,6 +1547,28 @@ ] } ], + "fromTransactionSequential": [ + { + "description": "Transaction w/ P2SH(P2MS 2/3) -> ?", + "network": "testnet", + "txHex": "0100000001b033b2214568b49fda417371aba0634b0303a2b6a19884c25d03d0b91bdbe231000000006f000000004c6952210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a9121038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f2103b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d953aeffffffff0200e1f5050000000017a914a9974100aeee974a20cda9a2f545704a0ab54fdc87c72831010000000017a9149f57a6712ef023f85ffac631ed4263b977b2d0678700000000", + "txHexAfter": "0100000001b033b2214568b49fda417371aba0634b0303a2b6a19884c25d03d0b91bdbe23100000000b60000004730440220793d87f2a8afeb856816efa38984418c692c15170e99ca371f547454079c0dd3022074ae95e438fee1f37619fabe0ce1083c3be0d65c3defb5337833d50fdc694b13014c6952210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a9121038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f2103b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d953aeffffffff0200e1f5050000000017a914a9974100aeee974a20cda9a2f545704a0ab54fdc87c72831010000000017a9149f57a6712ef023f85ffac631ed4263b977b2d0678700000000", + "incomplete": true, + "inputs": [ + { + "vout": 0, + "scriptSig": "OP_0 OP_0 OP_0 OP_0 52210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a9121038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f2103b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d953ae", + "scriptSigAfter": "OP_0 OP_0 OP_0 30440220793d87f2a8afeb856816efa38984418c692c15170e99ca371f547454079c0dd3022074ae95e438fee1f37619fabe0ce1083c3be0d65c3defb5337833d50fdc694b1301 52210258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a9121038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f2103b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d953ae", + "signs": [ + { + "keyPair": "cTkcnMZoFYH1UgumzCFHv2veLMNN1PaJyHHUxFT127zhNGBqqEZ2", + "redeemScript": "OP_2 0258db1bb3801f1ecde47602143beaeb9cac93251724b8e589fae5c08c1a399a91 038e803e3d84cfc821cc8bf46233a9c2bb359d529db0bcdd3f1a4f38678dd02d7f 03b83e59d848407d7f62a82c99905f5ca3e8e8f5d6400eb78a0b4b067aea0720d9 OP_3 OP_CHECKMULTISIG" + } + ] + } + ] + } + ], "classification": { "hex": "01000000059c06fb641a8cd69be81ca91e68d8a115cb698396876ecd77120ec1e4ab9002279f000000b500483045022100d58f828ab39cfac592f89fe372fb520992975218698c683a893f29e39cf0080302207cc0485dab5ce621089bdd15e1f15db0ecbde8dd4bb661bcf0e3af6ecab075e6014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff0821dc00213d2b7993f8f2a1553800c6f2f31106da176505d0ade467b68401d795000000b400473044022028e937a7bba888fe3428f442f6e22d92ce2ddba01548c38780d40890fa6cc305022043204d0bcfb1150b045d54cf9b13462e44e2ef47fee03d3cea08e84a8060fc30014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffffaa997ac385dc666af1f5947ef615431024eb314cac2308d5e1b903e28ca466f499000000b50048304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e85252014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffffd9f61bf98a021ee144f33ba5a6b04274de8fcb5c05f1ff7c12367fb7a608b2dd9e000000b4004730440220456e1201c1fa727288cba7fa0054dc02d8dd6c7418cae1e97006ef0652891c9202201192d0fbf3a9c00afb99a415f2bf515509e1150805acd8de95c496c27cb6570f014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff1f8119e3bc7c2f451feaa79f42ec5a63502afb425c253c935e43d217d5c29bdea1000000b500483045022100f669004f770490093eba4ac4903cb7581f7d18ea9245c538585ef5367e520e4702205485fafe0be178563a599d41e0cc172bb01314ed65d0e48df19a5258f17bdbc4014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff0380f0fa02000000001976a91439692085cf9d27e8c1cf63e76bd32d9bd15cab8b88ac50c300000000000017a9147204bb26950ce1595255897f63d205779f033f3e875b5409000000000017a9142538893d984a4b5695e4bfde1a90a9f02fabf8e38700000000" }, diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 34ec9da..93f407e 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -19,9 +19,46 @@ function getAddress (node) { return baddress.toBase58Check(bcrypto.hash160(node.publicKey), NETWORKS.bitcoin.pubKeyHash) } +function constructSign (f, txb) { + const network = NETWORKS[f.network] + const stages = f.stages && f.stages.concat() + + f.inputs.forEach(function (input, index) { + if (!input.signs) return + input.signs.forEach(function (sign) { + const keyPair = ECPair.fromWIF(sign.keyPair, network) + let redeemScript + let witnessScript + let value + + if (sign.redeemScript) { + redeemScript = bscript.fromASM(sign.redeemScript) + } + + if (sign.value) { + value = sign.value + } + + if (sign.witnessScript) { + witnessScript = bscript.fromASM(sign.witnessScript) + } + + txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript) + + if (sign.stage) { + const tx = txb.buildIncomplete() + assert.strictEqual(tx.toHex(), stages.shift()) + txb = TransactionBuilder.fromTransaction(tx, network) + } + }) + }) + + return txb +} + function construct (f, dontSign) { const network = NETWORKS[f.network] - let txb = new TransactionBuilder(network) + const txb = new TransactionBuilder(network) if (Number.isFinite(f.version)) txb.setVersion(f.version) if (f.locktime !== undefined) txb.setLockTime(f.locktime) @@ -55,39 +92,7 @@ function construct (f, dontSign) { }) if (dontSign) return txb - - const stages = f.stages && f.stages.concat() - f.inputs.forEach(function (input, index) { - if (!input.signs) return - input.signs.forEach(function (sign) { - const keyPair = ECPair.fromWIF(sign.keyPair, network) - let redeemScript - let witnessScript - let value - - if (sign.redeemScript) { - redeemScript = bscript.fromASM(sign.redeemScript) - } - - if (sign.value) { - value = sign.value - } - - if (sign.witnessScript) { - witnessScript = bscript.fromASM(sign.witnessScript) - } - - txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript) - - if (sign.stage) { - const tx = txb.buildIncomplete() - assert.strictEqual(tx.toHex(), stages.shift()) - txb = TransactionBuilder.fromTransaction(tx, network) - } - }) - }) - - return txb + return constructSign(f, txb) } describe('TransactionBuilder', function () { @@ -142,6 +147,27 @@ describe('TransactionBuilder', function () { }) }) + fixtures.valid.fromTransactionSequential.forEach(function (f) { + it('with ' + f.description, function () { + const network = NETWORKS[f.network] + const tx = Transaction.fromHex(f.txHex) + const txb = TransactionBuilder.fromTransaction(tx, network) + + tx.ins.forEach(function (input, i) { + assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSig) + }) + + constructSign(f, txb) + const txAfter = f.incomplete ? txb.buildIncomplete() : txb.build() + + txAfter.ins.forEach(function (input, i) { + assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter) + }) + + assert.equal(txAfter.toHex(), f.txHexAfter) + }) + }) + it('classifies transaction inputs', function () { const tx = Transaction.fromHex(fixtures.valid.classification.hex) const txb = TransactionBuilder.fromTransaction(tx) From 24d541d0ed13afaeaf866f262fc5a7b592b64572 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 28 Aug 2018 14:21:18 +0900 Subject: [PATCH 009/183] Fix default assignment of validate key for payments Fixes problems with p2ms experienced in issue below. Related: #1194 --- src/payments/embed.js | 2 +- src/payments/p2ms.js | 2 +- src/payments/p2pk.js | 2 +- src/payments/p2pkh.js | 2 +- src/payments/p2sh.js | 2 +- src/payments/p2wpkh.js | 2 +- src/payments/p2wsh.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/payments/embed.js b/src/payments/embed.js index c636c80..ea2c8e9 100644 --- a/src/payments/embed.js +++ b/src/payments/embed.js @@ -19,7 +19,7 @@ function p2data (a, opts) { !a.data && !a.output ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ network: typef.maybe(typef.Object), diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index 15de44e..5c90a4d 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -24,7 +24,7 @@ function p2ms (a, opts) { !(a.pubkeys && a.m !== undefined) && !a.signatures ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) function isAcceptableSignature (x) { return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 4073d52..b930612 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -16,7 +16,7 @@ function p2pk (a, opts) { !a.input && !a.signature ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ network: typef.maybe(typef.Object), diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 0ab9fa0..e9248a2 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -18,7 +18,7 @@ function p2pkh (a, opts) { !a.pubkey && !a.input ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ network: typef.maybe(typef.Object), diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index b642154..4741936 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -26,7 +26,7 @@ function p2sh (a, opts) { !a.redeem && !a.input ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ network: typef.maybe(typef.Object), diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index c47c354..1483bd8 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -21,7 +21,7 @@ function p2wpkh (a, opts) { !a.pubkey && !a.witness ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ address: typef.maybe(typef.String), diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index 8c45022..a26e706 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -28,7 +28,7 @@ function p2wsh (a, opts) { !a.redeem && !a.witness ) throw new TypeError('Not enough data') - opts = opts || { validate: true } + opts = Object.assign({ validate: true }, opts || {}) typef({ network: typef.maybe(typef.Object), From f84a5d18a3246d5f2a05f6b170c356dbc79d2e02 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 3 Sep 2018 12:05:06 +0900 Subject: [PATCH 010/183] Fix test cases to make sure that validate: true is being set to default --- test/fixtures/embed.json | 9 +++++++++ test/fixtures/p2ms.json | 4 ++++ test/fixtures/p2pk.json | 2 ++ test/fixtures/p2pkh.json | 2 ++ test/fixtures/p2sh.json | 2 ++ test/fixtures/p2wpkh.json | 2 ++ test/fixtures/p2wsh.json | 2 ++ test/transaction_builder.js | 2 +- 8 files changed, 24 insertions(+), 1 deletion(-) diff --git a/test/fixtures/embed.json b/test/fixtures/embed.json index ccc0e70..40e43cd 100644 --- a/test/fixtures/embed.json +++ b/test/fixtures/embed.json @@ -5,6 +5,7 @@ "arguments": { "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4" }, + "options": {}, "expected": { "data": [ "a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4" @@ -35,6 +36,14 @@ { "exception": "Not enough data", "arguments": {} + }, + { + "description": "First OP is not OP_RETURN", + "exception": "Output is invalid", + "options": {}, + "arguments": { + "output": "OP_1 OP_2 OP_ADD" + } } ], "dynamic": { diff --git a/test/fixtures/p2ms.json b/test/fixtures/p2ms.json index d5bb0c8..8ea033e 100644 --- a/test/fixtures/p2ms.json +++ b/test/fixtures/p2ms.json @@ -5,6 +5,7 @@ "arguments": { "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG" }, + "options": {}, "expected": { "m": 2, "n": 2, @@ -239,6 +240,7 @@ { "description": "n !== output pubkeys", "exception": "Output is invalid", + "options": {}, "arguments": { "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_2 OP_CHECKMULTISIG" } @@ -266,6 +268,7 @@ }, { "exception": "Pubkeys mismatch", + "options": {}, "arguments": { "pubkeys": [ "030000000000000000000000000000000000000000000000000000000000000001" @@ -325,6 +328,7 @@ { "description": "Missing OP_0", "exception": "Input is invalid", + "options": {}, "arguments": { "m": 2, "pubkeys": [ diff --git a/test/fixtures/p2pk.json b/test/fixtures/p2pk.json index a9e1063..58f51cb 100644 --- a/test/fixtures/p2pk.json +++ b/test/fixtures/p2pk.json @@ -5,6 +5,7 @@ "arguments": { "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG" }, + "options": {}, "expected": { "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", "signature": null, @@ -97,6 +98,7 @@ }, { "exception": "Pubkey mismatch", + "options": {}, "arguments": { "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", "output": "030000000000000000000000000000000000000000000000000000000000000002 OP_CHECKSIG" diff --git a/test/fixtures/p2pkh.json b/test/fixtures/p2pkh.json index 118111d..44c20fe 100644 --- a/test/fixtures/p2pkh.json +++ b/test/fixtures/p2pkh.json @@ -5,6 +5,7 @@ "arguments": { "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh" }, + "options": {}, "expected": { "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", @@ -103,6 +104,7 @@ { "description": "Unexpected OP_DUP", "exception": "Output is invalid", + "options": {}, "arguments": { "output": "OP_DUP OP_DUP 168b992bcfc44050310b3a94bd0771136d0b28d137 OP_EQUALVERIFY" } diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json index 44611a5..e6fe2ae 100644 --- a/test/fixtures/p2sh.json +++ b/test/fixtures/p2sh.json @@ -5,6 +5,7 @@ "arguments": { "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT" }, + "options": {}, "expected": { "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", @@ -182,6 +183,7 @@ { "description": "Expected OP_HASH160", "exception": "Output is invalid", + "options": {}, "arguments": { "output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL" } diff --git a/test/fixtures/p2wpkh.json b/test/fixtures/p2wpkh.json index 7341907..f667bdc 100644 --- a/test/fixtures/p2wpkh.json +++ b/test/fixtures/p2wpkh.json @@ -5,6 +5,7 @@ "arguments": { "address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d" }, + "options": {}, "expected": { "hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727", "output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727", @@ -108,6 +109,7 @@ }, { "exception": "Pubkey mismatch", + "options": {}, "arguments": { "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", "witness": [ diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json index 2f7b9cc..0870278 100644 --- a/test/fixtures/p2wsh.json +++ b/test/fixtures/p2wsh.json @@ -5,6 +5,7 @@ "arguments": { "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q" }, + "options": {}, "expected": { "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", @@ -221,6 +222,7 @@ }, { "exception": "Output is invalid", + "options": {}, "arguments": { "output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff OP_EQUAL" } diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 34ec9da..05dbbe3 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -477,7 +477,7 @@ describe('TransactionBuilder', function () { redeem: payments.p2ms({ output: redeemScript, signatures - }, { allowIncomplete: true }) + }, { allowIncomplete: true, validate: false }) }).input assert.strictEqual(bscript.toASM(replacement), sign.scriptSigFiltered) From d06c149ec3d3d2594fe816049539b8abce550aea Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 3 Sep 2018 13:46:16 +1000 Subject: [PATCH 011/183] avoid special code path, add explicit fixture overwrite --- test/fixtures/transaction_builder.json | 7 +++---- test/transaction_builder.js | 26 ++++++-------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 6896f30..6cc6851 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -1491,7 +1491,7 @@ ], "fromTransaction": [ { - "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | 1 OP_0, no signatures", + "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | 1 OP_0 fixes to 2 OP_0, no signatures", "network": "testnet", "incomplete": true, "inputs": [ @@ -1785,11 +1785,10 @@ "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" }, { - "filterOP_0": true, "pubKeyIndex": 0, "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", - "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae", - "scriptSigFiltered": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" + "scriptSigBefore": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae", + "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae" } ] } diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 05dbbe3..0aaed24 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -463,27 +463,12 @@ describe('TransactionBuilder', function () { 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) { - const scriptSig = tx.ins[i].script - - // ignore OP_0 on the front, ignore redeemScript - const signatures = bscript.decompile(scriptSig) - .slice(1, -1) - .filter(x => x !== ops.OP_0) - - // rebuild/replace the scriptSig without them - const replacement = payments.p2sh({ - redeem: payments.p2ms({ - output: redeemScript, - signatures - }, { allowIncomplete: true, validate: false }) - }).input - assert.strictEqual(bscript.toASM(replacement), sign.scriptSigFiltered) - - tx.ins[i].script = replacement + // manually override the scriptSig? + if (sign.scriptSigBefore) { + tx.ins[i].script = bscript.fromASM(sign.scriptSigBefore) } - // now import it + + // rebuild txb = TransactionBuilder.fromTransaction(tx, network) } @@ -492,6 +477,7 @@ describe('TransactionBuilder', function () { // update the tx tx = txb.buildIncomplete() + // now verify the serialized scriptSig is as expected assert.strictEqual(bscript.toASM(tx.ins[i].script), sign.scriptSig) }) From b906fd6be6bb6b731d6e6a41ddb0359f31b332cf Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 13 Sep 2018 08:50:14 +1000 Subject: [PATCH 012/183] CHANGELOG: amend script.decompile return type --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6cd2a3..b3985c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ __changed__ - `ECPair` (and all ECDSA code) now uses [`tiny-secp256k1`](http://github.com/bitcoinjs/tiny-secp256k1), which uses the [`libsecp256k1` library](https://github.com/bitcoin-core/secp256k1) (#1070) - `TransactionBuilder` internal variables are now `__` prefixed to discourage public usage (#1038) - `TransactionBuilder` now defaults to version 2 transaction versions (#1036) -- `script.decompile` now returns `Buffer` or `null`, if decompilation failed (#1039) +- `script.decompile` now returns `[Buffer]` or `null`, if decompilation failed (#1039) __fixed__ - Fixed `TransactionBuilder` rejecting uncompressed public keys to comply with BIP143 (#987) From 07fcbe5890d4ef1b63ba4f6e131162d62a18fb52 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 13 Sep 2018 17:34:42 +1000 Subject: [PATCH 013/183] rm unused imports --- test/transaction_builder.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 88294fb..5a6b86f 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -4,8 +4,6 @@ const assert = require('assert') const baddress = require('../src/address') const bcrypto = require('../src/crypto') const bscript = require('../src/script') -const ops = require('bitcoin-ops') -const payments = require('../src/payments') const ECPair = require('../src/ecpair') const Transaction = require('../src/transaction') From 1c64094c2949747cb7ae4434d4a163611b7ef35e Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 13 Sep 2018 17:34:50 +1000 Subject: [PATCH 014/183] use hoodwink@2.0.0 --- package.json | 2 +- test/ecpair.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index a696033..6d6b524 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "bn.js": "^4.11.8", "bs58": "^4.0.0", "dhttp": "^2.5.0", - "hoodwink": "^1.0.0", + "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", "nyc": "^11.8.0", diff --git a/test/ecpair.js b/test/ecpair.js index 8a246f1..78223ca 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -187,8 +187,8 @@ describe('ECPair', function () { }) it('loops until d is within interval [1, n) : 1', hoodwink(function () { - const rng = this.stub(function f () { - if (f.calls === 0) return ZERO // 0 + const rng = this.stub(function () { + if (rng.calls === 0) return ZERO // 0 return ONE // >0 }, 2) @@ -196,9 +196,9 @@ describe('ECPair', function () { })) it('loops until d is within interval [1, n) : n - 1', hoodwink(function () { - const rng = this.stub(function f () { - if (f.calls === 0) return ZERO // <1 - if (f.calls === 1) return GROUP_ORDER // >n-1 + const rng = this.stub(function () { + if (rng.calls === 0) return ZERO // <1 + if (rng.calls === 1) return GROUP_ORDER // >n-1 return GROUP_ORDER_LESS_1 // n-1 }, 3) From 09b2475117b2553547eb0fc360946722a457119f Mon Sep 17 00:00:00 2001 From: JP Richardson Date: Sun, 16 Sep 2018 01:17:04 -0500 Subject: [PATCH 015/183] remove superfluous package.json file in payments/ --- src/payments/package.json | 40 --------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/payments/package.json diff --git a/src/payments/package.json b/src/payments/package.json deleted file mode 100644 index 9383db2..0000000 --- a/src/payments/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "bitcoinjs-playground", - "version": "1.0.0", - "description": "Go nuts!", - "main": "_testnet.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/bitcoinjs/bitcoinjs-playground.git" - }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/bitcoinjs/bitcoinjs-playground/issues" - }, - "homepage": "https://github.com/bitcoinjs/bitcoinjs-playground#readme", - "dependencies": { - "async": "^2.5.0", - "bech32": "^1.1.3", - "bip21": "^2.0.1", - "bip32-utils": "^0.11.1", - "bip38": "^2.0.2", - "bip39": "^2.5.0", - "bip69": "^2.1.1", - "bitcoin-ops": "^1.4.1", - "bitcoinjs-lib": "^3.3.2", - "bs58": "^4.0.1", - "bs58check": "^2.1.1", - "cb-http-client": "^0.2.3", - "coinselect": "^3.1.11", - "dhttp": "^2.4.2", - "merkle-lib": "^2.0.10", - "mocha": "^5.0.5", - "tape": "^4.9.0", - "typeforce": "^1.11.4", - "utxo": "^2.0.4" - } -} From 35dbcfaa0c8898a7584267e6d9bcee9d55af3331 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sun, 16 Sep 2018 16:52:36 +1000 Subject: [PATCH 016/183] CHANGELOG: note TxBuilder fixes --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3985c8..210f6da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 4.0.2 +__fixed__ +- Fixed `TransactionBuilder` not throwing when payment type validation should fail (#1195) + # 4.0.1 __fixed__ - Fixed `tiny-secp256k1` dependency version (used `ecurve`) (#1139) From c8b7906058b310d2887ce891054a0db7d11d081a Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sun, 16 Sep 2018 16:52:46 +1000 Subject: [PATCH 017/183] 4.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d6b524..dadea12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "4.0.1", + "version": "4.0.2", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "engines": { From a309ee53e2f1432e93003afadd132ed29f05c206 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sun, 16 Sep 2018 16:54:51 +1000 Subject: [PATCH 018/183] CHANGELOG: add rogue packagejson removal --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 210f6da..907c6d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ __fixed__ - Fixed `TransactionBuilder` not throwing when payment type validation should fail (#1195) +__removed__ +- Removed rogue `package.json` from `src/payments` (#1216) + # 4.0.1 __fixed__ - Fixed `tiny-secp256k1` dependency version (used `ecurve`) (#1139) From f89ef93d1e7dc7d31b0dedfd5076364bb781d177 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Sep 2018 10:38:18 +1000 Subject: [PATCH 019/183] rm empty file --- src/payments/p2data.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/payments/p2data.js diff --git a/src/payments/p2data.js b/src/payments/p2data.js deleted file mode 100644 index e69de29..0000000 From da88e1c5af215292b6507f25ac29e5a0316e4204 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 24 Sep 2018 15:24:23 +1000 Subject: [PATCH 020/183] bump dhttp --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dadea12..755be28 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "bip68": "^1.0.3", "bn.js": "^4.11.8", "bs58": "^4.0.0", - "dhttp": "^2.5.0", + "dhttp": "^3.0.0", "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", From 4616d24016a743ad8e687adcb556a1569efbe2bf Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 15:47:28 +1000 Subject: [PATCH 021/183] tests/txb: remove getAddress --- test/transaction_builder.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 4911cbb..554257e 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,8 +1,8 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const baddress = require('../src/address') -const bcrypto = require('../src/crypto') const bscript = require('../src/script') +const payments = require('../src/payments') const ECPair = require('../src/ecpair') const Transaction = require('../src/transaction') @@ -11,11 +11,6 @@ const NETWORKS = require('../src/networks') const fixtures = require('./fixtures/transaction_builder') -// TODO: remove -function getAddress (node) { - return baddress.toBase58Check(bcrypto.hash160(node.publicKey), NETWORKS.bitcoin.pubKeyHash) -} - function constructSign (f, txb) { const network = NETWORKS[f.network] const stages = f.stages && f.stages.concat() @@ -251,7 +246,7 @@ describe('TransactionBuilder', function () { }) it('accepts an address string and value', function () { - const address = getAddress(keyPair) + const { address } = payments.p2pkh({ pubkey: keyPair.publicKey }) const vout = txb.addOutput(address, 1000) assert.strictEqual(vout, 0) From 43f52c452b764fd41b307bb57c433d29cb2acaf9 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 14:35:47 +1000 Subject: [PATCH 022/183] tests: enforce something threw for invalid cases --- test/transaction_builder.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 554257e..7112be0 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -340,6 +340,7 @@ describe('TransactionBuilder', function () { it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), function () { const txb = construct(f, true) + let threw = false f.inputs.forEach(function (input, index) { input.signs.forEach(function (sign) { const keyPairNetwork = NETWORKS[sign.network || f.network] @@ -355,15 +356,18 @@ describe('TransactionBuilder', function () { witnessScript = bscript.fromASM(sign.witnessScript) } - if (!sign.throws) { - txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript) - } else { + if (sign.throws) { assert.throws(function () { txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript) }, new RegExp(f.exception)) + threw = true + } else { + txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript) } }) }) + + assert.equal(threw, true) }) }) }) From acdfb34545bf38f80189fbb6a2e3365563d1304d Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 23 Aug 2018 12:38:01 +1000 Subject: [PATCH 023/183] rename Sighash: to SIGHASH --- test/fixtures/transaction_builder.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 4ddc5cb..83ae4eb 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -443,7 +443,7 @@ ] }, { - "description": "Sighash: SINGLE (random)", + "description": "SIGHASH SINGLE (random)", "txHex": "01000000012ffb29d53528ad30c37c267fbbeda3c6fce08f5f6f5d3b1eab22193599a3612a010000006b483045022100f963f1d9564075a934d7c3cfa333bd1378859b84cba947e149926fc9ec89b5ae02202b5b912e507bae65002aff972f9752e2aeb2e22c5fdbaaad672090378184df37032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff0260a62f01000000001976a9140de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b888ac80969800000000001976a91454d0e925d5ee0ee26768a237067dee793d01a70688ac00000000", "version": 1, "inputs": [ @@ -473,7 +473,7 @@ ] }, { - "description": "Sighash: ALL", + "description": "SIGHASH ALL", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402206abb0622b8b6ca83f1f4de84830cf38bf4615dc9e47a7dcdcc489905f26aa9cb02201d2d8a7815242b88e4cd66390ca46da802238f9b1395e0d118213d30dad38184012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100de13b42804f87a09bb46def12ab4608108d8c2db41db4bc09064f9c46fcf493102205e5c759ab7b2895c9b0447e56029f6895ff7bb20e0847c564a88a3cfcf080c4f012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b4830450221009100a3f5b30182d1cb0172792af6947b6d8d42badb0539f2c209aece5a0628f002200ae91702ca63347e344c85fcb536f30ee97b75cdf4900de534ed5e040e71a548012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ @@ -533,7 +533,7 @@ ] }, { - "description": "Sighash: ALL | ANYONECANPAY", + "description": "SIGHASH ALL | ANYONECANPAY", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100bd2829550e9b3a081747281029b5f5a96bbd83bb6a92fa2f8310f1bd0d53abc90220071b469417c55cdb3b04171fd7900d2768981b7ab011553d84d24ea85d277079812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206295e17c45c6356ffb20365b696bcbb869db7e8697f4b8a684098ee2bff85feb02202905c441abe39ec9c480749236b84fdd3ebd91ecd25b559136370aacfcf2815c812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100f58e7c98ac8412944d575bcdece0e5966d4018f05988b5b60b6f46b8cb7a543102201c5854d3361e29b58123f34218cec2c722f5ec7a08235ebd007ec637b07c193a812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ @@ -593,7 +593,7 @@ ] }, { - "description": "Sighash: SINGLE", + "description": "SIGHASH SINGLE", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e822f152bb15a1d623b91913cd0fb915e9f85a8dc6c26d51948208bbc0218e800220255f78549d9614c88eac9551429bc00224f22cdcb41a3af70d52138f7e98d333032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206f37f79adeb86e0e2da679f79ff5c3ba206c6d35cd9a21433f0de34ee83ddbc00220118cabbac5d83b3aa4c2dc01b061e4b2fe83750d85a72ae6a1752300ee5d9aff032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a473044022042ac843d220a56b3de05f24c85a63e71efa7e5fc7c2ec766a2ffae82a88572b0022051a816b317313ea8d90010a77c3e02d41da4a500e67e6a5347674f836f528d82032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ @@ -653,7 +653,7 @@ ] }, { - "description": "Sighash: SINGLE|ANYONECANPAY", + "description": "SIGHASH SINGLE|ANYONECANPAY", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100d05a3b6cf2f0301000b0e45c09054f2c61570ce8798ebf571eef72da3b1c94a1022016d7ef3c133fa703bae2c75158ea08d335ac698506f99b3c369c37a9e8fc4beb832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100ee6bf07b051001dcbfa062692a40adddd070303286b714825b3fb4693dd8fcdb022056610885e5053e5d47f2be3433051305abe7978ead8f7cf2d0368947aff6b307832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100cfc930d5b5272d0220d9da98fabec97b9e66306f735efa837f43f6adc675cad902202f9dff76b8b9ec8f613d46094f17f64d875804292d8804aa59fd295b6fc1416b832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ @@ -713,7 +713,7 @@ ] }, { - "description": "Sighash: NONE", + "description": "SIGHASH NONE", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e7f0a1ddd2c0b81e093e029b8a503afa27fe43549b0668d2141abf35eb3a63be022037f12d12cd50fc94a135f933406a8937557de9b9566a8841ff1548c1b6984531022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a473044022008451123ec2535dab545ade9d697519e63b28df5e311ea05e0ce28d39877a7c8022061ce5dbfb7ab478dd9e05b0acfd959ac3eb2641f61958f5d352f37621073d7c0022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a47304402205c001bcdfb35c70d8aa3bdbc75399afb72eb7cf1926ca7c1dfcddcb4d4d3e0f8022028992fffdcd4e9f34ab726f97c24157917641c2ef99361f588e3d4147d46eea5022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ @@ -773,7 +773,7 @@ ] }, { - "description": "Sighash: NONE | ANYONECANPAY", + "description": "SIGHASH NONE | ANYONECANPAY", "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402204ed272952177aaa5a1b171c2ca5a7a3d300ffcd7e04b040c0baaa4e3561862a502207e65a5b8f99c8a632b186c8a60496a12bf3116f51909b7497413aefdc3be7bf6822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402203ec365300cc67602f4cc5be027959d3667b48db34c6c87d267c94a7e210d5c1f02204843350311c0a9711cad1960b17ce9e323a1ce6f37deefc3ffe63082d480be92822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b48304502210084f86f905c36372eff9c54ccd509a519a3325bcace8abfeed7ed3f0d579979e902201ff330dd2402e5ca9989a8a294fa36d6cf3a093edb18d29c9d9644186a3efeb4822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000", "version": 1, "inputs": [ From ed1c1a5661efa2f274b4a57f6a0b5a8dd68c4e2d Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 27 Jul 2018 15:55:17 +1000 Subject: [PATCH 024/183] txb: enforce outputs exist when signing --- src/transaction_builder.js | 10 ++++++++-- test/fixtures/transaction_builder.json | 17 +++++++++++++++++ test/transaction_builder.js | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 8706841..597c1d0 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -633,6 +633,8 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network') if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin) + if (this.__needsOutputs()) throw new Error('Transaction needs outputs') + hashType = hashType || Transaction.SIGHASH_ALL const input = this.__inputs[vin] @@ -694,8 +696,7 @@ function signatureHashType (buffer) { TransactionBuilder.prototype.__canModifyInputs = function () { return this.__inputs.every(function (input) { - // any signatures? - if (input.signatures === undefined) return true + if (!input.signatures) return true return input.signatures.every(function (signature) { if (!signature) return true @@ -708,6 +709,11 @@ TransactionBuilder.prototype.__canModifyInputs = function () { }) } +// TODO: handle incomplete SIGHASH_NONE flow +TransactionBuilder.prototype.__needsOutputs = function () { + return this.__tx.outs.length === 0 +} + TransactionBuilder.prototype.__canModifyOutputs = function () { const nInputs = this.__tx.ins.length const nOutputs = this.__tx.outs.length diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 83ae4eb..62c410a 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -2357,6 +2357,23 @@ "value": 1000 } ] + }, + { + "description": "Transaction w/ no outputs", + "exception": "Transaction needs outputs", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "throws": true + } + ] + } + ], + "outputs": [] } ], "fromTransaction": [ diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 7112be0..bd0a3ab 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -313,6 +313,7 @@ describe('TransactionBuilder', function () { it('throws if if there exist any scriptSigs', function () { const txb = new TransactionBuilder() txb.addInput(txHash, 0) + txb.addOutput(scripts[0], 100) txb.sign(0, keyPair) assert.throws(function () { From 2223e6170ee964f2637d3840e2beea25025fe707 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 14:39:55 +1000 Subject: [PATCH 025/183] txb/tests: test solo SIGHASH_ALL, support existing SIGHASH_NONE --- src/transaction_builder.js | 14 ++++++++++++-- test/fixtures/transaction_builder.json | 11 ++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 597c1d0..232c9a2 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -709,9 +709,19 @@ TransactionBuilder.prototype.__canModifyInputs = function () { }) } -// TODO: handle incomplete SIGHASH_NONE flow TransactionBuilder.prototype.__needsOutputs = function () { - return this.__tx.outs.length === 0 + // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs + // .build() will fail, but .buildIncomplete() is OK + return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { + if (!input.signatures) return false + + return input.signatures.some((signature) => { + if (!signature) return false // no signature, no issue + const hashType = signatureHashType(signature) + if (hashType & Transaction.SIGHASH_NONE) return false // SIGHASH_NONE doesn't care about outputs + return true // SIGHASH_* does care + }) + }) } TransactionBuilder.prototype.__canModifyOutputs = function () { diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 62c410a..607e16a 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -2359,12 +2359,21 @@ ] }, { - "description": "Transaction w/ no outputs", + "description": "Transaction w/ no outputs (but 1 SIGHASH_ALL)", "exception": "Transaction needs outputs", "inputs": [ { "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "vout": 0, + "signs": [ + { + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + } + ] + }, + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 1, "signs": [ { "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", From a58c5b4f5b38a91458e8b06e73b8bcc9b38eb5ee Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 14:47:14 +1000 Subject: [PATCH 026/183] txb/tests: add solo SIGHASH_ALL fixes --- src/transaction_builder.js | 8 ++++++-- test/fixtures/transaction_builder.json | 22 ++++++++++++++++++++-- test/transaction_builder.js | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 232c9a2..af238da 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -633,9 +633,9 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network') if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin) - if (this.__needsOutputs()) throw new Error('Transaction needs outputs') hashType = hashType || Transaction.SIGHASH_ALL + if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs') const input = this.__inputs[vin] @@ -709,7 +709,11 @@ TransactionBuilder.prototype.__canModifyInputs = function () { }) } -TransactionBuilder.prototype.__needsOutputs = function () { +TransactionBuilder.prototype.__needsOutputs = function (signingHashType) { + if (signingHashType === Transaction.SIGHASH_ALL) { + return this.__tx.outs.length === 0 + } + // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // .build() will fail, but .buildIncomplete() is OK return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 607e16a..133fc2d 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -2359,7 +2359,7 @@ ] }, { - "description": "Transaction w/ no outputs (but 1 SIGHASH_ALL)", + "description": "Transaction w/ no outputs (but 1 SIGHASH_NONE)", "exception": "Transaction needs outputs", "inputs": [ { @@ -2367,7 +2367,8 @@ "vout": 0, "signs": [ { - "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "hashType": 2 } ] }, @@ -2383,6 +2384,23 @@ } ], "outputs": [] + }, + { + "description": "Transaction w/ no outputs", + "exception": "Transaction needs outputs", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn", + "throws": true + } + ] + } + ], + "outputs": [] } ], "fromTransaction": [ diff --git a/test/transaction_builder.js b/test/transaction_builder.js index bd0a3ab..85adcff 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -231,6 +231,7 @@ describe('TransactionBuilder', function () { it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(txHash, 0) + txb.addOutput(scripts[0], 1000) txb.sign(0, keyPair) assert.throws(function () { From d232545ac8728f5417de25ff4b06570d8f0775e3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 3 Sep 2018 14:06:30 +1000 Subject: [PATCH 027/183] rename MULTISIG to P2MS --- src/classify.js | 6 +++--- src/transaction_builder.js | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/classify.js b/src/classify.js index 0b98fa6..8350e07 100644 --- a/src/classify.js +++ b/src/classify.js @@ -9,7 +9,7 @@ const witnessScriptHash = require('./templates/witnessscripthash') const witnessCommitment = require('./templates/witnesscommitment') const types = { - MULTISIG: 'multisig', + P2MS: 'multisig', NONSTANDARD: 'nonstandard', NULLDATA: 'nulldata', P2PK: 'pubkey', @@ -30,7 +30,7 @@ function classifyOutput (script) { const chunks = decompile(script) if (!chunks) throw new TypeError('Invalid script') - if (multisig.output.check(chunks)) return types.MULTISIG + if (multisig.output.check(chunks)) return types.P2MS if (pubKey.output.check(chunks)) return types.P2PK if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT if (nullData.output.check(chunks)) return types.NULLDATA @@ -45,7 +45,7 @@ function classifyInput (script, allowIncomplete) { if (pubKeyHash.input.check(chunks)) return types.P2PKH if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH - if (multisig.input.check(chunks, allowIncomplete)) return types.MULTISIG + if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS if (pubKey.input.check(chunks)) return types.P2PK return types.NONSTANDARD diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 8706841..a97df14 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -56,14 +56,14 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { } } - case SCRIPT_TYPES.MULTISIG: { + case SCRIPT_TYPES.P2MS: { const { pubkeys, signatures } = payments.p2ms({ input: scriptSig, output: scriptPubKey }, { allowIncomplete: true }) return { - prevOutType: SCRIPT_TYPES.MULTISIG, + prevOutType: SCRIPT_TYPES.P2MS, pubkeys: pubkeys, signatures: signatures } @@ -126,7 +126,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { // could be done in expandInput, but requires the original Transaction for hashForSignature function fixMultisigOrder (input, transaction, vin) { - if (input.redeemScriptType !== SCRIPT_TYPES.MULTISIG || !input.redeemScript) return + if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return if (input.pubkeys.length === input.signatures.length) return const unmatched = input.signatures.concat() @@ -202,7 +202,7 @@ function expandOutput (script, ourPubKey) { } } - case SCRIPT_TYPES.MULTISIG: { + case SCRIPT_TYPES.P2MS: { const p2ms = payments.p2ms({ output: script }) return { type, @@ -392,7 +392,7 @@ function build (type, input, allowIncomplete) { return payments.p2pk({ signature: signatures[0] }) } - case SCRIPT_TYPES.MULTISIG: { + case SCRIPT_TYPES.P2MS: { if (allowIncomplete) { signatures = signatures.map(x => x || ops.OP_0) } else { From 1119a449a5ed41b10751c27621b482b812558262 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 3 Sep 2018 14:00:13 +1000 Subject: [PATCH 028/183] txbuilder: add missing signature P2MS fixture --- src/transaction_builder.js | 28 +++++++++++++++++--------- test/fixtures/transaction_builder.json | 23 +++++++++++++++++++++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index a97df14..861483f 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -57,7 +57,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { } case SCRIPT_TYPES.P2MS: { - const { pubkeys, signatures } = payments.p2ms({ + const { m, pubkeys, signatures } = payments.p2ms({ input: scriptSig, output: scriptPubKey }, { allowIncomplete: true }) @@ -65,7 +65,8 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { return { prevOutType: SCRIPT_TYPES.P2MS, pubkeys: pubkeys, - signatures: signatures + signatures: signatures, + maxSignatures: m } } } @@ -207,7 +208,8 @@ function expandOutput (script, ourPubKey) { return { type, pubkeys: p2ms.pubkeys, - signatures: p2ms.pubkeys.map(() => undefined) + signatures: p2ms.pubkeys.map(() => undefined), + maxSignatures: p2ms.m } } } @@ -250,7 +252,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: expanded.type, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures } } @@ -288,7 +291,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: expanded.type, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures } } @@ -321,7 +325,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: expanded.type, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures } } @@ -351,7 +356,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: expanded.type, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures } } @@ -365,7 +371,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: SCRIPT_TYPES.P2PKH, pubkeys: [ourPubKey], - signatures: [undefined] + signatures: [undefined], + maxSignatures: 1 } } @@ -393,13 +400,14 @@ function build (type, input, allowIncomplete) { return payments.p2pk({ signature: signatures[0] }) } case SCRIPT_TYPES.P2MS: { + const m = input.maxSignatures if (allowIncomplete) { signatures = signatures.map(x => x || ops.OP_0) } else { signatures = signatures.filter(x => x) } - - return payments.p2ms({ signatures }, { allowIncomplete }) + const validate = !allowIncomplete || (m === signatures.length) + return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }) } case SCRIPT_TYPES.P2SH: { const redeem = build(input.redeemScriptType, input, allowIncomplete) diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index 4ddc5cb..40e3d74 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -1917,6 +1917,29 @@ } ] }, + { + "description": "Incomplete Transaction P2SH(P2MS 2/3), missing signature", + "exception": "Not enough signatures provided", + "network": "testnet", + "inputs": [ + { + "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "vout": 0, + "signs": [ + { + "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx", + "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG" + } + ] + } + ], + "outputs": [ + { + "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG", + "value": 1000 + } + ] + }, { "description": "Duplicate transaction outs", "exception": "Duplicate TxOut: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:0", From 7c3d1f292d6914c355e5b3e8cbd5ea732bb735cd Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 14:57:03 +1000 Subject: [PATCH 029/183] txb: add inline explanatory comment --- src/transaction_builder.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 861483f..3d1b2c5 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -406,6 +406,9 @@ function build (type, input, allowIncomplete) { } else { signatures = signatures.filter(x => x) } + + // if the transaction is not not complete (complete), or if signatures.length === m, validate + // otherwise, the number of OP_0's may be >= m, so don't validate (boo) const validate = !allowIncomplete || (m === signatures.length) return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }) } From c8ae86b9ce728fbd6e982d111cf8dcdb5de1c43b Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 15:02:18 +1000 Subject: [PATCH 030/183] refactor(txb): maxSignatures is optional --- src/transaction_builder.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 3d1b2c5..7411a29 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -371,8 +371,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri signType: SCRIPT_TYPES.P2PKH, pubkeys: [ourPubKey], - signatures: [undefined], - maxSignatures: 1 + signatures: [undefined] } } From 17c89fdc5eb9e508c372f91996bda8f1b183f3f3 Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 26 Sep 2018 14:54:53 +0900 Subject: [PATCH 031/183] Move Transaction to ES6 --- src/transaction.js | 773 ++++++++++++++++++++++++--------------------- 1 file changed, 418 insertions(+), 355 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index 751446f..c6a9909 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -7,35 +7,20 @@ const typeforce = require('typeforce') const types = require('./types') const varuint = require('varuint-bitcoin') -function varSliceSize (someScript) { +const varSliceSize = (someScript) => { const length = someScript.length return varuint.encodingLength(length) + length } -function vectorSize (someVector) { +const vectorSize = (someVector) => { const length = someVector.length - return varuint.encodingLength(length) + someVector.reduce(function (sum, witness) { + return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { return sum + varSliceSize(witness) }, 0) } -function Transaction () { - this.version = 1 - this.locktime = 0 - this.ins = [] - this.outs = [] -} - -Transaction.DEFAULT_SEQUENCE = 0xffffffff -Transaction.SIGHASH_ALL = 0x01 -Transaction.SIGHASH_NONE = 0x02 -Transaction.SIGHASH_SINGLE = 0x03 -Transaction.SIGHASH_ANYONECANPAY = 0x80 -Transaction.ADVANCED_TRANSACTION_MARKER = 0x00 -Transaction.ADVANCED_TRANSACTION_FLAG = 0x01 - const EMPTY_SCRIPT = Buffer.allocUnsafe(0) const EMPTY_WITNESS = [] const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex') @@ -46,447 +31,525 @@ const BLANK_OUTPUT = { valueBuffer: VALUE_UINT64_MAX } -Transaction.fromBuffer = function (buffer, __noStrict) { - let offset = 0 - function readSlice (n) { - offset += n - return buffer.slice(offset - n, offset) +class Transaction { + constructor () { + this.version = 1 + this.locktime = 0 + this.ins = [] + this.outs = [] } - function readUInt32 () { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i + static get DEFAULT_SEQUENCE () { + return 0xffffffff } - - function readInt32 () { - const i = buffer.readInt32LE(offset) - offset += 4 - return i + static get SIGHASH_ALL () { + return 0x01 } - - function readUInt64 () { - const i = bufferutils.readUInt64LE(buffer, offset) - offset += 8 - return i + static get SIGHASH_NONE () { + return 0x02 } - - function readVarInt () { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi + static get SIGHASH_SINGLE () { + return 0x03 } - - function readVarSlice () { - return readSlice(readVarInt()) + static get SIGHASH_ANYONECANPAY () { + return 0x80 + } + static get ADVANCED_TRANSACTION_MARKER () { + return 0x00 + } + static get ADVANCED_TRANSACTION_FLAG () { + return 0x01 } - function readVector () { - const count = readVarInt() - const vector = [] - for (var i = 0; i < count; i++) vector.push(readVarSlice()) - return vector + isCoinbase () { + return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) } - const tx = new Transaction() - tx.version = readInt32() + addInput (hash, index, sequence, scriptSig) { + typeforce(types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer) + ), arguments) - const marker = buffer.readUInt8(offset) - const flag = buffer.readUInt8(offset + 1) + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE + } - let hasWitnesses = false - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - offset += 2 - hasWitnesses = true + // Add the input and return the input's index + return (this.ins.push({ + hash: hash, + index: index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS + }) - 1) } - const vinLen = readVarInt() - for (var i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), - witness: EMPTY_WITNESS - }) + addOutput (scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) + + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value: value + }) - 1) } - const voutLen = readVarInt() - for (i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: readUInt64(), - script: readVarSlice() + hasWitnesses () { + return this.ins.some((x) => { + return x.witness.length !== 0 }) } - if (hasWitnesses) { - for (i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector() - } + weight () { + const base = this.__byteLength(false) + const total = this.__byteLength(true) + return base * 3 + total + } - // was this pointless? - if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') + virtualSize () { + return Math.ceil(this.weight() / 4) } - tx.locktime = readUInt32() + byteLength () { + return this.__byteLength(true) + } - if (__noStrict) return tx - if (offset !== buffer.length) throw new Error('Transaction has unexpected data') + __byteLength (__allowWitness) { + const hasWitnesses = __allowWitness && this.hasWitnesses() + + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script) + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script) + }, 0) + + (hasWitnesses ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness) + }, 0) : 0) + ) + } - return tx -} + clone () { + const newTx = new Transaction() + newTx.version = this.version + newTx.locktime = this.locktime + + newTx.ins = this.ins.map((txIn) => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness + } + }) -Transaction.fromHex = function (hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex')) -} + newTx.outs = this.outs.map((txOut) => { + return { + script: txOut.script, + value: txOut.value + } + }) -Transaction.isCoinbaseHash = function (buffer) { - typeforce(types.Hash256bit, buffer) - for (var i = 0; i < 32; ++i) { - if (buffer[i] !== 0) return false + return newTx } - return true -} -Transaction.prototype.isCoinbase = function () { - return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) -} + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature (inIndex, prevOutScript, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) + + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE + + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { + return x !== opcodes.OP_CODESEPARATOR + })) + + const txTmp = this.clone() + + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = [] + + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) return + + input.sequence = 0 + }) + + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE + + // truncate outputs after + txTmp.outs.length = inIndex + 1 + + // "blank" outputs before + for (var i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT + } + + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) return + + input.sequence = 0 + }) + } -Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) { - typeforce(types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer) - ), arguments) - - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE - } - - // Add the input and return the input's index - return (this.ins.push({ - hash: hash, - index: index, - script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, - witness: EMPTY_WITNESS - }) - 1) -} + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]] + txTmp.ins[0].script = ourScript + + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach((input) => { + input.script = EMPTY_SCRIPT + }) + txTmp.ins[inIndex].script = ourScript + } -Transaction.prototype.addOutput = function (scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) + buffer.writeInt32LE(hashType, buffer.length - 4) + txTmp.__toBuffer(buffer, 0, false) - // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value: value - }) - 1) -} + return bcrypto.hash256(buffer) + } -Transaction.prototype.hasWitnesses = function () { - return this.ins.some(function (x) { - return x.witness.length !== 0 - }) -} + hashForWitnessV0 (inIndex, prevOutScript, value, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) -Transaction.prototype.weight = function () { - const base = this.__byteLength(false) - const total = this.__byteLength(true) - return base * 3 + total -} + let tbuffer, toffset -Transaction.prototype.virtualSize = function () { - return Math.ceil(this.weight() / 4) -} + const writeSlice = (slice) => { + toffset += slice.copy(tbuffer, toffset) + } -Transaction.prototype.byteLength = function () { - return this.__byteLength(true) -} + const writeUInt32 = (i) => { + toffset = tbuffer.writeUInt32LE(i, toffset) + } -Transaction.prototype.__byteLength = function (__allowWitness) { - const hasWitnesses = __allowWitness && this.hasWitnesses() - - return ( - (hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) + - this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) + - (hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0) - ) -} + const writeUInt64 = (i) => { + toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) + } -Transaction.prototype.clone = function () { - const newTx = new Transaction() - newTx.version = this.version - newTx.locktime = this.locktime - - newTx.ins = this.ins.map(function (txIn) { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness + const writeVarInt = (i) => { + varuint.encode(i, tbuffer, toffset) + toffset += varuint.encode.bytes } - }) - newTx.outs = this.outs.map(function (txOut) { - return { - script: txOut.script, - value: txOut.value + const writeVarSlice = (slice) => { + writeVarInt(slice.length) + writeSlice(slice) } - }) - return newTx -} + let hashOutputs = ZERO + let hashPrevouts = ZERO + let hashSequence = ZERO -/** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ -Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length) + toffset = 0 - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) return ONE + this.ins.forEach((txIn) => { + writeSlice(txIn.hash) + writeUInt32(txIn.index) + }) - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) { - return x !== opcodes.OP_CODESEPARATOR - })) + hashPrevouts = bcrypto.hash256(tbuffer) + } - const txTmp = this.clone() + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length) + toffset = 0 - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = [] + this.ins.forEach((txIn) => { + writeUInt32(txIn.sequence) + }) - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach(function (input, i) { - if (i === inIndex) return + hashSequence = bcrypto.hash256(tbuffer) + } - input.sequence = 0 - }) + if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script) + }, 0) + + tbuffer = Buffer.allocUnsafe(txOutsSize) + toffset = 0 - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) return ONE + this.outs.forEach((out) => { + writeUInt64(out.value) + writeVarSlice(out.script) + }) - // truncate outputs after - txTmp.outs.length = inIndex + 1 + hashOutputs = bcrypto.hash256(tbuffer) + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { + const output = this.outs[inIndex] - // "blank" outputs before - for (var i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) + toffset = 0 + writeUInt64(output.value) + writeVarSlice(output.script) + + hashOutputs = bcrypto.hash256(tbuffer) } - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach(function (input, y) { - if (y === inIndex) return + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) + toffset = 0 - input.sequence = 0 - }) + const input = this.ins[inIndex] + writeUInt32(this.version) + writeSlice(hashPrevouts) + writeSlice(hashSequence) + writeSlice(input.hash) + writeUInt32(input.index) + writeVarSlice(prevOutScript) + writeUInt64(value) + writeUInt32(input.sequence) + writeSlice(hashOutputs) + writeUInt32(this.locktime) + writeUInt32(hashType) + return bcrypto.hash256(tbuffer) } - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]] - txTmp.ins[0].script = ourScript + getHash () { + return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) + } - // SIGHASH_ALL: only ignore input scripts - } else { - // "blank" others input scripts - txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT }) - txTmp.ins[inIndex].script = ourScript + getId () { + // transaction hash's are displayed in reverse order + return this.getHash().reverse().toString('hex') } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) - buffer.writeInt32LE(hashType, buffer.length - 4) - txTmp.__toBuffer(buffer, 0, false) + toBuffer (buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true) + } - return bcrypto.hash256(buffer) -} + __toBuffer (buffer, initialOffset, __allowWitness) { + if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)) -Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) + let offset = initialOffset || 0 - let tbuffer, toffset - function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) } - function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) } - function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) } - function writeVarInt (i) { - varuint.encode(i, tbuffer, toffset) - toffset += varuint.encode.bytes - } - function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } + const writeSlice = (slice) => { + offset += slice.copy(buffer, offset) + } - let hashOutputs = ZERO - let hashPrevouts = ZERO - let hashSequence = ZERO + const writeUInt8 = (i) => { + offset = buffer.writeUInt8(i, offset) + } - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length) - toffset = 0 + const writeUInt32 = (i) => { + offset = buffer.writeUInt32LE(i, offset) + } + + const writeInt32 = (i) => { + offset = buffer.writeInt32LE(i, offset) + } + + const writeUInt64 = (i) => { + offset = bufferutils.writeUInt64LE(buffer, i, offset) + } + + const writeVarInt = (i) => { + varuint.encode(i, buffer, offset) + offset += varuint.encode.bytes + } + + const writeVarSlice = (slice) => { + writeVarInt(slice.length) + writeSlice(slice) + } + + const writeVector = (vector) => { + writeVarInt(vector.length) + vector.forEach(writeVarSlice) + } + + writeInt32(this.version) + + const hasWitnesses = __allowWitness && this.hasWitnesses() - this.ins.forEach(function (txIn) { + if (hasWitnesses) { + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) + } + + writeVarInt(this.ins.length) + + this.ins.forEach((txIn) => { writeSlice(txIn.hash) writeUInt32(txIn.index) + writeVarSlice(txIn.script) + writeUInt32(txIn.sequence) }) - hashPrevouts = bcrypto.hash256(tbuffer) - } - - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length) - toffset = 0 + writeVarInt(this.outs.length) + this.outs.forEach((txOut) => { + if (!txOut.valueBuffer) { + writeUInt64(txOut.value) + } else { + writeSlice(txOut.valueBuffer) + } - this.ins.forEach(function (txIn) { - writeUInt32(txIn.sequence) + writeVarSlice(txOut.script) }) - hashSequence = bcrypto.hash256(tbuffer) + if (hasWitnesses) { + this.ins.forEach((input) => { + writeVector(input.witness) + }) + } + + writeUInt32(this.locktime) + + // avoid slicing unless necessary + if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) + return buffer } - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - const txOutsSize = this.outs.reduce(function (sum, output) { - return sum + 8 + varSliceSize(output.script) - }, 0) + toHex () { + return this.toBuffer().toString('hex') + } - tbuffer = Buffer.allocUnsafe(txOutsSize) - toffset = 0 + setInputScript (index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments) - this.outs.forEach(function (out) { - writeUInt64(out.value) - writeVarSlice(out.script) - }) + this.ins[index].script = scriptSig + } - hashOutputs = bcrypto.hash256(tbuffer) - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { - const output = this.outs[inIndex] + setWitness (index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments) - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) - toffset = 0 - writeUInt64(output.value) - writeVarSlice(output.script) - - hashOutputs = bcrypto.hash256(tbuffer) - } - - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) - toffset = 0 - - const input = this.ins[inIndex] - writeUInt32(this.version) - writeSlice(hashPrevouts) - writeSlice(hashSequence) - writeSlice(input.hash) - writeUInt32(input.index) - writeVarSlice(prevOutScript) - writeUInt64(value) - writeUInt32(input.sequence) - writeSlice(hashOutputs) - writeUInt32(this.locktime) - writeUInt32(hashType) - return bcrypto.hash256(tbuffer) + this.ins[index].witness = witness + } } -Transaction.prototype.getHash = function () { - return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) -} +Transaction.fromBuffer = (buffer, __noStrict) => { + let offset = 0 -Transaction.prototype.getId = function () { - // transaction hash's are displayed in reverse order - return this.getHash().reverse().toString('hex') -} + const readSlice = (n) => { + offset += n + return buffer.slice(offset - n, offset) + } -Transaction.prototype.toBuffer = function (buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true) -} + const readUInt32 = () => { + const i = buffer.readUInt32LE(offset) + offset += 4 + return i + } -Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) { - if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)) + const readInt32 = () => { + const i = buffer.readInt32LE(offset) + offset += 4 + return i + } - let offset = initialOffset || 0 - function writeSlice (slice) { offset += slice.copy(buffer, offset) } - function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) } - function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) } - function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) } - function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } - function writeVarInt (i) { - varuint.encode(i, buffer, offset) - offset += varuint.encode.bytes + const readUInt64 = () => { + const i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i } - function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } - function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) } - writeInt32(this.version) + const readVarInt = () => { + const vi = varuint.decode(buffer, offset) + offset += varuint.decode.bytes + return vi + } - const hasWitnesses = __allowWitness && this.hasWitnesses() + const readVarSlice = () => { + return readSlice(readVarInt()) + } - if (hasWitnesses) { - writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) - writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) + const readVector = () => { + const count = readVarInt() + const vector = [] + for (var i = 0; i < count; i++) vector.push(readVarSlice()) + return vector } - writeVarInt(this.ins.length) + const tx = new Transaction() + tx.version = readInt32() - this.ins.forEach(function (txIn) { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - writeVarSlice(txIn.script) - writeUInt32(txIn.sequence) - }) + const marker = buffer.readUInt8(offset) + const flag = buffer.readUInt8(offset + 1) - writeVarInt(this.outs.length) - this.outs.forEach(function (txOut) { - if (!txOut.valueBuffer) { - writeUInt64(txOut.value) - } else { - writeSlice(txOut.valueBuffer) - } + let hasWitnesses = false + if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG) { + offset += 2 + hasWitnesses = true + } - writeVarSlice(txOut.script) - }) + const vinLen = readVarInt() + for (var i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readVarSlice(), + sequence: readUInt32(), + witness: EMPTY_WITNESS + }) + } - if (hasWitnesses) { - this.ins.forEach(function (input) { - writeVector(input.witness) + const voutLen = readVarInt() + for (i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readVarSlice() }) } - writeUInt32(this.locktime) + if (hasWitnesses) { + for (i = 0; i < vinLen; ++i) { + tx.ins[i].witness = readVector() + } - // avoid slicing unless necessary - if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) - return buffer -} + // was this pointless? + if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') + } -Transaction.prototype.toHex = function () { - return this.toBuffer().toString('hex') -} + tx.locktime = readUInt32() -Transaction.prototype.setInputScript = function (index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments) + if (__noStrict) return tx + if (offset !== buffer.length) throw new Error('Transaction has unexpected data') - this.ins[index].script = scriptSig + return tx } -Transaction.prototype.setWitness = function (index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments) +Transaction.fromHex = (hex) => { + return Transaction.fromBuffer(Buffer.from(hex, 'hex')) +} - this.ins[index].witness = witness +Transaction.isCoinbaseHash = (buffer) => { + typeforce(types.Hash256bit, buffer) + for (var i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false + } + return true } module.exports = Transaction From df2a66c852546a273f33d7a997c46945202b7155 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 16:02:39 +1000 Subject: [PATCH 032/183] tests/payments: fix redeem fixture mutation --- test/payments.utils.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/payments.utils.js b/test/payments.utils.js index 219d086..485bf03 100644 --- a/test/payments.utils.js +++ b/test/payments.utils.js @@ -1,6 +1,6 @@ const t = require('assert') const bscript = require('../src/script') -const bnetworks = require('../src/networks') +const BNETWORKS = require('../src/networks') function tryHex (x) { if (Buffer.isBuffer(x)) return x.toString('hex') @@ -58,7 +58,7 @@ function equate (a, b, args) { equateBase(a, b, '') if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.') - if (b.network) t.deepEqual(a.network, b.network, 'Inequal *.network') + if (b.network) t.deepEqual(a.network, BNETWORKS[b.network], 'Inequal *.network') // contextual if (b.signature === null) b.signature = undefined @@ -76,7 +76,7 @@ function equate (a, b, args) { function preform (x) { x = Object.assign({}, x) - if (x.network) x.network = bnetworks[x.network] + if (x.network) x.network = BNETWORKS[x.network] if (typeof x.inputHex === 'string') { x.input = Buffer.from(x.inputHex, 'hex') delete x.inputHex @@ -96,10 +96,11 @@ function preform (x) { if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex) if (x.signatures) x.signatures = x.signatures.map(function (y) { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') }) if (x.redeem) { + x.redeem = Object.assign({}, x.redeem) if (typeof x.redeem.input === 'string') x.redeem.input = asmToBuffer(x.redeem.input) if (typeof x.redeem.output === 'string') x.redeem.output = asmToBuffer(x.redeem.output) if (Array.isArray(x.redeem.witness)) x.redeem.witness = x.redeem.witness.map(fromHex) - if (x.redeem.network) x.redeem.network = bnetworks[x.redeem.network] + if (x.redeem.network) x.redeem.network = BNETWORKS[x.redeem.network] } return x From 6927f74b7aafc046bbca80ebe8658186149c598a Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 15:44:55 +1000 Subject: [PATCH 033/183] add inverted Network mismatch tests --- test/fixtures/p2sh.json | 18 ++++++++++++++++++ test/fixtures/p2wsh.json | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json index e6fe2ae..e447e4a 100644 --- a/test/fixtures/p2sh.json +++ b/test/fixtures/p2sh.json @@ -325,6 +325,24 @@ } } }, + { + "exception": "Network mismatch", + "arguments": { + "network": "bitcoin", + "redeem": { + "network": "testnet" + } + } + }, + { + "exception": "Network mismatch", + "arguments": { + "network": "testnet", + "redeem": { + "network": "bitcoin" + } + } + }, { "exception": "Empty input", "arguments": { diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json index 0870278..2dfec75 100644 --- a/test/fixtures/p2wsh.json +++ b/test/fixtures/p2wsh.json @@ -306,6 +306,15 @@ } } }, + { + "exception": "Network mismatch", + "arguments": { + "network": "testnet", + "redeem": { + "network": "bitcoin" + } + } + }, { "exception": "Invalid prefix or Network mismatch", "arguments": { From 1b4dc48d75c65c854c23fa7abff7976b7814615a Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 16:02:13 +1000 Subject: [PATCH 034/183] add failing tests for redeem.network derivation --- test/fixtures/p2sh.json | 18 ++++++++++++++++++ test/fixtures/p2wsh.json | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json index e447e4a..595b85e 100644 --- a/test/fixtures/p2sh.json +++ b/test/fixtures/p2sh.json @@ -166,6 +166,24 @@ ] } } + }, + { + "description": "p2sh-p2pkh, out (network derived from redeem)", + "arguments": { + "redeem": { + "address": "this is P2PKH context, unknown and ignored by P2SH", + "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", + "network": "testnet" + } + }, + "expected": { + "address": "2N7nfc7zeWuADtpdR4MrR7Wq3dzr7LxTCgS", + "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", + "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", + "input": null, + "witness": null, + "network": "testnet" + } } ], "invalid": [ diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json index 2dfec75..e5ce0e0 100644 --- a/test/fixtures/p2wsh.json +++ b/test/fixtures/p2wsh.json @@ -179,6 +179,24 @@ ] } } + }, + { + "description": "p2wsh-p2pkh, out (network derived from redeem)", + "arguments": { + "redeem": { + "address": "this is P2PKH context, unknown and ignored by p2wsh", + "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", + "network": "testnet" + } + }, + "expected": { + "address": "tb1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ssaskm8v", + "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", + "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", + "input": null, + "witness": null, + "network": "testnet" + } } ], "invalid": [ From a976fba27b45c742207b7081565a4e35a3282c9f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 16:02:52 +1000 Subject: [PATCH 035/183] add network derivation from redeem.network --- src/payments/p2sh.js | 6 +++++- src/payments/p2wsh.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index 4741936..0729c8b 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -45,7 +45,11 @@ function p2sh (a, opts) { witness: typef.maybe(typef.arrayOf(typef.Buffer)) }, a) - const network = a.network || BITCOIN_NETWORK + let network = a.network + if (!network) { + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK + } + const o = { network } const _address = lazy.value(function () { diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index a26e706..d8e6e8a 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -59,7 +59,11 @@ function p2wsh (a, opts) { }) const _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input) }) - const network = a.network || BITCOIN_NETWORK + let network = a.network + if (!network) { + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK + } + const o = { network } lazy.prop(o, 'address', function () { From a88aa3334876ba13b23a8dd348958148be8d7309 Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 26 Sep 2018 16:30:33 +0900 Subject: [PATCH 036/183] Revert function hoisting removal --- src/transaction.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index c6a9909..e1be629 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -7,13 +7,13 @@ const typeforce = require('typeforce') const types = require('./types') const varuint = require('varuint-bitcoin') -const varSliceSize = (someScript) => { +function varSliceSize (someScript) { const length = someScript.length return varuint.encodingLength(length) + length } -const vectorSize = (someVector) => { +function vectorSize (someVector) { const length = someVector.length return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { @@ -241,24 +241,24 @@ class Transaction { let tbuffer, toffset - const writeSlice = (slice) => { + function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) } - const writeUInt32 = (i) => { + function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) } - const writeUInt64 = (i) => { + function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) } - const writeVarInt = (i) => { + function writeVarInt (i) { varuint.encode(i, tbuffer, toffset) toffset += varuint.encode.bytes } - const writeVarSlice = (slice) => { + function writeVarSlice (slice) { writeVarInt(slice.length) writeSlice(slice) } @@ -354,37 +354,37 @@ class Transaction { let offset = initialOffset || 0 - const writeSlice = (slice) => { + function writeSlice (slice) { offset += slice.copy(buffer, offset) } - const writeUInt8 = (i) => { + function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) } - const writeUInt32 = (i) => { + function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) } - const writeInt32 = (i) => { + function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) } - const writeUInt64 = (i) => { + function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } - const writeVarInt = (i) => { + function writeVarInt (i) { varuint.encode(i, buffer, offset) offset += varuint.encode.bytes } - const writeVarSlice = (slice) => { + function writeVarSlice (slice) { writeVarInt(slice.length) writeSlice(slice) } - const writeVector = (vector) => { + function writeVector (vector) { writeVarInt(vector.length) vector.forEach(writeVarSlice) } @@ -451,40 +451,40 @@ class Transaction { Transaction.fromBuffer = (buffer, __noStrict) => { let offset = 0 - const readSlice = (n) => { + function readSlice (n) { offset += n return buffer.slice(offset - n, offset) } - const readUInt32 = () => { + function readUInt32 () { const i = buffer.readUInt32LE(offset) offset += 4 return i } - const readInt32 = () => { + function readInt32 () { const i = buffer.readInt32LE(offset) offset += 4 return i } - const readUInt64 = () => { + function readUInt64 () { const i = bufferutils.readUInt64LE(buffer, offset) offset += 8 return i } - const readVarInt = () => { + function readVarInt () { const vi = varuint.decode(buffer, offset) offset += varuint.decode.bytes return vi } - const readVarSlice = () => { + function readVarSlice () { return readSlice(readVarInt()) } - const readVector = () => { + function readVector () { const count = readVarInt() const vector = [] for (var i = 0; i < count; i++) vector.push(readVarSlice()) From b93d9d99ccc240d3e022f1a680024469fcc04cf5 Mon Sep 17 00:00:00 2001 From: Apichan Chaiyutthasat Date: Sat, 6 Oct 2018 13:13:40 +0700 Subject: [PATCH 037/183] Update addresses.js --- test/integration/addresses.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 4bd71c8..9ad7502 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -19,6 +19,7 @@ function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } describe('bitcoinjs-lib (addresses)', function () { it('can generate a random address', function () { + // in production: const keyPair = bitcoin.ECPair.makeRandom({}) const keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) @@ -121,6 +122,7 @@ describe('bitcoinjs-lib (addresses)', function () { // other networks it('can generate a Testnet address', function () { const testnet = bitcoin.networks.testnet + // in production: const keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: rng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: testnet }) @@ -130,6 +132,7 @@ describe('bitcoinjs-lib (addresses)', function () { }) it('can generate a Litecoin address', function () { + // in production: const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: rng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN }) From 44a98c0fa6487eaf81500427366787a953ff890d Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 15 Nov 2018 15:32:03 +0900 Subject: [PATCH 038/183] Add regtest network --- src/networks.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/networks.js b/src/networks.js index b168f7a..fb3957c 100644 --- a/src/networks.js +++ b/src/networks.js @@ -13,6 +13,17 @@ module.exports = { scriptHash: 0x05, wif: 0x80 }, + regtest: { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef + }, testnet: { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'tb', From 28bfb71b5406646746fe4b591d8c697bcf704d28 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 15 Nov 2018 15:44:03 +0900 Subject: [PATCH 039/183] Add tests for regtest bech32 address --- test/fixtures/address.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/fixtures/address.json b/test/fixtures/address.json index 2b7e5fa..2668a08 100644 --- a/test/fixtures/address.json +++ b/test/fixtures/address.json @@ -63,6 +63,20 @@ "bech32": "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "data": "000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", "script": "OP_0 000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" + }, + { + "network": "regtest", + "version": 0, + "bech32": "bcrt1qjh3dnrafy8f2zszh5sdqn6c3ycfljh930yza9nt72v30dkw8mlvscn82zx", + "data": "95e2d98fa921d2a14057a41a09eb112613f95cb17905d2cd7e5322f6d9c7dfd9", + "script": "OP_0 95e2d98fa921d2a14057a41a09eb112613f95cb17905d2cd7e5322f6d9c7dfd9" + }, + { + "network": "regtest", + "version": 0, + "bech32": "bcrt1qqqqqqqqqqqqqqahrwf6d62emdxmpq8gu3xe9au9fjwc9sxxn4k2qujfh7u", + "data": "000000000000000076e37274dd2b3b69b6101d1c89b25ef0a993b05818d3ad94", + "script": "OP_0 000000000000000076e37274dd2b3b69b6101d1c89b25ef0a993b05818d3ad94" } ], "bech32": [ @@ -179,4 +193,3 @@ ] } } - From bd0be2f3430e7a5a81b776129befc004b48635da Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 15 Nov 2018 18:52:16 +0900 Subject: [PATCH 040/183] Fix errors for bitcoin core 0.17.0 --- test/integration/cltv.js | 2 +- test/integration/csv.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/cltv.js b/test/integration/cltv.js index e4a1133..2c39b2c 100644 --- a/test/integration/cltv.js +++ b/test/integration/cltv.js @@ -212,7 +212,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { regtestUtils.broadcast(tx.toHex(), function (err) { assert.throws(function () { if (err) throw err - }, /Error: 64: non-final/) + }, /Error: non-final \(code 64\)/) done() }) diff --git a/test/integration/csv.js b/test/integration/csv.js index 1662a1a..5996634 100644 --- a/test/integration/csv.js +++ b/test/integration/csv.js @@ -132,7 +132,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { regtestUtils.broadcast(tx.toHex(), function (err) { assert.throws(function () { if (err) throw err - }, /Error: 64: non-BIP68-final/) + }, /Error: non-BIP68-final \(code 64\)/) done() }) From 9c409b1274f0b671099214963a3638097ce83d77 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 20 Nov 2018 16:28:35 +0900 Subject: [PATCH 041/183] Change regtest server over to regtest.bitbank.cc --- test/integration/_regtest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index 059cec2..f392a8a 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -3,12 +3,12 @@ const bitcoin = require('../../') const dhttp = require('dhttp/200') const APIPASS = process.env.APIPASS || 'satoshi' -const APIURL = 'https://api.dcousens.cloud/1' +const APIURL = 'https://regtest.bitbank.cc/1' const NETWORK = bitcoin.networks.testnet function broadcast (txHex, callback) { dhttp({ - method: 'PUT', + method: 'POST', url: APIURL + '/t/push', body: txHex }, callback) From 1e05fa085e5f4dfcec9a076d19dd08df0211e552 Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 27 Nov 2018 01:20:08 +0000 Subject: [PATCH 042/183] README: emphasis dependencies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a7b5b8..bbd40ae 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Master is not stable; it is our development branch, and [only tagged releases ma ## Can I trust this code? > Don't trust. Verify. -We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability. +We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability, including the dependencies. Mistakes and bugs happen, but with your help in resolving and reporting [issues](https://github.com/bitcoinjs/bitcoinjs-lib/issues), together we can produce open source software that is: From 661ec6b9184b8663d80c08c7ee14b68d72cfc12e Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 27 Nov 2018 01:21:01 +0000 Subject: [PATCH 043/183] README: more emphasis --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbd40ae..2d8e9bf 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Master is not stable; it is our development branch, and [only tagged releases ma ## Can I trust this code? > Don't trust. Verify. -We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability, including the dependencies. +We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability, including reviewing any and all of your project's dependencies. Mistakes and bugs happen, but with your help in resolving and reporting [issues](https://github.com/bitcoinjs/bitcoinjs-lib/issues), together we can produce open source software that is: From 06342a830fc963830b32df7358523d037302bdc6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 27 Nov 2018 03:48:57 +0000 Subject: [PATCH 044/183] README: upgrade iOS warning --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d8e9bf..3ca8866 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ If you're familiar with how to use browserify, ignore this and carry on, otherwi **NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](http://babeljs.io/docs/plugins/preset-es2015/) preset). -**NOTE**: If you expect this library to run on an iOS 10 device, ensure that you are using [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater. +**WARNING**: iOS devices have [problems](https://github.com/feross/buffer/issues/136), use atleast [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater, and enforce the test suites (for `Buffer`, and any other dependency) pass before use. ### Typescript or VSCode users Type declarations for Typescript [are available](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/0897921174860ec3d5318992d2323b3ae8100a68/types/bitcoinjs-lib) for version `^3.0.0` of the library. @@ -74,7 +74,7 @@ npm install -g flow-typed flow-typed install -f 0.27 bitcoinjs-lib@2.2.0 ``` -These definitions are maintained by [@runn1ng](https://github.com/runn1ng). +These flow bindings are not maintained by the maintainers of this repository. ## Examples From 47b5dfb4688638163daacc586cb3b720c5a06621 Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 27 Nov 2018 03:51:08 +0000 Subject: [PATCH 045/183] README: add warning to flow type bindings --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ca8866..e8866c9 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ npm install -g flow-typed flow-typed install -f 0.27 bitcoinjs-lib@2.2.0 ``` -These flow bindings are not maintained by the maintainers of this repository. +**WARNING**: These flow-typed definitions are not maintained by the maintainers of this repository. ## Examples From 1b5d1fadba50f5ce795a58b38efb30db652fa693 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 10:30:28 +1000 Subject: [PATCH 046/183] README: use https --- CHANGELOG.md | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 907c6d5..451a168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ __added__ __changed__ - `ECPair.prototype.sign` now returns a 64-byte signature `Buffer`, not an `ECSignature` object (#1084) -- `ECPair` (and all ECDSA code) now uses [`tiny-secp256k1`](http://github.com/bitcoinjs/tiny-secp256k1), which uses the [`libsecp256k1` library](https://github.com/bitcoin-core/secp256k1) (#1070) +- `ECPair` (and all ECDSA code) now uses [`tiny-secp256k1`](https://github.com/bitcoinjs/tiny-secp256k1), which uses the [`libsecp256k1` library](https://github.com/bitcoin-core/secp256k1) (#1070) - `TransactionBuilder` internal variables are now `__` prefixed to discourage public usage (#1038) - `TransactionBuilder` now defaults to version 2 transaction versions (#1036) - `script.decompile` now returns `[Buffer]` or `null`, if decompilation failed (#1039) diff --git a/README.md b/README.md index e8866c9..07c5ca4 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Mistakes and bugs happen, but with your help in resolving and reporting [issues] - Easy to audit and verify, - Tested, with test coverage >95%, - Advanced and feature rich, -- Standardized, using [standard](http://github.com/standard/standard) and Node `Buffer`'s throughout, and +- Standardized, using [standard](https://github.com/standard/standard) and Node `Buffer`'s throughout, and - Friendly, with a strong and helpful community, ready to answer questions. ## Documentation @@ -45,9 +45,9 @@ If in doubt, see the [.travis.yml](.travis.yml) for what versions are used by ou ### Browser The recommended method of using `bitcoinjs-lib` in your browser is through [Browserify](https://github.com/substack/node-browserify). -If you're familiar with how to use browserify, ignore this and carry on, otherwise, it is recommended to read the tutorial at http://browserify.org/. +If you're familiar with how to use browserify, ignore this and carry on, otherwise, it is recommended to read the tutorial at https://browserify.org/. -**NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](http://babeljs.io/docs/plugins/preset-es2015/) preset). +**NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset). **WARNING**: iOS devices have [problems](https://github.com/feross/buffer/issues/136), use atleast [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater, and enforce the test suites (for `Buffer`, and any other dependency) pass before use. From b273deb265c2f58cdc1c7fa3af2cf2c2ff27a6a3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 11:03:21 +1000 Subject: [PATCH 047/183] README: add crypto is hard disclaimer --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 07c5ca4..2541b3b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Mistakes and bugs happen, but with your help in resolving and reporting [issues] - Standardized, using [standard](https://github.com/standard/standard) and Node `Buffer`'s throughout, and - Friendly, with a strong and helpful community, ready to answer questions. + ## Documentation Presently, we do not have any formal documentation other than our [examples](#examples), please [ask for help](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new) if our examples aren't enough to guide you. @@ -42,6 +43,27 @@ If in doubt, see the [.travis.yml](.travis.yml) for what versions are used by ou ## Usage +Crypto is hard. + +When working with private keys, the random number generator is fundamentally one of the most important parts of any software you write. +For random number generation, we *default* to the [`randombytes`](https://github.com/crypto-browserify/randombytes) module, which uses [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues) in the browser, or Node js' [`crypto.randomBytes`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback), depending on your build system. +Although this default is ~OK, there is no simple way to detect if the underlying RNG provided is good enough, or if it is **catastrophically bad**. +You should always verify this yourself to your own standards. + +This library uses [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1), which uses [RFC6979](https://tools.ietf.org/html/rfc6979) to help prevent `k` re-use and exploitation. +Unfortunately, this isn't a silver bullet. +Often, Javascript itself is working against us by bypassing these counter-measures. + +Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in catastrophic fund loss without any warning. +It can do this through undermining your random number generation, accidentally producing a duplicate `k` value, sending Bitcoin to a malformed output script, or any of a million different ways. +Running tests in your target environment is important and a recommended step to verify continuously. + +Finally, **adhere to best practice**. We aren't an authorative source for best practice, but, at the very least: + +* Don't re-use addresses. Privacy is important, but, .... TODO +* Don't share BIP32 extended public keys. They are a liability, and [as shown in our examples](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L68), it only takes 1 mistake until **catastrophic failure**. +* TODO, anythign else of importance here? + ### Browser The recommended method of using `bitcoinjs-lib` in your browser is through [Browserify](https://github.com/substack/node-browserify). From e514bc73643ff63863c43896ea83f8a62fb72f8f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 17:26:04 +1000 Subject: [PATCH 048/183] README: add extra suggestions for best practice --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2541b3b..f2b2c8d 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,18 @@ Unfortunately, this isn't a silver bullet. Often, Javascript itself is working against us by bypassing these counter-measures. Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in catastrophic fund loss without any warning. -It can do this through undermining your random number generation, accidentally producing a duplicate `k` value, sending Bitcoin to a malformed output script, or any of a million different ways. +It can do this through undermining your random number generation, [accidentally producing a duplicate `k` value](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L14), sending Bitcoin to a malformed output script, or any of a million different ways. Running tests in your target environment is important and a recommended step to verify continuously. -Finally, **adhere to best practice**. We aren't an authorative source for best practice, but, at the very least: +Finally, **adhere to best practice**. +We are not an authorative source of best practice, but, at the very least: -* Don't re-use addresses. Privacy is important, but, .... TODO -* Don't share BIP32 extended public keys. They are a liability, and [as shown in our examples](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L68), it only takes 1 mistake until **catastrophic failure**. -* TODO, anythign else of importance here? +* [Don't re-use addresses](https://en.bitcoin.it/wiki/Address_reuse). +* Don't share BIP32 extended public keys ('xpubs'). [They are a liability](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L68), and it only takes 1 misplaced private key (or a buggy implementation!) and you are vulnerable to **catastrophic fund loss**. +* [Don't use `Math.random`](https://security.stackexchange.com/questions/181580/why-is-math-random-not-designed-to-be-cryptographically-secure) - in any way - don't. +* Enforce that users always verify (manually) a freshly-decoded human-readable version of their intended transaction before broadcast. +* Don't *ask* users to generate mnemonics, or 'brain wallets', humans are terrible random number generators. +* Lastly, if you can, use [Typescript](https://www.typescriptlang.org/) or similar. ### Browser From 5fc673a8d6e7acd4b5767f1f0b633538d2c69429 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 17:28:15 +1000 Subject: [PATCH 049/183] README: link to external explanations --- README.md | 7 +-- test/integration/crypto.js | 103 ------------------------------------- 2 files changed, 2 insertions(+), 108 deletions(-) delete mode 100644 test/integration/crypto.js diff --git a/README.md b/README.md index f2b2c8d..8a0885c 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,14 @@ Unfortunately, this isn't a silver bullet. Often, Javascript itself is working against us by bypassing these counter-measures. Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in catastrophic fund loss without any warning. -It can do this through undermining your random number generation, [accidentally producing a duplicate `k` value](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L14), sending Bitcoin to a malformed output script, or any of a million different ways. +It can do this through undermining your random number generation, [accidentally producing a duplicate `k` value](https://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html), sending Bitcoin to a malformed output script, or any of a million different ways. Running tests in your target environment is important and a recommended step to verify continuously. Finally, **adhere to best practice**. We are not an authorative source of best practice, but, at the very least: * [Don't re-use addresses](https://en.bitcoin.it/wiki/Address_reuse). -* Don't share BIP32 extended public keys ('xpubs'). [They are a liability](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L68), and it only takes 1 misplaced private key (or a buggy implementation!) and you are vulnerable to **catastrophic fund loss**. +* Don't share BIP32 extended public keys ('xpubs'). [They are a liability](https://bitcoin.stackexchange.com/questions/56916/derivation-of-parent-private-key-from-non-hardened-child), and it only takes 1 misplaced private key (or a buggy implementation!) and you are vulnerable to **catastrophic fund loss**. * [Don't use `Math.random`](https://security.stackexchange.com/questions/181580/why-is-math-random-not-designed-to-be-cryptographically-secure) - in any way - don't. * Enforce that users always verify (manually) a freshly-decoded human-readable version of their intended transaction before broadcast. * Don't *ask* users to generate mnemonics, or 'brain wallets', humans are terrible random number generators. @@ -140,11 +140,8 @@ Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). - [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L88) - [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L144) - [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L190) -- [Recover a private key from duplicate R values](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L14) -- [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#L68) - [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L72) - [Generate a single-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L91) -- [Recover parent recipient.d, if a derived private key is leaked (and nonce was revealed)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L107) - [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L124) - [Generate a dual-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L147) diff --git a/test/integration/crypto.js b/test/integration/crypto.js deleted file mode 100644 index 3a40f6c..0000000 --- a/test/integration/crypto.js +++ /dev/null @@ -1,103 +0,0 @@ -const { describe, it } = require('mocha') -const assert = require('assert') -const BN = require('bn.js') -const bitcoin = require('../../') -const bip32 = require('bip32') -const crypto = require('crypto') -const tinysecp = require('tiny-secp256k1') - -describe('bitcoinjs-lib (crypto)', function () { - it('can recover a private key from duplicate R values', function () { - // https://blockchain.info/tx/f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50 - const tx = bitcoin.Transaction.fromHex('01000000020b668015b32a6178d8524cfef6dc6fc0a4751915c2e9b2ed2d2eab02424341c8000000006a47304402205e00298dc5265b7a914974c9d0298aa0e69a0ca932cb52a360436d6a622e5cd7022024bf5f506968f5f23f1835574d5afe0e9021b4a5b65cf9742332d5e4acb68f41012103fd089f73735129f3d798a657aaaa4aa62a00fa15c76b61fc7f1b27ed1d0f35b8ffffffffa95fa69f11dc1cbb77ef64f25a95d4b12ebda57d19d843333819d95c9172ff89000000006b48304502205e00298dc5265b7a914974c9d0298aa0e69a0ca932cb52a360436d6a622e5cd7022100832176b59e8f50c56631acbc824bcba936c9476c559c42a4468be98975d07562012103fd089f73735129f3d798a657aaaa4aa62a00fa15c76b61fc7f1b27ed1d0f35b8ffffffff02b000eb04000000001976a91472956eed9a8ecb19ae7e3ebd7b06cae4668696a788ac303db000000000001976a9146c0bd55dd2592287cd9992ce3ba3fc1208fb76da88ac00000000') - - tx.ins.forEach(function (input, vin) { - const { output: prevOutput, pubkey, signature } = bitcoin.payments.p2pkh({ input: input.script }) - - const scriptSignature = bitcoin.script.signature.decode(signature) - const m = tx.hashForSignature(vin, prevOutput, scriptSignature.hashType) - assert(bitcoin.ECPair.fromPublicKey(pubkey).verify(m, scriptSignature.signature), 'Invalid m') - - // store the required information - input.signature = scriptSignature.signature - input.z = new BN(m) - }) - - const n = new BN('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16) - - for (var i = 0; i < tx.ins.length; ++i) { - for (var j = i + 1; j < tx.ins.length; ++j) { - const inputA = tx.ins[i] - const inputB = tx.ins[j] - - // enforce matching r values - const r = inputA.signature.slice(0, 32) - const rB = inputB.signature.slice(0, 32) - assert.strictEqual(r.toString('hex'), rB.toString('hex')) - - const rInv = new BN(r).invm(n) - - const s1 = new BN(inputA.signature.slice(32, 64)) - const s2 = new BN(inputB.signature.slice(32, 64)) - const z1 = inputA.z - const z2 = inputB.z - - const zz = z1.sub(z2).mod(n) - const ss = s1.sub(s2).mod(n) - - // k = (z1 - z2) / (s1 - s2) - // d1 = (s1 * k - z1) / r - // d2 = (s2 * k - z2) / r - const k = zz.mul(ss.invm(n)).mod(n) - const d1 = ((s1.mul(k).mod(n)).sub(z1).mod(n)).mul(rInv).mod(n) - const d2 = ((s2.mul(k).mod(n)).sub(z2).mod(n)).mul(rInv).mod(n) - - // enforce matching private keys - assert.strictEqual(d1.toString(), d2.toString()) - } - } - }) - - it('can recover a BIP32 parent private key from the parent public key, and a derived, non-hardened child private key', function () { - function recoverParent (master, child) { - assert(master.isNeutered(), 'You already have the parent private key') - assert(!child.isNeutered(), 'Missing child private key') - - const serQP = master.publicKey - const d1 = child.privateKey - const data = Buffer.alloc(37) - serQP.copy(data, 0) - - // search index space until we find it - let d2 - for (var i = 0; i < 0x80000000; ++i) { - data.writeUInt32BE(i, 33) - - // calculate I - const I = crypto.createHmac('sha512', master.chainCode).update(data).digest() - const IL = I.slice(0, 32) - - // See bip32.js:273 to understand - d2 = tinysecp.privateSub(d1, IL) - - const Qp = bip32.fromPrivateKey(d2, Buffer.alloc(32, 0)).publicKey - if (Qp.equals(serQP)) break - } - - const node = bip32.fromPrivateKey(d2, master.chainCode, master.network) - node.depth = master.depth - node.index = master.index - node.masterFingerprint = master.masterFingerprint - return node - } - - const seed = crypto.randomBytes(32) - const master = bip32.fromSeed(seed) - const child = master.derive(6) // m/6 - - // now for the recovery - const neuteredMaster = master.neutered() - const recovered = recoverParent(neuteredMaster, child) - assert.strictEqual(recovered.toBase58(), master.toBase58()) - }) -}) From a908e909d1841500b5eeed4bee7a44240fc53b4c Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 17:40:45 +1000 Subject: [PATCH 050/183] README: rm stealth address examples --- README.md | 4 - test/integration/stealth.js | 167 ------------------------------------ 2 files changed, 171 deletions(-) delete mode 100644 test/integration/stealth.js diff --git a/README.md b/README.md index 8a0885c..23dce36 100644 --- a/README.md +++ b/README.md @@ -140,10 +140,6 @@ Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). - [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L88) - [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L144) - [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L190) -- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L72) -- [Generate a single-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L91) -- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L124) -- [Generate a dual-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L147) If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)! diff --git a/test/integration/stealth.js b/test/integration/stealth.js deleted file mode 100644 index dd99d63..0000000 --- a/test/integration/stealth.js +++ /dev/null @@ -1,167 +0,0 @@ -const { describe, it } = require('mocha') -const assert = require('assert') -const bitcoin = require('../../') -const ecc = require('tiny-secp256k1') - -function getAddress (node, network) { - return bitcoin.payments.p2pkh({ pubkey: node.publicKey, network }).address -} - -// vG = (dG \+ sha256(e * dG)G) -function stealthSend (e, Q) { - const eQ = ecc.pointMultiply(Q, e, true) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const Qc = ecc.pointAddScalar(Q, c) - const vG = bitcoin.ECPair.fromPublicKey(Qc) - - return vG -} - -// v = (d + sha256(eG * d)) -function stealthReceive (d, eG) { - const eQ = ecc.pointMultiply(eG, d) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const dc = ecc.privateAdd(d, c) - const v = bitcoin.ECPair.fromPrivateKey(dc) - - return v -} - -// d = (v - sha256(e * dG)) -function stealthRecoverLeaked (v, e, Q) { - const eQ = ecc.pointMultiply(Q, e) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const vc = ecc.privateSub(v, c) - const d = bitcoin.ECPair.fromPrivateKey(vc) - - return d -} - -// vG = (rG \+ sha256(e * dG)G) -function stealthDualSend (e, R, Q) { - const eQ = ecc.pointMultiply(Q, e) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const Rc = ecc.pointAddScalar(R, c) - const vG = bitcoin.ECPair.fromPublicKey(Rc) - - return vG -} - -// vG = (rG \+ sha256(eG * d)G) -function stealthDualScan (d, R, eG) { - const eQ = ecc.pointMultiply(eG, d) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const Rc = ecc.pointAddScalar(R, c) - const vG = bitcoin.ECPair.fromPublicKey(Rc) - - return vG -} - -// v = (r + sha256(eG * d)) -function stealthDualReceive (d, r, eG) { - const eQ = ecc.pointMultiply(eG, d) // shared secret - const c = bitcoin.crypto.sha256(eQ) - const rc = ecc.privateAdd(r, c) - const v = bitcoin.ECPair.fromPrivateKey(rc) - - return v -} - -describe('bitcoinjs-lib (crypto)', function () { - it('can generate a single-key stealth address', function () { - // XXX: should be randomly generated, see next test for example - const recipient = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // private to recipient - const nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender - - // ... recipient reveals public key (recipient.Q) to sender - const forSender = stealthSend(nonce.privateKey, recipient.publicKey) - assert.equal(getAddress(forSender), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE') - assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) - - // ... sender reveals nonce public key (nonce.Q) to recipient - const forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey) - assert.equal(getAddress(forRecipient), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE') - assert.equal(forRecipient.toWIF(), 'L1yjUN3oYyCXV3LcsBrmxCNTa62bZKWCybxVJMvqjMmmfDE8yk7n') - - // sender and recipient, both derived same address - assert.equal(getAddress(forSender), getAddress(forRecipient)) - }) - - it('can generate a single-key stealth address (randomly)', function () { - const recipient = bitcoin.ECPair.makeRandom() // private to recipient - const nonce = bitcoin.ECPair.makeRandom() // private to sender - - // ... recipient reveals public key (recipient.Q) to sender - const forSender = stealthSend(nonce.privateKey, recipient.publicKey) - assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) - - // ... sender reveals nonce public key (nonce.Q) to recipient - const forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey) - assert.doesNotThrow(function () { forRecipient.toWIF() }) - - // sender and recipient, both derived same address - assert.equal(getAddress(forSender), getAddress(forRecipient)) - }) - - it('can recover parent recipient.d, if a derived private key is leaked [and nonce was revealed]', function () { - const recipient = bitcoin.ECPair.makeRandom() // private to recipient - const nonce = bitcoin.ECPair.makeRandom() // private to sender - - // ... recipient reveals public key (recipient.Q) to sender - const forSender = stealthSend(nonce.privateKey, recipient.publicKey) - assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) - - // ... sender reveals nonce public key (nonce.Q) to recipient - const forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey) - assert.doesNotThrow(function () { forRecipient.toWIF() }) - - // ... recipient accidentally leaks forRecipient.d on the blockchain - const leaked = stealthRecoverLeaked(forRecipient.privateKey, nonce.privateKey, recipient.publicKey) - assert.equal(leaked.toWIF(), recipient.toWIF()) - }) - - it('can generate a dual-key stealth address', function () { - // XXX: should be randomly generated, see next test for example - const recipient = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // private to recipient - const scan = bitcoin.ECPair.fromWIF('L5DkCk3xLLoGKncqKsWQTdaPSR4V8gzc14WVghysQGkdryRudjBM') // private to scanner/recipient - const nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender - - // ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender - const forSender = stealthDualSend(nonce.privateKey, recipient.publicKey, scan.publicKey) - assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) - - // ... sender reveals nonce public key (nonce.Q) to scanner - const forScanner = stealthDualScan(scan.privateKey, recipient.publicKey, nonce.publicKey) - assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/) - - // ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient - const forRecipient = stealthDualReceive(scan.privateKey, recipient.privateKey, nonce.publicKey) - assert.doesNotThrow(function () { forRecipient.toWIF() }) - - // scanner, sender and recipient, all derived same address - assert.equal(getAddress(forSender), getAddress(forScanner)) - assert.equal(getAddress(forSender), getAddress(forRecipient)) - }) - - it('can generate a dual-key stealth address (randomly)', function () { - const recipient = bitcoin.ECPair.makeRandom() // private to recipient - const scan = bitcoin.ECPair.makeRandom() // private to scanner/recipient - const nonce = bitcoin.ECPair.makeRandom() // private to sender - - // ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender - const forSender = stealthDualSend(nonce.privateKey, recipient.publicKey, scan.publicKey) - assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) - - // ... sender reveals nonce public key (nonce.Q) to scanner - const forScanner = stealthDualScan(scan.privateKey, recipient.publicKey, nonce.publicKey) - assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/) - - // ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient - const forRecipient = stealthDualReceive(scan.privateKey, recipient.privateKey, nonce.publicKey) - assert.doesNotThrow(function () { forRecipient.toWIF() }) - - // scanner, sender and recipient, all derived same address - assert.equal(getAddress(forSender), getAddress(forScanner)) - assert.equal(getAddress(forSender), getAddress(forRecipient)) - }) -}) From aac228011f9c8c75b17bc9d100bb67534172e366 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 17:44:31 +1000 Subject: [PATCH 051/183] README: rm bad sha256 hash example --- README.md | 1 - test/integration/addresses.js | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/README.md b/README.md index 23dce36..28c1b21 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,6 @@ Otherwise, pull requests are appreciated. Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). - [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L22) -- [Generate an address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L29) - [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L40) - [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L47) - [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L60) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 4bd71c8..0024410 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -25,17 +25,6 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') }) - it('can generate an address from a SHA256 hash', function () { - const hash = bitcoin.crypto.sha256(Buffer.from('correct horse battery staple')) - - const keyPair = bitcoin.ECPair.fromPrivateKey(hash) - const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - - // Generating addresses from SHA256 hashes is not secure if the input to the hash function is predictable - // Do not use with predictable inputs - assert.strictEqual(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') - }) - it('can import an address via WIF', function () { const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) From e1049c1090b329a60e5d31679b77bb568e594b9f Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 26 Sep 2018 17:59:04 +1000 Subject: [PATCH 052/183] README: fix emphasis --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 28c1b21..9342696 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ This library uses [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1), Unfortunately, this isn't a silver bullet. Often, Javascript itself is working against us by bypassing these counter-measures. -Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in catastrophic fund loss without any warning. -It can do this through undermining your random number generation, [accidentally producing a duplicate `k` value](https://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html), sending Bitcoin to a malformed output script, or any of a million different ways. +Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in **catastrophic fund loss** without any warning. +It can do this through undermining your random number generation, accidentally producing a [duplicate `k` value](https://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html), sending Bitcoin to a malformed output script, or any of a million different ways. Running tests in your target environment is important and a recommended step to verify continuously. Finally, **adhere to best practice**. From 959ba5ae96a3c04cb14a795fc64a4b0a1c67e866 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 6 Dec 2018 13:16:30 +1100 Subject: [PATCH 053/183] add P2SH(P2WPKH) signature verification example --- test/integration/transactions.js | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/test/integration/transactions.js b/test/integration/transactions.js index e828414..0d88d78 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -258,7 +258,7 @@ describe('bitcoinjs-lib (transactions)', function () { }) }) - it('can verify Transaction signatures', function () { + it('can verify Transaction (P2PKH) signatures', function () { const txHex = '010000000321c5f7e7bc98b3feda84aad36a5c99a02bcb8823a2f3eccbcd5da209698b5c20000000006b48304502210099e021772830207cf7c55b69948d3b16b4dcbf1f55a9cd80ebf8221a169735f9022064d33f11d62cd28240b3862afc0b901adc9f231c7124dd19bdb30367b61964c50121032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63dffffffff8a75ce85441ddb3f342708ee33cc8ed418b07d9ba9e0e7c4e1cccfe9f52d8a88000000006946304302207916c23dae212c95a920423902fa44e939fb3d542f4478a7b46e9cde53705800021f0d74e9504146e404c1b8f9cba4dff2d4782e3075491c9ed07ce4a7d1c4461a01210216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2affffffffdfef93f69fe32e944fad79fa8f882b3a155d80383252348caba1a77a5abbf7ef000000006b483045022100faa6e9ca289b46c64764a624c59ac30d9abcf1d4a04c4de9089e67cbe0d300a502206930afa683f6807502de5c2431bf9a1fd333c8a2910a76304df0f3d23d83443f0121039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18fffffffff01ff4b0000000000001976a9146c86476d1d85cd60116cd122a274e6a570a5a35c88acc96d0700' const keyPairs = [ '032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d', @@ -281,4 +281,34 @@ describe('bitcoinjs-lib (transactions)', function () { assert.strictEqual(keyPair.verify(hash, ss.signature), true) }) }) + + it('can verify Transaction (P2SH(P2WPKH)) signatures', function () { + const utxos = { + 'f72d1d83ac40fcedd01415751556a905844ab5f44bbb7728565ebb91b1590109:0': { + value: 50000 + } + } + + const txHex = '02000000000101090159b191bb5e562877bb4bf4b54a8405a95615751514d0edfc40ac831d2df7000000001716001435a179e5516947a39ae9c8a25e9fe62c0fc598edffffffff01204e0000000000001976a91431d43308d3c886d53e9ae8a45728370571ff456988ac0247304402206ec41f685b997a51f325b07ee852e82a535f6b52ef54485cc133e05168aa052a022070bafa86108acb51c77b2b259ae8fb7fd1efa10fef804fcfe9b13c2db719acf5012103fb03e9d0a9af86cbed94225dbb8bb70f6b82109bce0a61ddcf41dab6cbb4871100000000' + const tx = bitcoin.Transaction.fromHex(txHex) + + tx.ins.forEach(function (input, i) { + const txId = Buffer.from(input.hash).reverse().toString('hex') + const utxo = utxos[`${txId}:${i}`] + if (!utxo) throw new Error('Missing utxo') + + const p2sh = bitcoin.payments.p2sh({ + input: input.script, + witness: input.witness + }) + const p2wpkh = bitcoin.payments.p2wpkh(p2sh.redeem) + const p2pkh = bitcoin.payments.p2pkh({ pubkey: p2wpkh.pubkey }) // because P2WPKH is annoying + + const ss = bitcoin.script.signature.decode(p2wpkh.signature) + const hash = tx.hashForWitnessV0(i, p2pkh.output, utxo.value, ss.hashType) + const keyPair = bitcoin.ECPair.fromPublicKey(p2wpkh.pubkey) // aka, cQ3EtF4mApRcogNGSeyPTKbmfxxn3Yfb1wecfKSws9a8bnYuxoAk + + assert.strictEqual(keyPair.verify(hash, ss.signature), true) + }) + }) }) From 15289fe0cfc3c8b48a1b477a407dc0cc3ce7d044 Mon Sep 17 00:00:00 2001 From: Jonathan Underwood Date: Mon, 10 Dec 2018 01:01:55 +0900 Subject: [PATCH 054/183] Add notes for learners about nSequence + LockTime --- test/integration/cltv.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/integration/cltv.js b/test/integration/cltv.js index 2c39b2c..8bf1c4a 100644 --- a/test/integration/cltv.js +++ b/test/integration/cltv.js @@ -50,6 +50,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { const txb = new bitcoin.TransactionBuilder(regtest) txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) @@ -96,6 +97,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { const txb = new bitcoin.TransactionBuilder(regtest) txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) @@ -147,6 +149,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { const txb = new bitcoin.TransactionBuilder(regtest) txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4) @@ -191,6 +194,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { const txb = new bitcoin.TransactionBuilder(regtest) txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) From 7c0e02ad488fa826cbfb69d0508aab0e427ce346 Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 12 Dec 2018 21:07:16 +0900 Subject: [PATCH 055/183] Fix Block to allow regtest target (easiest possible target) --- src/block.js | 2 +- test/fixtures/block.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/block.js b/src/block.js index 8c7f3a6..eb7f708 100644 --- a/src/block.js +++ b/src/block.js @@ -145,7 +145,7 @@ Block.calculateTarget = function (bits) { const exponent = ((bits & 0xff000000) >> 24) - 3 const mantissa = bits & 0x007fffff const target = Buffer.alloc(32, 0) - target.writeUInt32BE(mantissa, 28 - exponent) + target.writeUIntBE(mantissa, 29 - exponent, 3) return target } diff --git a/test/fixtures/block.json b/test/fixtures/block.json index c7aa5f7..b4a1cfe 100644 --- a/test/fixtures/block.json +++ b/test/fixtures/block.json @@ -19,6 +19,10 @@ { "bits": "cffca00", "expected": "00000000000000000000000000000000000000007fca00000000000000000000" + }, + { + "bits": "207fffff", + "expected": "7fffff0000000000000000000000000000000000000000000000000000000000" } ], "valid": [ From f860d467d6993615c11e11e213da5337a0f4305a Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 19 Dec 2018 00:16:48 +0900 Subject: [PATCH 056/183] Revert "Merge pull request #1086 from bitcoinjs/refactorTransaction" This reverts commit 5e1ae82a5d9569b8a14c3e526847b9904ff57c01, reversing changes made to 96240b636d99fb0553aa7fc7722a13942bff1c83. --- src/transaction.js | 769 +++++++++++++++++++++------------------------ 1 file changed, 353 insertions(+), 416 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index e1be629..751446f 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -16,11 +16,26 @@ function varSliceSize (someScript) { function vectorSize (someVector) { const length = someVector.length - return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { + return varuint.encodingLength(length) + someVector.reduce(function (sum, witness) { return sum + varSliceSize(witness) }, 0) } +function Transaction () { + this.version = 1 + this.locktime = 0 + this.ins = [] + this.outs = [] +} + +Transaction.DEFAULT_SEQUENCE = 0xffffffff +Transaction.SIGHASH_ALL = 0x01 +Transaction.SIGHASH_NONE = 0x02 +Transaction.SIGHASH_SINGLE = 0x03 +Transaction.SIGHASH_ANYONECANPAY = 0x80 +Transaction.ADVANCED_TRANSACTION_MARKER = 0x00 +Transaction.ADVANCED_TRANSACTION_FLAG = 0x01 + const EMPTY_SCRIPT = Buffer.allocUnsafe(0) const EMPTY_WITNESS = [] const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex') @@ -31,525 +46,447 @@ const BLANK_OUTPUT = { valueBuffer: VALUE_UINT64_MAX } -class Transaction { - constructor () { - this.version = 1 - this.locktime = 0 - this.ins = [] - this.outs = [] +Transaction.fromBuffer = function (buffer, __noStrict) { + let offset = 0 + function readSlice (n) { + offset += n + return buffer.slice(offset - n, offset) } - static get DEFAULT_SEQUENCE () { - return 0xffffffff - } - static get SIGHASH_ALL () { - return 0x01 - } - static get SIGHASH_NONE () { - return 0x02 - } - static get SIGHASH_SINGLE () { - return 0x03 - } - static get SIGHASH_ANYONECANPAY () { - return 0x80 - } - static get ADVANCED_TRANSACTION_MARKER () { - return 0x00 - } - static get ADVANCED_TRANSACTION_FLAG () { - return 0x01 + function readUInt32 () { + const i = buffer.readUInt32LE(offset) + offset += 4 + return i } - isCoinbase () { - return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + function readInt32 () { + const i = buffer.readInt32LE(offset) + offset += 4 + return i } - addInput (hash, index, sequence, scriptSig) { - typeforce(types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer) - ), arguments) - - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE - } - - // Add the input and return the input's index - return (this.ins.push({ - hash: hash, - index: index, - script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, - witness: EMPTY_WITNESS - }) - 1) + function readUInt64 () { + const i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i } - addOutput (scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) - - // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value: value - }) - 1) + function readVarInt () { + const vi = varuint.decode(buffer, offset) + offset += varuint.decode.bytes + return vi } - hasWitnesses () { - return this.ins.some((x) => { - return x.witness.length !== 0 - }) + function readVarSlice () { + return readSlice(readVarInt()) } - weight () { - const base = this.__byteLength(false) - const total = this.__byteLength(true) - return base * 3 + total + function readVector () { + const count = readVarInt() + const vector = [] + for (var i = 0; i < count; i++) vector.push(readVarSlice()) + return vector } - virtualSize () { - return Math.ceil(this.weight() / 4) - } + const tx = new Transaction() + tx.version = readInt32() - byteLength () { - return this.__byteLength(true) - } + const marker = buffer.readUInt8(offset) + const flag = buffer.readUInt8(offset + 1) - __byteLength (__allowWitness) { - const hasWitnesses = __allowWitness && this.hasWitnesses() - - return ( - (hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script) - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script) - }, 0) + - (hasWitnesses ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness) - }, 0) : 0) - ) + let hasWitnesses = false + if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG) { + offset += 2 + hasWitnesses = true } - clone () { - const newTx = new Transaction() - newTx.version = this.version - newTx.locktime = this.locktime - - newTx.ins = this.ins.map((txIn) => { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness - } + const vinLen = readVarInt() + for (var i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readVarSlice(), + sequence: readUInt32(), + witness: EMPTY_WITNESS }) + } - newTx.outs = this.outs.map((txOut) => { - return { - script: txOut.script, - value: txOut.value - } + const voutLen = readVarInt() + for (i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readVarSlice() }) - - return newTx } - /** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ - hashForSignature (inIndex, prevOutScript, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) - - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) return ONE - - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { - return x !== opcodes.OP_CODESEPARATOR - })) - - const txTmp = this.clone() - - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = [] - - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, i) => { - if (i === inIndex) return - - input.sequence = 0 - }) - - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) return ONE - - // truncate outputs after - txTmp.outs.length = inIndex + 1 - - // "blank" outputs before - for (var i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT - } - - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, y) => { - if (y === inIndex) return - - input.sequence = 0 - }) - } - - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]] - txTmp.ins[0].script = ourScript - - // SIGHASH_ALL: only ignore input scripts - } else { - // "blank" others input scripts - txTmp.ins.forEach((input) => { - input.script = EMPTY_SCRIPT - }) - txTmp.ins[inIndex].script = ourScript + if (hasWitnesses) { + for (i = 0; i < vinLen; ++i) { + tx.ins[i].witness = readVector() } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) - buffer.writeInt32LE(hashType, buffer.length - 4) - txTmp.__toBuffer(buffer, 0, false) - - return bcrypto.hash256(buffer) + // was this pointless? + if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') } - hashForWitnessV0 (inIndex, prevOutScript, value, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) - - let tbuffer, toffset + tx.locktime = readUInt32() - function writeSlice (slice) { - toffset += slice.copy(tbuffer, toffset) - } + if (__noStrict) return tx + if (offset !== buffer.length) throw new Error('Transaction has unexpected data') - function writeUInt32 (i) { - toffset = tbuffer.writeUInt32LE(i, toffset) - } + return tx +} - function writeUInt64 (i) { - toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) - } +Transaction.fromHex = function (hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex')) +} - function writeVarInt (i) { - varuint.encode(i, tbuffer, toffset) - toffset += varuint.encode.bytes - } +Transaction.isCoinbaseHash = function (buffer) { + typeforce(types.Hash256bit, buffer) + for (var i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false + } + return true +} - function writeVarSlice (slice) { - writeVarInt(slice.length) - writeSlice(slice) - } +Transaction.prototype.isCoinbase = function () { + return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) +} - let hashOutputs = ZERO - let hashPrevouts = ZERO - let hashSequence = ZERO +Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) { + typeforce(types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer) + ), arguments) + + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE + } + + // Add the input and return the input's index + return (this.ins.push({ + hash: hash, + index: index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS + }) - 1) +} - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length) - toffset = 0 +Transaction.prototype.addOutput = function (scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) - this.ins.forEach((txIn) => { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - }) + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value: value + }) - 1) +} - hashPrevouts = bcrypto.hash256(tbuffer) - } +Transaction.prototype.hasWitnesses = function () { + return this.ins.some(function (x) { + return x.witness.length !== 0 + }) +} - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length) - toffset = 0 +Transaction.prototype.weight = function () { + const base = this.__byteLength(false) + const total = this.__byteLength(true) + return base * 3 + total +} - this.ins.forEach((txIn) => { - writeUInt32(txIn.sequence) - }) +Transaction.prototype.virtualSize = function () { + return Math.ceil(this.weight() / 4) +} - hashSequence = bcrypto.hash256(tbuffer) - } +Transaction.prototype.byteLength = function () { + return this.__byteLength(true) +} - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - const txOutsSize = this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script) - }, 0) +Transaction.prototype.__byteLength = function (__allowWitness) { + const hasWitnesses = __allowWitness && this.hasWitnesses() + + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) + + this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) + + (hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0) + ) +} - tbuffer = Buffer.allocUnsafe(txOutsSize) - toffset = 0 +Transaction.prototype.clone = function () { + const newTx = new Transaction() + newTx.version = this.version + newTx.locktime = this.locktime + + newTx.ins = this.ins.map(function (txIn) { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness + } + }) - this.outs.forEach((out) => { - writeUInt64(out.value) - writeVarSlice(out.script) - }) + newTx.outs = this.outs.map(function (txOut) { + return { + script: txOut.script, + value: txOut.value + } + }) - hashOutputs = bcrypto.hash256(tbuffer) - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { - const output = this.outs[inIndex] + return newTx +} - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) - toffset = 0 - writeUInt64(output.value) - writeVarSlice(output.script) +/** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ +Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) - hashOutputs = bcrypto.hash256(tbuffer) - } + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) - toffset = 0 + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) { + return x !== opcodes.OP_CODESEPARATOR + })) - const input = this.ins[inIndex] - writeUInt32(this.version) - writeSlice(hashPrevouts) - writeSlice(hashSequence) - writeSlice(input.hash) - writeUInt32(input.index) - writeVarSlice(prevOutScript) - writeUInt64(value) - writeUInt32(input.sequence) - writeSlice(hashOutputs) - writeUInt32(this.locktime) - writeUInt32(hashType) - return bcrypto.hash256(tbuffer) - } + const txTmp = this.clone() - getHash () { - return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) - } + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = [] - getId () { - // transaction hash's are displayed in reverse order - return this.getHash().reverse().toString('hex') - } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach(function (input, i) { + if (i === inIndex) return - toBuffer (buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true) - } + input.sequence = 0 + }) - __toBuffer (buffer, initialOffset, __allowWitness) { - if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)) + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE - let offset = initialOffset || 0 + // truncate outputs after + txTmp.outs.length = inIndex + 1 - function writeSlice (slice) { - offset += slice.copy(buffer, offset) + // "blank" outputs before + for (var i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT } - function writeUInt8 (i) { - offset = buffer.writeUInt8(i, offset) - } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach(function (input, y) { + if (y === inIndex) return - function writeUInt32 (i) { - offset = buffer.writeUInt32LE(i, offset) - } + input.sequence = 0 + }) + } - function writeInt32 (i) { - offset = buffer.writeInt32LE(i, offset) - } + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]] + txTmp.ins[0].script = ourScript - function writeUInt64 (i) { - offset = bufferutils.writeUInt64LE(buffer, i, offset) - } + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT }) + txTmp.ins[inIndex].script = ourScript + } - function writeVarInt (i) { - varuint.encode(i, buffer, offset) - offset += varuint.encode.bytes - } + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) + buffer.writeInt32LE(hashType, buffer.length - 4) + txTmp.__toBuffer(buffer, 0, false) - function writeVarSlice (slice) { - writeVarInt(slice.length) - writeSlice(slice) - } + return bcrypto.hash256(buffer) +} - function writeVector (vector) { - writeVarInt(vector.length) - vector.forEach(writeVarSlice) - } +Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) - writeInt32(this.version) + let tbuffer, toffset + function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) } + function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) } + function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) } + function writeVarInt (i) { + varuint.encode(i, tbuffer, toffset) + toffset += varuint.encode.bytes + } + function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } - const hasWitnesses = __allowWitness && this.hasWitnesses() + let hashOutputs = ZERO + let hashPrevouts = ZERO + let hashSequence = ZERO - if (hasWitnesses) { - writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) - writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) - } - - writeVarInt(this.ins.length) + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length) + toffset = 0 - this.ins.forEach((txIn) => { + this.ins.forEach(function (txIn) { writeSlice(txIn.hash) writeUInt32(txIn.index) - writeVarSlice(txIn.script) - writeUInt32(txIn.sequence) }) - writeVarInt(this.outs.length) - this.outs.forEach((txOut) => { - if (!txOut.valueBuffer) { - writeUInt64(txOut.value) - } else { - writeSlice(txOut.valueBuffer) - } - - writeVarSlice(txOut.script) - }) + hashPrevouts = bcrypto.hash256(tbuffer) + } - if (hasWitnesses) { - this.ins.forEach((input) => { - writeVector(input.witness) - }) - } + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length) + toffset = 0 - writeUInt32(this.locktime) + this.ins.forEach(function (txIn) { + writeUInt32(txIn.sequence) + }) - // avoid slicing unless necessary - if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) - return buffer + hashSequence = bcrypto.hash256(tbuffer) } - toHex () { - return this.toBuffer().toString('hex') - } + if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + const txOutsSize = this.outs.reduce(function (sum, output) { + return sum + 8 + varSliceSize(output.script) + }, 0) - setInputScript (index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments) + tbuffer = Buffer.allocUnsafe(txOutsSize) + toffset = 0 - this.ins[index].script = scriptSig - } + this.outs.forEach(function (out) { + writeUInt64(out.value) + writeVarSlice(out.script) + }) - setWitness (index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments) + hashOutputs = bcrypto.hash256(tbuffer) + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { + const output = this.outs[inIndex] - this.ins[index].witness = witness - } + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) + toffset = 0 + writeUInt64(output.value) + writeVarSlice(output.script) + + hashOutputs = bcrypto.hash256(tbuffer) + } + + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) + toffset = 0 + + const input = this.ins[inIndex] + writeUInt32(this.version) + writeSlice(hashPrevouts) + writeSlice(hashSequence) + writeSlice(input.hash) + writeUInt32(input.index) + writeVarSlice(prevOutScript) + writeUInt64(value) + writeUInt32(input.sequence) + writeSlice(hashOutputs) + writeUInt32(this.locktime) + writeUInt32(hashType) + return bcrypto.hash256(tbuffer) } -Transaction.fromBuffer = (buffer, __noStrict) => { - let offset = 0 +Transaction.prototype.getHash = function () { + return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) +} - function readSlice (n) { - offset += n - return buffer.slice(offset - n, offset) - } +Transaction.prototype.getId = function () { + // transaction hash's are displayed in reverse order + return this.getHash().reverse().toString('hex') +} - function readUInt32 () { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i - } +Transaction.prototype.toBuffer = function (buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true) +} - function readInt32 () { - const i = buffer.readInt32LE(offset) - offset += 4 - return i - } +Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) { + if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)) - function readUInt64 () { - const i = bufferutils.readUInt64LE(buffer, offset) - offset += 8 - return i + let offset = initialOffset || 0 + function writeSlice (slice) { offset += slice.copy(buffer, offset) } + function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) } + function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) } + function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) } + function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } + function writeVarInt (i) { + varuint.encode(i, buffer, offset) + offset += varuint.encode.bytes } + function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } + function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) } - function readVarInt () { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi - } + writeInt32(this.version) - function readVarSlice () { - return readSlice(readVarInt()) - } + const hasWitnesses = __allowWitness && this.hasWitnesses() - function readVector () { - const count = readVarInt() - const vector = [] - for (var i = 0; i < count; i++) vector.push(readVarSlice()) - return vector + if (hasWitnesses) { + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) } - const tx = new Transaction() - tx.version = readInt32() + writeVarInt(this.ins.length) - const marker = buffer.readUInt8(offset) - const flag = buffer.readUInt8(offset + 1) + this.ins.forEach(function (txIn) { + writeSlice(txIn.hash) + writeUInt32(txIn.index) + writeVarSlice(txIn.script) + writeUInt32(txIn.sequence) + }) - let hasWitnesses = false - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - offset += 2 - hasWitnesses = true - } + writeVarInt(this.outs.length) + this.outs.forEach(function (txOut) { + if (!txOut.valueBuffer) { + writeUInt64(txOut.value) + } else { + writeSlice(txOut.valueBuffer) + } - const vinLen = readVarInt() - for (var i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), - witness: EMPTY_WITNESS - }) - } + writeVarSlice(txOut.script) + }) - const voutLen = readVarInt() - for (i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: readUInt64(), - script: readVarSlice() + if (hasWitnesses) { + this.ins.forEach(function (input) { + writeVector(input.witness) }) } - if (hasWitnesses) { - for (i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector() - } + writeUInt32(this.locktime) - // was this pointless? - if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') - } + // avoid slicing unless necessary + if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) + return buffer +} - tx.locktime = readUInt32() +Transaction.prototype.toHex = function () { + return this.toBuffer().toString('hex') +} - if (__noStrict) return tx - if (offset !== buffer.length) throw new Error('Transaction has unexpected data') +Transaction.prototype.setInputScript = function (index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments) - return tx + this.ins[index].script = scriptSig } -Transaction.fromHex = (hex) => { - return Transaction.fromBuffer(Buffer.from(hex, 'hex')) -} +Transaction.prototype.setWitness = function (index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments) -Transaction.isCoinbaseHash = (buffer) => { - typeforce(types.Hash256bit, buffer) - for (var i = 0; i < 32; ++i) { - if (buffer[i] !== 0) return false - } - return true + this.ins[index].witness = witness } module.exports = Transaction From bb982895012446de41f76ea5a19ea9ced52c2616 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 21 Dec 2018 17:55:03 +0900 Subject: [PATCH 057/183] Renamed files to ts --- src/{address.js => address.ts} | 0 src/{block.js => block.ts} | 0 src/{bufferutils.js => bufferutils.ts} | 0 src/{classify.js => classify.ts} | 0 src/{crypto.js => crypto.ts} | 0 src/{ecpair.js => ecpair.ts} | 0 src/{index.js => index.ts} | 0 src/{networks.js => networks.ts} | 0 src/payments/{embed.js => embed.ts} | 0 src/payments/{index.js => index.ts} | 0 src/payments/{lazy.js => lazy.ts} | 0 src/payments/{p2ms.js => p2ms.ts} | 0 src/payments/{p2pk.js => p2pk.ts} | 0 src/payments/{p2pkh.js => p2pkh.ts} | 0 src/payments/{p2sh.js => p2sh.ts} | 0 src/payments/{p2wpkh.js => p2wpkh.ts} | 0 src/payments/{p2wsh.js => p2wsh.ts} | 0 src/{script.js => script.ts} | 0 src/{script_number.js => script_number.ts} | 0 src/{script_signature.js => script_signature.ts} | 0 src/templates/multisig/{index.js => index.ts} | 0 src/templates/multisig/{input.js => input.ts} | 0 src/templates/multisig/{output.js => output.ts} | 0 src/templates/{nulldata.js => nulldata.ts} | 0 src/templates/pubkey/{index.js => index.ts} | 0 src/templates/pubkey/{input.js => input.ts} | 0 src/templates/pubkey/{output.js => output.ts} | 0 src/templates/pubkeyhash/{index.js => index.ts} | 0 src/templates/pubkeyhash/{input.js => input.ts} | 0 src/templates/pubkeyhash/{output.js => output.ts} | 0 src/templates/scripthash/{index.js => index.ts} | 0 src/templates/scripthash/{input.js => input.ts} | 0 src/templates/scripthash/{output.js => output.ts} | 0 src/templates/witnesscommitment/{index.js => index.ts} | 0 src/templates/witnesscommitment/{output.js => output.ts} | 0 src/templates/witnesspubkeyhash/{index.js => index.ts} | 0 src/templates/witnesspubkeyhash/{input.js => input.ts} | 0 src/templates/witnesspubkeyhash/{output.js => output.ts} | 0 src/templates/witnessscripthash/{index.js => index.ts} | 0 src/templates/witnessscripthash/{input.js => input.ts} | 0 src/templates/witnessscripthash/{output.js => output.ts} | 0 src/{transaction.js => transaction.ts} | 0 src/{transaction_builder.js => transaction_builder.ts} | 0 src/{types.js => types.ts} | 0 44 files changed, 0 insertions(+), 0 deletions(-) rename src/{address.js => address.ts} (100%) rename src/{block.js => block.ts} (100%) rename src/{bufferutils.js => bufferutils.ts} (100%) rename src/{classify.js => classify.ts} (100%) rename src/{crypto.js => crypto.ts} (100%) rename src/{ecpair.js => ecpair.ts} (100%) rename src/{index.js => index.ts} (100%) rename src/{networks.js => networks.ts} (100%) rename src/payments/{embed.js => embed.ts} (100%) rename src/payments/{index.js => index.ts} (100%) rename src/payments/{lazy.js => lazy.ts} (100%) rename src/payments/{p2ms.js => p2ms.ts} (100%) rename src/payments/{p2pk.js => p2pk.ts} (100%) rename src/payments/{p2pkh.js => p2pkh.ts} (100%) rename src/payments/{p2sh.js => p2sh.ts} (100%) rename src/payments/{p2wpkh.js => p2wpkh.ts} (100%) rename src/payments/{p2wsh.js => p2wsh.ts} (100%) rename src/{script.js => script.ts} (100%) rename src/{script_number.js => script_number.ts} (100%) rename src/{script_signature.js => script_signature.ts} (100%) rename src/templates/multisig/{index.js => index.ts} (100%) rename src/templates/multisig/{input.js => input.ts} (100%) rename src/templates/multisig/{output.js => output.ts} (100%) rename src/templates/{nulldata.js => nulldata.ts} (100%) rename src/templates/pubkey/{index.js => index.ts} (100%) rename src/templates/pubkey/{input.js => input.ts} (100%) rename src/templates/pubkey/{output.js => output.ts} (100%) rename src/templates/pubkeyhash/{index.js => index.ts} (100%) rename src/templates/pubkeyhash/{input.js => input.ts} (100%) rename src/templates/pubkeyhash/{output.js => output.ts} (100%) rename src/templates/scripthash/{index.js => index.ts} (100%) rename src/templates/scripthash/{input.js => input.ts} (100%) rename src/templates/scripthash/{output.js => output.ts} (100%) rename src/templates/witnesscommitment/{index.js => index.ts} (100%) rename src/templates/witnesscommitment/{output.js => output.ts} (100%) rename src/templates/witnesspubkeyhash/{index.js => index.ts} (100%) rename src/templates/witnesspubkeyhash/{input.js => input.ts} (100%) rename src/templates/witnesspubkeyhash/{output.js => output.ts} (100%) rename src/templates/witnessscripthash/{index.js => index.ts} (100%) rename src/templates/witnessscripthash/{input.js => input.ts} (100%) rename src/templates/witnessscripthash/{output.js => output.ts} (100%) rename src/{transaction.js => transaction.ts} (100%) rename src/{transaction_builder.js => transaction_builder.ts} (100%) rename src/{types.js => types.ts} (100%) diff --git a/src/address.js b/src/address.ts similarity index 100% rename from src/address.js rename to src/address.ts diff --git a/src/block.js b/src/block.ts similarity index 100% rename from src/block.js rename to src/block.ts diff --git a/src/bufferutils.js b/src/bufferutils.ts similarity index 100% rename from src/bufferutils.js rename to src/bufferutils.ts diff --git a/src/classify.js b/src/classify.ts similarity index 100% rename from src/classify.js rename to src/classify.ts diff --git a/src/crypto.js b/src/crypto.ts similarity index 100% rename from src/crypto.js rename to src/crypto.ts diff --git a/src/ecpair.js b/src/ecpair.ts similarity index 100% rename from src/ecpair.js rename to src/ecpair.ts diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/networks.js b/src/networks.ts similarity index 100% rename from src/networks.js rename to src/networks.ts diff --git a/src/payments/embed.js b/src/payments/embed.ts similarity index 100% rename from src/payments/embed.js rename to src/payments/embed.ts diff --git a/src/payments/index.js b/src/payments/index.ts similarity index 100% rename from src/payments/index.js rename to src/payments/index.ts diff --git a/src/payments/lazy.js b/src/payments/lazy.ts similarity index 100% rename from src/payments/lazy.js rename to src/payments/lazy.ts diff --git a/src/payments/p2ms.js b/src/payments/p2ms.ts similarity index 100% rename from src/payments/p2ms.js rename to src/payments/p2ms.ts diff --git a/src/payments/p2pk.js b/src/payments/p2pk.ts similarity index 100% rename from src/payments/p2pk.js rename to src/payments/p2pk.ts diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.ts similarity index 100% rename from src/payments/p2pkh.js rename to src/payments/p2pkh.ts diff --git a/src/payments/p2sh.js b/src/payments/p2sh.ts similarity index 100% rename from src/payments/p2sh.js rename to src/payments/p2sh.ts diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.ts similarity index 100% rename from src/payments/p2wpkh.js rename to src/payments/p2wpkh.ts diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.ts similarity index 100% rename from src/payments/p2wsh.js rename to src/payments/p2wsh.ts diff --git a/src/script.js b/src/script.ts similarity index 100% rename from src/script.js rename to src/script.ts diff --git a/src/script_number.js b/src/script_number.ts similarity index 100% rename from src/script_number.js rename to src/script_number.ts diff --git a/src/script_signature.js b/src/script_signature.ts similarity index 100% rename from src/script_signature.js rename to src/script_signature.ts diff --git a/src/templates/multisig/index.js b/src/templates/multisig/index.ts similarity index 100% rename from src/templates/multisig/index.js rename to src/templates/multisig/index.ts diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.ts similarity index 100% rename from src/templates/multisig/input.js rename to src/templates/multisig/input.ts diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.ts similarity index 100% rename from src/templates/multisig/output.js rename to src/templates/multisig/output.ts diff --git a/src/templates/nulldata.js b/src/templates/nulldata.ts similarity index 100% rename from src/templates/nulldata.js rename to src/templates/nulldata.ts diff --git a/src/templates/pubkey/index.js b/src/templates/pubkey/index.ts similarity index 100% rename from src/templates/pubkey/index.js rename to src/templates/pubkey/index.ts diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.ts similarity index 100% rename from src/templates/pubkey/input.js rename to src/templates/pubkey/input.ts diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.ts similarity index 100% rename from src/templates/pubkey/output.js rename to src/templates/pubkey/output.ts diff --git a/src/templates/pubkeyhash/index.js b/src/templates/pubkeyhash/index.ts similarity index 100% rename from src/templates/pubkeyhash/index.js rename to src/templates/pubkeyhash/index.ts diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.ts similarity index 100% rename from src/templates/pubkeyhash/input.js rename to src/templates/pubkeyhash/input.ts diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.ts similarity index 100% rename from src/templates/pubkeyhash/output.js rename to src/templates/pubkeyhash/output.ts diff --git a/src/templates/scripthash/index.js b/src/templates/scripthash/index.ts similarity index 100% rename from src/templates/scripthash/index.js rename to src/templates/scripthash/index.ts diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.ts similarity index 100% rename from src/templates/scripthash/input.js rename to src/templates/scripthash/input.ts diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.ts similarity index 100% rename from src/templates/scripthash/output.js rename to src/templates/scripthash/output.ts diff --git a/src/templates/witnesscommitment/index.js b/src/templates/witnesscommitment/index.ts similarity index 100% rename from src/templates/witnesscommitment/index.js rename to src/templates/witnesscommitment/index.ts diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.ts similarity index 100% rename from src/templates/witnesscommitment/output.js rename to src/templates/witnesscommitment/output.ts diff --git a/src/templates/witnesspubkeyhash/index.js b/src/templates/witnesspubkeyhash/index.ts similarity index 100% rename from src/templates/witnesspubkeyhash/index.js rename to src/templates/witnesspubkeyhash/index.ts diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.ts similarity index 100% rename from src/templates/witnesspubkeyhash/input.js rename to src/templates/witnesspubkeyhash/input.ts diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.ts similarity index 100% rename from src/templates/witnesspubkeyhash/output.js rename to src/templates/witnesspubkeyhash/output.ts diff --git a/src/templates/witnessscripthash/index.js b/src/templates/witnessscripthash/index.ts similarity index 100% rename from src/templates/witnessscripthash/index.js rename to src/templates/witnessscripthash/index.ts diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.ts similarity index 100% rename from src/templates/witnessscripthash/input.js rename to src/templates/witnessscripthash/input.ts diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.ts similarity index 100% rename from src/templates/witnessscripthash/output.js rename to src/templates/witnessscripthash/output.ts diff --git a/src/transaction.js b/src/transaction.ts similarity index 100% rename from src/transaction.js rename to src/transaction.ts diff --git a/src/transaction_builder.js b/src/transaction_builder.ts similarity index 100% rename from src/transaction_builder.js rename to src/transaction_builder.ts diff --git a/src/types.js b/src/types.ts similarity index 100% rename from src/types.js rename to src/types.ts From e855bde3b37698825f729051731c78c176795fe7 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 21 Dec 2018 18:17:54 +0900 Subject: [PATCH 058/183] Add tsconfig.json and types for node as well as typescript --- .gitignore | 1 + package.json | 4 +++- tsconfig.json | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index a6c0ab8..3d940fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ coverage +dist node_modules .nyc_output npm-debug.log diff --git a/package.json b/package.json index 755be28..52c7e8d 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "wif": "^2.0.1" }, "devDependencies": { + "@types/node": "^10.12.18", "bip39": "^2.3.0", "bip65": "^1.0.1", "bip68": "^1.0.3", @@ -58,7 +59,8 @@ "mocha": "^5.2.0", "nyc": "^11.8.0", "proxyquire": "^2.0.1", - "standard": "^11.0.1" + "standard": "^11.0.1", + "typescript": "^3.2.2" }, "license": "MIT" } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8e1edb4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2015", + "module": "commonjs", + "outDir": "./dist", + "rootDir": "./", + "types": [ + "node" + ], + "allowJs": true, + "strict": false, + "noImplicitAny": false, + "strictNullChecks": false, + "strictFunctionTypes": false, + "strictBindCallApply": false, + "strictPropertyInitialization": false, + "noImplicitThis": false, + "alwaysStrict": false, + "esModuleInterop": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "**/*.spec.ts" + ] +} From d684a6b2ef96054ab6270107450a68d127c8e9c5 Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 26 Dec 2018 14:25:33 +0900 Subject: [PATCH 059/183] Fix compiler errors, tests, and scripts --- package.json | 11 ++++++----- src/address.ts | 1 + src/block.ts | 1 + src/bufferutils.ts | 1 + src/classify.ts | 1 + src/crypto.ts | 1 + src/ecpair.ts | 1 + src/index.ts | 1 + src/networks.ts | 1 + src/payments/embed.ts | 6 +++++- src/payments/index.ts | 1 + src/payments/lazy.ts | 1 + src/payments/p2ms.ts | 13 +++++++++++-- src/payments/p2pk.ts | 8 +++++++- src/payments/p2pkh.ts | 8 +++++++- src/payments/p2sh.ts | 8 +++++++- src/payments/p2wpkh.ts | 8 +++++++- src/payments/p2wsh.ts | 8 +++++++- src/script.ts | 1 + src/script_number.ts | 1 + src/script_signature.ts | 1 + src/templates/multisig/index.ts | 1 + src/templates/multisig/input.ts | 1 + src/templates/multisig/output.ts | 1 + src/templates/nulldata.ts | 1 + src/templates/pubkey/index.ts | 1 + src/templates/pubkey/input.ts | 1 + src/templates/pubkey/output.ts | 1 + src/templates/pubkeyhash/index.ts | 1 + src/templates/pubkeyhash/input.ts | 1 + src/templates/pubkeyhash/output.ts | 1 + src/templates/scripthash/index.ts | 1 + src/templates/scripthash/input.ts | 1 + src/templates/scripthash/output.ts | 1 + src/templates/witnesscommitment/index.ts | 1 + src/templates/witnesscommitment/output.ts | 1 + src/templates/witnesspubkeyhash/index.ts | 1 + src/templates/witnesspubkeyhash/input.ts | 1 + src/templates/witnesspubkeyhash/output.ts | 1 + src/templates/witnessscripthash/index.ts | 1 + src/templates/witnessscripthash/input.ts | 1 + src/templates/witnessscripthash/output.ts | 1 + src/transaction.ts | 3 ++- src/transaction_builder.ts | 21 ++++++++++++++------- src/types.ts | 1 + test/address.js | 6 +++--- test/block.js | 2 +- test/bufferutils.js | 2 +- test/classify.js | 20 ++++++++++---------- test/crypto.js | 2 +- test/ecpair.js | 6 +++--- test/payments.js | 2 +- test/payments.utils.js | 4 ++-- test/script.js | 2 +- test/script_number.js | 2 +- test/script_signature.js | 2 +- test/transaction.js | 4 ++-- test/transaction_builder.js | 16 ++++++++-------- test/types.js | 2 +- tsconfig.json | 3 ++- 60 files changed, 146 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index 52c7e8d..669233e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bitcoinjs-lib", "version": "4.0.2", "description": "Client-side Bitcoin JavaScript library", - "main": "./src/index.js", + "main": "./dist/src/index.js", "engines": { "node": ">=8.0.0" }, @@ -17,17 +17,18 @@ "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha", - "integration": "mocha --timeout 50000 test/integration/", + "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", - "test": "npm run standard && npm run coverage", - "unit": "mocha" + "test": "npm run build && npm run standard && npm run coverage", + "unit": "npm run build && mocha", + "build": "tsc -p tsconfig.json" }, "repository": { "type": "git", "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git" }, "files": [ - "src" + "dist/src" ], "dependencies": { "bech32": "^1.1.2", diff --git a/src/address.ts b/src/address.ts index e71bd46..e6f60fc 100644 --- a/src/address.ts +++ b/src/address.ts @@ -95,3 +95,4 @@ module.exports = { toBech32: toBech32, toOutputScript: toOutputScript } +export {} diff --git a/src/block.ts b/src/block.ts index eb7f708..1d69d0b 100644 --- a/src/block.ts +++ b/src/block.ts @@ -175,3 +175,4 @@ Block.prototype.checkProofOfWork = function () { } module.exports = Block +export {} diff --git a/src/bufferutils.ts b/src/bufferutils.ts index 48647d6..a78b07b 100644 --- a/src/bufferutils.ts +++ b/src/bufferutils.ts @@ -27,3 +27,4 @@ module.exports = { readUInt64LE: readUInt64LE, writeUInt64LE: writeUInt64LE } +export {} diff --git a/src/classify.ts b/src/classify.ts index 8350e07..3f824c4 100644 --- a/src/classify.ts +++ b/src/classify.ts @@ -68,3 +68,4 @@ module.exports = { witness: classifyWitness, types: types } +export {} diff --git a/src/crypto.ts b/src/crypto.ts index a11d061..a04c67f 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -27,3 +27,4 @@ module.exports = { sha1: sha1, sha256: sha256 } +export {} diff --git a/src/ecpair.ts b/src/ecpair.ts index 0e2cf26..0c9fd83 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -104,3 +104,4 @@ module.exports = { fromPublicKey, fromWIF } +export {} diff --git a/src/index.ts b/src/index.ts index 213e98a..967fddc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,3 +14,4 @@ module.exports = { payments: require('./payments'), script: script } +export {} diff --git a/src/networks.ts b/src/networks.ts index fb3957c..0aac048 100644 --- a/src/networks.ts +++ b/src/networks.ts @@ -36,3 +36,4 @@ module.exports = { wif: 0xef } } +export {} diff --git a/src/payments/embed.ts b/src/payments/embed.ts index ea2c8e9..bfb70e5 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -28,7 +28,10 @@ function p2data (a, opts) { }, a) const network = a.network || BITCOIN_NETWORK - const o = { network } + const o = { + network, + data: undefined + } lazy.prop(o, 'output', function () { if (!a.data) return @@ -54,3 +57,4 @@ function p2data (a, opts) { } module.exports = p2data +export {} diff --git a/src/payments/index.ts b/src/payments/index.ts index d445466..bb4e0e6 100644 --- a/src/payments/index.ts +++ b/src/payments/index.ts @@ -10,3 +10,4 @@ module.exports = { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh } // TODO // witness commitment +export {} diff --git a/src/payments/lazy.ts b/src/payments/lazy.ts index 8538752..4a9611c 100644 --- a/src/payments/lazy.ts +++ b/src/payments/lazy.ts @@ -28,3 +28,4 @@ function value (f) { } module.exports = { prop, value } +export {} diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index 5c90a4d..39b38f1 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -42,7 +42,15 @@ function p2ms (a, opts) { }, a) const network = a.network || BITCOIN_NETWORK - const o = { network } + const o = { + network, + m: undefined, + n: undefined, + pubkeys: undefined, + output: undefined, + input: undefined, + signatures: undefined, + } let chunks let decoded = false @@ -129,7 +137,7 @@ function p2ms (a, opts) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - if (a.signatures && !stacksEqual(a.signatures.equals(o.signatures))) throw new TypeError('Signature mismatch') + if (a.signatures && !stacksEqual(a.signatures.equals(o.signatures), undefined)) throw new TypeError('Signature mismatch') if (a.m !== undefined && a.m !== a.signatures.length) throw new TypeError('Signature count mismatch') } } @@ -138,3 +146,4 @@ function p2ms (a, opts) { } module.exports = p2ms +export {} diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index b930612..b810d48 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -30,7 +30,12 @@ function p2pk (a, opts) { const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK - const o = { network } + const o = { + network, + input: undefined, + pubkey: undefined, + signature: undefined, + } lazy.prop(o, 'output', function () { if (!a.pubkey) return @@ -78,3 +83,4 @@ function p2pk (a, opts) { } module.exports = p2pk +export {} diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index e9248a2..c322fc7 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -40,7 +40,12 @@ function p2pkh (a, opts) { const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK - const o = { network } + const o = { + network, + hash: undefined, + pubkey: undefined, + input: undefined, + } lazy.prop(o, 'address', function () { if (!o.hash) return @@ -135,3 +140,4 @@ function p2pkh (a, opts) { } module.exports = p2pkh +export {} diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index 0729c8b..07bb32e 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -50,7 +50,12 @@ function p2sh (a, opts) { network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK } - const o = { network } + const o = { + network, + hash: undefined, + redeem: undefined, + input: undefined, + } const _address = lazy.value(function () { const payload = bs58check.decode(a.address) @@ -191,3 +196,4 @@ function p2sh (a, opts) { } module.exports = p2sh +export {} diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index 1483bd8..1ab21b5 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -46,7 +46,12 @@ function p2wpkh (a, opts) { }) const network = a.network || BITCOIN_NETWORK - const o = { network } + const o = { + network, + hash: undefined, + pubkey: undefined, + witness: undefined, + } lazy.prop(o, 'address', function () { if (!o.hash) return @@ -133,3 +138,4 @@ function p2wpkh (a, opts) { } module.exports = p2wpkh +export {} diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index d8e6e8a..fe19314 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -64,7 +64,12 @@ function p2wsh (a, opts) { network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK } - const o = { network } + const o = { + network, + hash: undefined, + redeem: undefined, + witness: undefined, + } lazy.prop(o, 'address', function () { if (!o.hash) return @@ -178,3 +183,4 @@ function p2wsh (a, opts) { } module.exports = p2wsh +export {} diff --git a/src/script.ts b/src/script.ts index ad7c4e4..514e992 100644 --- a/src/script.ts +++ b/src/script.ts @@ -203,3 +203,4 @@ module.exports = { isPushOnly: isPushOnly, isDefinedHashType: isDefinedHashType } +export {} diff --git a/src/script_number.ts b/src/script_number.ts index 3440797..4df4704 100644 --- a/src/script_number.ts +++ b/src/script_number.ts @@ -65,3 +65,4 @@ module.exports = { decode: decode, encode: encode } +export {} diff --git a/src/script_signature.ts b/src/script_signature.ts index bdb3ddb..b1f933a 100644 --- a/src/script_signature.ts +++ b/src/script_signature.ts @@ -62,3 +62,4 @@ module.exports = { decode: decode, encode: encode } +export {} diff --git a/src/templates/multisig/index.ts b/src/templates/multisig/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/multisig/index.ts +++ b/src/templates/multisig/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/multisig/input.ts b/src/templates/multisig/input.ts index a66f05f..d395108 100644 --- a/src/templates/multisig/input.ts +++ b/src/templates/multisig/input.ts @@ -21,3 +21,4 @@ function check (script, allowIncomplete) { check.toJSON = function () { return 'multisig input' } module.exports = { check } +export {} diff --git a/src/templates/multisig/output.ts b/src/templates/multisig/output.ts index 5c9d81f..5ff18f1 100644 --- a/src/templates/multisig/output.ts +++ b/src/templates/multisig/output.ts @@ -27,3 +27,4 @@ function check (script, allowIncomplete) { check.toJSON = function () { return 'multi-sig output' } module.exports = { check } +export {} diff --git a/src/templates/nulldata.ts b/src/templates/nulldata.ts index d42fd71..145b504 100644 --- a/src/templates/nulldata.ts +++ b/src/templates/nulldata.ts @@ -12,3 +12,4 @@ function check (script) { check.toJSON = function () { return 'null data output' } module.exports = { output: { check: check } } +export {} diff --git a/src/templates/pubkey/index.ts b/src/templates/pubkey/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/pubkey/index.ts +++ b/src/templates/pubkey/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/pubkey/input.ts b/src/templates/pubkey/input.ts index ec21155..b6963e7 100644 --- a/src/templates/pubkey/input.ts +++ b/src/templates/pubkey/input.ts @@ -13,3 +13,4 @@ check.toJSON = function () { return 'pubKey input' } module.exports = { check: check } +export {} diff --git a/src/templates/pubkey/output.ts b/src/templates/pubkey/output.ts index b25c8c1..b64c596 100644 --- a/src/templates/pubkey/output.ts +++ b/src/templates/pubkey/output.ts @@ -13,3 +13,4 @@ function check (script) { check.toJSON = function () { return 'pubKey output' } module.exports = { check } +export {} diff --git a/src/templates/pubkeyhash/index.ts b/src/templates/pubkeyhash/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/pubkeyhash/index.ts +++ b/src/templates/pubkeyhash/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/pubkeyhash/input.ts b/src/templates/pubkeyhash/input.ts index f5bc452..cab6f0a 100644 --- a/src/templates/pubkeyhash/input.ts +++ b/src/templates/pubkeyhash/input.ts @@ -12,3 +12,4 @@ function check (script) { check.toJSON = function () { return 'pubKeyHash input' } module.exports = { check } +export {} diff --git a/src/templates/pubkeyhash/output.ts b/src/templates/pubkeyhash/output.ts index fbb6ed1..bf34b83 100644 --- a/src/templates/pubkeyhash/output.ts +++ b/src/templates/pubkeyhash/output.ts @@ -16,3 +16,4 @@ function check (script) { check.toJSON = function () { return 'pubKeyHash output' } module.exports = { check } +export {} diff --git a/src/templates/scripthash/index.ts b/src/templates/scripthash/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/scripthash/index.ts +++ b/src/templates/scripthash/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/scripthash/input.ts b/src/templates/scripthash/input.ts index 5164370..ad53df9 100644 --- a/src/templates/scripthash/input.ts +++ b/src/templates/scripthash/input.ts @@ -46,3 +46,4 @@ function check (script, allowIncomplete) { check.toJSON = function () { return 'scriptHash input' } module.exports = { check } +export {} diff --git a/src/templates/scripthash/output.ts b/src/templates/scripthash/output.ts index b5b6e7a..9f91f17 100644 --- a/src/templates/scripthash/output.ts +++ b/src/templates/scripthash/output.ts @@ -14,3 +14,4 @@ function check (script) { check.toJSON = function () { return 'scriptHash output' } module.exports = { check } +export {} diff --git a/src/templates/witnesscommitment/index.ts b/src/templates/witnesscommitment/index.ts index d459038..d274d6b 100644 --- a/src/templates/witnesscommitment/index.ts +++ b/src/templates/witnesscommitment/index.ts @@ -1,3 +1,4 @@ module.exports = { output: require('./output') } +export {} diff --git a/src/templates/witnesscommitment/output.ts b/src/templates/witnesscommitment/output.ts index 8938f45..db92e54 100644 --- a/src/templates/witnesscommitment/output.ts +++ b/src/templates/witnesscommitment/output.ts @@ -40,3 +40,4 @@ module.exports = { decode: decode, encode: encode } +export {} diff --git a/src/templates/witnesspubkeyhash/index.ts b/src/templates/witnesspubkeyhash/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/witnesspubkeyhash/index.ts +++ b/src/templates/witnesspubkeyhash/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/witnesspubkeyhash/input.ts b/src/templates/witnesspubkeyhash/input.ts index 488e5e6..ec93c47 100644 --- a/src/templates/witnesspubkeyhash/input.ts +++ b/src/templates/witnesspubkeyhash/input.ts @@ -16,3 +16,4 @@ function check (script) { check.toJSON = function () { return 'witnessPubKeyHash input' } module.exports = { check } +export {} diff --git a/src/templates/witnesspubkeyhash/output.ts b/src/templates/witnesspubkeyhash/output.ts index 08af3bc..a289038 100644 --- a/src/templates/witnesspubkeyhash/output.ts +++ b/src/templates/witnesspubkeyhash/output.ts @@ -15,3 +15,4 @@ check.toJSON = function () { return 'Witness pubKeyHash output' } module.exports = { check } +export {} diff --git a/src/templates/witnessscripthash/index.ts b/src/templates/witnessscripthash/index.ts index 46863d6..7192cfd 100644 --- a/src/templates/witnessscripthash/index.ts +++ b/src/templates/witnessscripthash/index.ts @@ -2,3 +2,4 @@ module.exports = { input: require('./input'), output: require('./output') } +export {} diff --git a/src/templates/witnessscripthash/input.ts b/src/templates/witnessscripthash/input.ts index 072a289..c6d47e3 100644 --- a/src/templates/witnessscripthash/input.ts +++ b/src/templates/witnessscripthash/input.ts @@ -37,3 +37,4 @@ function check (chunks, allowIncomplete) { check.toJSON = function () { return 'witnessScriptHash input' } module.exports = { check } +export {} diff --git a/src/templates/witnessscripthash/output.ts b/src/templates/witnessscripthash/output.ts index c9fc21a..3bc327f 100644 --- a/src/templates/witnessscripthash/output.ts +++ b/src/templates/witnessscripthash/output.ts @@ -13,3 +13,4 @@ function check (script) { check.toJSON = function () { return 'Witness scriptHash output' } module.exports = { check } +export {} diff --git a/src/transaction.ts b/src/transaction.ts index 751446f..4ee08d3 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -138,7 +138,7 @@ Transaction.fromBuffer = function (buffer, __noStrict) { } Transaction.fromHex = function (hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex')) + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), undefined) } Transaction.isCoinbaseHash = function (buffer) { @@ -490,3 +490,4 @@ Transaction.prototype.setWitness = function (index, witness) { } module.exports = Transaction +export {} diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index bea1ded..56368bf 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -102,7 +102,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { const outputType = classify.output(redeem.output) let expanded if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput(redeem.input, redeem.witness, outputType) + expanded = expandInput(redeem.input, redeem.witness, outputType, undefined) } else { expanded = expandInput(bscript.compile(redeem.witness), [], outputType, redeem.output) } @@ -473,7 +473,7 @@ TransactionBuilder.prototype.setVersion = function (version) { } TransactionBuilder.fromTransaction = function (transaction, network) { - const txb = new TransactionBuilder(network) + const txb = new TransactionBuilder(network, undefined) // Copy transaction fields txb.setVersion(transaction.version) @@ -537,11 +537,17 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) const prevTxOut = txHash.toString('hex') + ':' + vout if (this.__prevTxSet[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut) - let input = {} + let input = { + value: undefined, + prevOutScript: undefined, + pubkeys: undefined, + signatures: undefined, + prevOutType: undefined, + } // derive what we can from the scriptSig if (options.script !== undefined) { - input = expandInput(options.script, options.witness || []) + input = expandInput(options.script, options.witness || [], undefined, undefined) } // if an input value was given, retain it @@ -554,7 +560,7 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) let prevOutType if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript) + const expanded = expandOutput(options.prevOutScript, undefined) if (expanded.pubkeys) { input.pubkeys = expanded.pubkeys input.signatures = expanded.signatures @@ -705,10 +711,10 @@ function signatureHashType (buffer) { } TransactionBuilder.prototype.__canModifyInputs = function () { - return this.__inputs.every(function (input) { + return (this.__inputs || []).every(function (input) { if (!input.signatures) return true - return input.signatures.every(function (signature) { + return (input.signatures || []).every(function (signature) { if (!signature) return true const hashType = signatureHashType(signature) @@ -775,3 +781,4 @@ TransactionBuilder.prototype.__overMaximumFees = function (bytes) { } module.exports = TransactionBuilder +export {} diff --git a/src/types.ts b/src/types.ts index 2d1ec6f..9fff4a6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -47,3 +47,4 @@ for (var typeName in typeforce) { } module.exports = types +export {} diff --git a/test/address.js b/test/address.js index a0f4df0..19093b6 100644 --- a/test/address.js +++ b/test/address.js @@ -1,7 +1,7 @@ const { describe, it } = require('mocha') const assert = require('assert') -const baddress = require('../src/address') -const bscript = require('../src/script') +const baddress = require('../dist/src/address') +const bscript = require('../dist/src/script') const fixtures = require('./fixtures/address.json') const NETWORKS = Object.assign({ litecoin: { @@ -14,7 +14,7 @@ const NETWORKS = Object.assign({ scriptHash: 0x32, wif: 0xb0 } -}, require('../src/networks')) +}, require('../dist/src/networks')) describe('address', function () { describe('fromBase58Check', function () { diff --git a/test/block.js b/test/block.js index d9ff405..eb52c0c 100644 --- a/test/block.js +++ b/test/block.js @@ -1,6 +1,6 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const Block = require('../src/block') +const Block = require('../dist/src/block') const fixtures = require('./fixtures/block') diff --git a/test/bufferutils.js b/test/bufferutils.js index 5f2c39e..ceb649a 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bufferutils = require('../src/bufferutils') +const bufferutils = require('../dist/src/bufferutils') const fixtures = require('./fixtures/bufferutils.json') diff --git a/test/classify.js b/test/classify.js index 3efcc74..33225b5 100644 --- a/test/classify.js +++ b/test/classify.js @@ -1,18 +1,18 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscript = require('../src/script') -const classify = require('../src/classify') +const bscript = require('../dist/src/script') +const classify = require('../dist/src/classify') const fixtures = require('./fixtures/templates.json') -const multisig = require('../src/templates/multisig') -const nullData = require('../src/templates/nulldata') -const pubKey = require('../src/templates/pubkey') -const pubKeyHash = require('../src/templates/pubkeyhash') -const scriptHash = require('../src/templates/scripthash') -const witnessPubKeyHash = require('../src/templates/witnesspubkeyhash') -const witnessScriptHash = require('../src/templates/witnessscripthash') -const witnessCommitment = require('../src/templates/witnesscommitment') +const multisig = require('../dist/src/templates/multisig') +const nullData = require('../dist/src/templates/nulldata') +const pubKey = require('../dist/src/templates/pubkey') +const pubKeyHash = require('../dist/src/templates/pubkeyhash') +const scriptHash = require('../dist/src/templates/scripthash') +const witnessPubKeyHash = require('../dist/src/templates/witnesspubkeyhash') +const witnessScriptHash = require('../dist/src/templates/witnessscripthash') +const witnessCommitment = require('../dist/src/templates/witnesscommitment') const tmap = { pubKey, diff --git a/test/crypto.js b/test/crypto.js index 3f7802a..0a01c98 100644 --- a/test/crypto.js +++ b/test/crypto.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bcrypto = require('../src/crypto') +const bcrypto = require('../dist/src/crypto') const fixtures = require('./fixtures/crypto') diff --git a/test/ecpair.js b/test/ecpair.js index 45e646d..75a2e81 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -5,12 +5,12 @@ const assert = require('assert') const proxyquire = require('proxyquire') const hoodwink = require('hoodwink') -const ECPair = require('../src/ecpair') +const ECPair = require('../dist/src/ecpair') const tinysecp = require('tiny-secp256k1') const fixtures = require('./fixtures/ecpair.json') -const NETWORKS = require('../src/networks') +const NETWORKS = require('../dist/src/networks') const NETWORKS_LIST = [] // Object.values(NETWORKS) for (let networkName in NETWORKS) { NETWORKS_LIST.push(NETWORKS[networkName]) @@ -144,7 +144,7 @@ describe('ECPair', function () { describe('uses randombytes RNG', function () { it('generates a ECPair', function () { const stub = { randombytes: function () { return d } } - const ProxiedECPair = proxyquire('../src/ecpair', stub) + const ProxiedECPair = proxyquire('../dist/src/ecpair', stub) const keyPair = ProxiedECPair.makeRandom() assert.strictEqual(keyPair.toWIF(), exWIF) diff --git a/test/payments.js b/test/payments.js index 3c07bf3..53e3f16 100644 --- a/test/payments.js +++ b/test/payments.js @@ -4,7 +4,7 @@ const u = require('./payments.utils') ;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) { describe(p, function () { - const fn = require('../src/payments/' + p) + const fn = require('../dist/src/payments/' + p) const fixtures = require('./fixtures/' + p) fixtures.valid.forEach(function (f, i) { diff --git a/test/payments.utils.js b/test/payments.utils.js index 485bf03..086561d 100644 --- a/test/payments.utils.js +++ b/test/payments.utils.js @@ -1,6 +1,6 @@ const t = require('assert') -const bscript = require('../src/script') -const BNETWORKS = require('../src/networks') +const bscript = require('../dist/src/script') +const BNETWORKS = require('../dist/src/networks') function tryHex (x) { if (Buffer.isBuffer(x)) return x.toString('hex') diff --git a/test/script.js b/test/script.js index c2a60ad..013d50a 100644 --- a/test/script.js +++ b/test/script.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscript = require('../src/script') +const bscript = require('../dist/src/script') const minimalData = require('minimaldata') const fixtures = require('./fixtures/script.json') diff --git a/test/script_number.js b/test/script_number.js index bc8f395..1d38e48 100644 --- a/test/script_number.js +++ b/test/script_number.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const scriptNumber = require('../src/script_number') +const scriptNumber = require('../dist/src/script_number') const fixtures = require('./fixtures/script_number.json') describe('script-number', function () { diff --git a/test/script_signature.js b/test/script_signature.js index cee69bd..e56ff68 100644 --- a/test/script_signature.js +++ b/test/script_signature.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscriptSig = require('../src/script').signature +const bscriptSig = require('../dist/src/script').signature const Buffer = require('safe-buffer').Buffer const fixtures = require('./fixtures/signature.json') diff --git a/test/transaction.js b/test/transaction.js index f8b7de9..f315a7d 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -1,8 +1,8 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const bscript = require('../src/script') +const bscript = require('../dist/src/script') const fixtures = require('./fixtures/transaction') -const Transaction = require('../src/transaction') +const Transaction = require('../dist/src/transaction') describe('Transaction', function () { function fromRaw (raw, noWitness) { diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 85adcff..a4b309a 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,13 +1,13 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const baddress = require('../src/address') -const bscript = require('../src/script') -const payments = require('../src/payments') - -const ECPair = require('../src/ecpair') -const Transaction = require('../src/transaction') -const TransactionBuilder = require('../src/transaction_builder') -const NETWORKS = require('../src/networks') +const baddress = require('../dist/src/address') +const bscript = require('../dist/src/script') +const payments = require('../dist/src/payments') + +const ECPair = require('../dist/src/ecpair') +const Transaction = require('../dist/src/transaction') +const TransactionBuilder = require('../dist/src/transaction_builder') +const NETWORKS = require('../dist/src/networks') const fixtures = require('./fixtures/transaction_builder') diff --git a/test/types.js b/test/types.js index d245d53..831d415 100644 --- a/test/types.js +++ b/test/types.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const types = require('../src/types') +const types = require('../dist/src/types') const typeforce = require('typeforce') describe('types', function () { diff --git a/tsconfig.json b/tsconfig.json index 8e1edb4..f358d14 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,7 @@ "src/**/*" ], "exclude": [ - "**/*.spec.ts" + "**/*.spec.ts", + "node_modules/**/*" ] } From b4d54af0fe438031b348b52c18554c24f191e10d Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 26 Dec 2018 18:37:09 +0900 Subject: [PATCH 060/183] Remove AllowJS and get definitions --- package.json | 2 +- src/templates/nulldata.ts | 9 ++++++--- src/types.ts | 38 ++++++++++++-------------------------- tsconfig.json | 6 +++--- 4 files changed, 22 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 669233e..e704249 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", "unit": "npm run build && mocha", - "build": "tsc -p tsconfig.json" + "build": "tsc -d -p tsconfig.json" }, "repository": { "type": "git", diff --git a/src/templates/nulldata.ts b/src/templates/nulldata.ts index 145b504..48b0365 100644 --- a/src/templates/nulldata.ts +++ b/src/templates/nulldata.ts @@ -3,7 +3,7 @@ const bscript = require('../script') const OPS = require('bitcoin-ops') -function check (script) { +export function check (script) { const buffer = bscript.compile(script) return buffer.length > 1 && @@ -11,5 +11,8 @@ function check (script) { } check.toJSON = function () { return 'null data output' } -module.exports = { output: { check: check } } -export {} +const output = { check } + +export { + output +} diff --git a/src/types.ts b/src/types.ts index 9fff4a6..57431ca 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,25 +1,25 @@ const typeforce = require('typeforce') -const UINT31_MAX = Math.pow(2, 31) - 1 -function UInt31 (value) { +const UINT31_MAX: number = Math.pow(2, 31) - 1 +export function UInt31 (value: number): boolean { return typeforce.UInt32(value) && value <= UINT31_MAX } -function BIP32Path (value) { - return typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) +export function BIP32Path (value: string): boolean { + return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) } BIP32Path.toJSON = function () { return 'BIP32 derivation path' } -const SATOSHI_MAX = 21 * 1e14 -function Satoshi (value) { +const SATOSHI_MAX: number = 21 * 1e14 +export function Satoshi (value: number): boolean { return typeforce.UInt53(value) && value <= SATOSHI_MAX } // external dependent types -const ECPoint = typeforce.quacksLike('Point') +export const ECPoint = typeforce.quacksLike('Point') // exposed, external API -const Network = typeforce.compile({ +export const Network = typeforce.compile({ messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), bip32: { public: typeforce.UInt32, @@ -30,21 +30,7 @@ const Network = typeforce.compile({ wif: typeforce.UInt8 }) -// extend typeforce types with ours -const types = { - BIP32Path: BIP32Path, - Buffer256bit: typeforce.BufferN(32), - ECPoint: ECPoint, - Hash160bit: typeforce.BufferN(20), - Hash256bit: typeforce.BufferN(32), - Network: Network, - Satoshi: Satoshi, - UInt31: UInt31 -} - -for (var typeName in typeforce) { - types[typeName] = typeforce[typeName] -} - -module.exports = types -export {} +export const Buffer256bit = typeforce.BufferN(32) +export const Hash160bit = typeforce.BufferN(20) +export const Hash256bit = typeforce.BufferN(32) +export * from 'typeforce' diff --git a/tsconfig.json b/tsconfig.json index f358d14..8803b83 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,12 +7,12 @@ "types": [ "node" ], - "allowJs": true, + "allowJs": false, "strict": false, "noImplicitAny": false, "strictNullChecks": false, - "strictFunctionTypes": false, - "strictBindCallApply": false, + "strictFunctionTypes": true, + "strictBindCallApply": true, "strictPropertyInitialization": false, "noImplicitThis": false, "alwaysStrict": false, From 037fbd898427926b83609473cd2420e4ee6469fd Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 26 Dec 2018 16:13:43 +0900 Subject: [PATCH 061/183] # This is a combination of 2 commits. # The first commit's message is: Add types to Networks and Addresses # This is the 2nd commit message: Added types --- src/address.ts | 48 ++++++++++++++++++----------- src/bufferutils.ts | 12 ++------ src/classify.ts | 35 +++++++++++---------- src/crypto.ts | 19 +++--------- src/networks.ts | 76 ++++++++++++++++++++++++++-------------------- 5 files changed, 99 insertions(+), 91 deletions(-) diff --git a/src/address.ts b/src/address.ts index e6f60fc..b758a66 100644 --- a/src/address.ts +++ b/src/address.ts @@ -6,8 +6,21 @@ const networks = require('./networks') const typeforce = require('typeforce') const types = require('./types') const payments = require('./payments') +import * as Networks from './networks' +import { Network } from './networks' -function fromBase58Check (address) { +export declare type Base58CheckResult = { + hash: Buffer; + version: number; +} + +export declare type Bech32Result = { + version: number; + prefix: string; + data: Buffer; +} + +function fromBase58Check (address: string): Base58CheckResult { const payload = bs58check.decode(address) // TODO: 4.0.0, move to "toOutputScript" @@ -20,7 +33,7 @@ function fromBase58Check (address) { return { version: version, hash: hash } } -function fromBech32 (address) { +function fromBech32 (address: string): Bech32Result { const result = bech32.decode(address) const data = bech32.fromWords(result.words.slice(1)) @@ -31,7 +44,7 @@ function fromBech32 (address) { } } -function toBase58Check (hash, version) { +function toBase58Check (hash: Buffer, version: number): string { typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments) const payload = Buffer.allocUnsafe(21) @@ -41,14 +54,14 @@ function toBase58Check (hash, version) { return bs58check.encode(payload) } -function toBech32 (data, version, prefix) { +function toBech32 (data: Buffer, version: number, prefix: string): string { const words = bech32.toWords(data) words.unshift(version) return bech32.encode(prefix, words) } -function fromOutputScript (output, network) { +function fromOutputScript (output: Buffer, network: Network): string { //TODO: Network network = network || networks.bitcoin try { return payments.p2pkh({ output, network }).address } catch (e) {} @@ -59,27 +72,28 @@ function fromOutputScript (output, network) { throw new Error(bscript.toASM(output) + ' has no matching Address') } -function toOutputScript (address, network) { +function toOutputScript (address: string, network: Network): Buffer { network = network || networks.bitcoin - let decode + let decodeBase58: Base58CheckResult + let decodeBech32: Bech32Result try { - decode = fromBase58Check(address) + decodeBase58 = fromBase58Check(address) } catch (e) {} - if (decode) { - if (decode.version === network.pubKeyHash) return payments.p2pkh({ hash: decode.hash }).output - if (decode.version === network.scriptHash) return payments.p2sh({ hash: decode.hash }).output + if (decodeBase58) { + if (decodeBase58.version === network.pubKeyHash) return payments.p2pkh({ hash: decodeBase58.hash }).output + if (decodeBase58.version === network.scriptHash) return payments.p2sh({ hash: decodeBase58.hash }).output } else { try { - decode = fromBech32(address) + decodeBech32 = fromBech32(address) } catch (e) {} - if (decode) { - if (decode.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix') - if (decode.version === 0) { - if (decode.data.length === 20) return payments.p2wpkh({ hash: decode.data }).output - if (decode.data.length === 32) return payments.p2wsh({ hash: decode.data }).output + if (decodeBech32) { + if (decodeBech32.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix') + if (decodeBech32.version === 0) { + if (decodeBech32.data.length === 20) return payments.p2wpkh({ hash: decodeBech32.data }).output + if (decodeBech32.data.length === 32) return payments.p2wsh({ hash: decodeBech32.data }).output } } } diff --git a/src/bufferutils.ts b/src/bufferutils.ts index a78b07b..b66c84a 100644 --- a/src/bufferutils.ts +++ b/src/bufferutils.ts @@ -1,12 +1,12 @@ // https://github.com/feross/buffer/blob/master/index.js#L1127 -function verifuint (value, max) { +function verifuint (value: number, max: number): void { if (typeof value !== 'number') throw new Error('cannot write a non-number as a number') if (value < 0) throw new Error('specified a negative value for writing an unsigned value') if (value > max) throw new Error('RangeError: value out of range') if (Math.floor(value) !== value) throw new Error('value has a fractional component') } -function readUInt64LE (buffer, offset) { +export function readUInt64LE (buffer: Buffer, offset: number): number { const a = buffer.readUInt32LE(offset) let b = buffer.readUInt32LE(offset + 4) b *= 0x100000000 @@ -15,16 +15,10 @@ function readUInt64LE (buffer, offset) { return b + a } -function writeUInt64LE (buffer, value, offset) { +export function writeUInt64LE (buffer: Buffer, value: number, offset: number): number { verifuint(value, 0x001fffffffffffff) buffer.writeInt32LE(value & -1, offset) buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) return offset + 8 } - -module.exports = { - readUInt64LE: readUInt64LE, - writeUInt64LE: writeUInt64LE -} -export {} diff --git a/src/classify.ts b/src/classify.ts index 3f824c4..5eabc7e 100644 --- a/src/classify.ts +++ b/src/classify.ts @@ -9,18 +9,18 @@ const witnessScriptHash = require('./templates/witnessscripthash') const witnessCommitment = require('./templates/witnesscommitment') const types = { - P2MS: 'multisig', - NONSTANDARD: 'nonstandard', - NULLDATA: 'nulldata', - P2PK: 'pubkey', - P2PKH: 'pubkeyhash', - P2SH: 'scripthash', - P2WPKH: 'witnesspubkeyhash', - P2WSH: 'witnessscripthash', - WITNESS_COMMITMENT: 'witnesscommitment' + P2MS: 'multisig', + NONSTANDARD: 'nonstandard', + NULLDATA: 'nulldata', + P2PK: 'pubkey', + P2PKH: 'pubkeyhash', + P2SH: 'scripthash', + P2WPKH: 'witnesspubkeyhash', + P2WSH: 'witnessscripthash', + WITNESS_COMMITMENT: 'witnesscommitment' } -function classifyOutput (script) { +function classifyOutput (script: Buffer): string { if (witnessPubKeyHash.output.check(script)) return types.P2WPKH if (witnessScriptHash.output.check(script)) return types.P2WSH if (pubKeyHash.output.check(script)) return types.P2PKH @@ -38,7 +38,7 @@ function classifyOutput (script) { return types.NONSTANDARD } -function classifyInput (script, allowIncomplete) { +function classifyInput (script: Buffer, allowIncomplete: boolean): string { // XXX: optimization, below functions .decompile before use const chunks = decompile(script) if (!chunks) throw new TypeError('Invalid script') @@ -51,7 +51,7 @@ function classifyInput (script, allowIncomplete) { return types.NONSTANDARD } -function classifyWitness (script, allowIncomplete) { +function classifyWitness (script: Buffer, allowIncomplete: boolean): string { // XXX: optimization, below functions .decompile before use const chunks = decompile(script) if (!chunks) throw new TypeError('Invalid script') @@ -62,10 +62,9 @@ function classifyWitness (script, allowIncomplete) { return types.NONSTANDARD } -module.exports = { - input: classifyInput, - output: classifyOutput, - witness: classifyWitness, - types: types +export { + classifyInput as input, + classifyOutput as output, + classifyWitness as witness, + types, } -export {} diff --git a/src/crypto.ts b/src/crypto.ts index a04c67f..6aabb5b 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,30 +1,21 @@ const createHash = require('create-hash') -function ripemd160 (buffer) { +export function ripemd160 (buffer: Buffer): Buffer { return createHash('rmd160').update(buffer).digest() } -function sha1 (buffer) { +export function sha1 (buffer: Buffer): Buffer { return createHash('sha1').update(buffer).digest() } -function sha256 (buffer) { +export function sha256 (buffer: Buffer): Buffer { return createHash('sha256').update(buffer).digest() } -function hash160 (buffer) { +export function hash160 (buffer: Buffer): Buffer { return ripemd160(sha256(buffer)) } -function hash256 (buffer) { +export function hash256 (buffer: Buffer): Buffer { return sha256(sha256(buffer)) } - -module.exports = { - hash160: hash160, - hash256: hash256, - ripemd160: ripemd160, - sha1: sha1, - sha256: sha256 -} -export {} diff --git a/src/networks.ts b/src/networks.ts index 0aac048..f8ee1aa 100644 --- a/src/networks.ts +++ b/src/networks.ts @@ -1,39 +1,49 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 +export declare type Network = { + messagePrefix: string; + bech32: string; + bip32: bip32; + pubKeyHash: number; + scriptHash: number; + wif: number; +} + +declare type bip32 = { + public: number; + private: number; +} -module.exports = { - bitcoin: { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'bc', - bip32: { - public: 0x0488b21e, - private: 0x0488ade4 - }, - pubKeyHash: 0x00, - scriptHash: 0x05, - wif: 0x80 +export const bitcoin: Network = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 }, - regtest: { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'bcrt', - bip32: { - public: 0x043587cf, - private: 0x04358394 - }, - pubKeyHash: 0x6f, - scriptHash: 0xc4, - wif: 0xef + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80 +} +export const regtest: Network = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef +} +export const testnet: Network = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394 }, - testnet: { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'tb', - bip32: { - public: 0x043587cf, - private: 0x04358394 - }, - pubKeyHash: 0x6f, - scriptHash: 0xc4, - wif: 0xef - } + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef } -export {} From 91d3037cf3b58420f7cfc535cd8b128eab8c0f0f Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 27 Dec 2018 17:15:24 +0900 Subject: [PATCH 062/183] Fix some exports --- src/address.ts | 26 ++++++++------------------ src/index.ts | 37 +++++++++++++++++++++++-------------- src/networks.ts | 4 ++-- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/address.ts b/src/address.ts index b758a66..e657d24 100644 --- a/src/address.ts +++ b/src/address.ts @@ -9,18 +9,18 @@ const payments = require('./payments') import * as Networks from './networks' import { Network } from './networks' -export declare type Base58CheckResult = { +export type Base58CheckResult = { hash: Buffer; version: number; } -export declare type Bech32Result = { +export type Bech32Result = { version: number; prefix: string; data: Buffer; } -function fromBase58Check (address: string): Base58CheckResult { +export function fromBase58Check (address: string): Base58CheckResult { const payload = bs58check.decode(address) // TODO: 4.0.0, move to "toOutputScript" @@ -33,7 +33,7 @@ function fromBase58Check (address: string): Base58CheckResult { return { version: version, hash: hash } } -function fromBech32 (address: string): Bech32Result { +export function fromBech32 (address: string): Bech32Result { const result = bech32.decode(address) const data = bech32.fromWords(result.words.slice(1)) @@ -44,7 +44,7 @@ function fromBech32 (address: string): Bech32Result { } } -function toBase58Check (hash: Buffer, version: number): string { +export function toBase58Check (hash: Buffer, version: number): string { typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments) const payload = Buffer.allocUnsafe(21) @@ -54,14 +54,14 @@ function toBase58Check (hash: Buffer, version: number): string { return bs58check.encode(payload) } -function toBech32 (data: Buffer, version: number, prefix: string): string { +export function toBech32 (data: Buffer, version: number, prefix: string): string { const words = bech32.toWords(data) words.unshift(version) return bech32.encode(prefix, words) } -function fromOutputScript (output: Buffer, network: Network): string { //TODO: Network +export function fromOutputScript (output: Buffer, network: Network): string { //TODO: Network network = network || networks.bitcoin try { return payments.p2pkh({ output, network }).address } catch (e) {} @@ -72,7 +72,7 @@ function fromOutputScript (output: Buffer, network: Network): string { //TODO: N throw new Error(bscript.toASM(output) + ' has no matching Address') } -function toOutputScript (address: string, network: Network): Buffer { +export function toOutputScript (address: string, network: Network): Buffer { network = network || networks.bitcoin let decodeBase58: Base58CheckResult @@ -100,13 +100,3 @@ function toOutputScript (address: string, network: Network): Buffer { throw new Error(address + ' has no matching Script') } - -module.exports = { - fromBase58Check: fromBase58Check, - fromBech32: fromBech32, - fromOutputScript: fromOutputScript, - toBase58Check: toBase58Check, - toBech32: toBech32, - toOutputScript: toOutputScript -} -export {} diff --git a/src/index.ts b/src/index.ts index 967fddc..d1b897b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,26 @@ -const script = require('./script') +const opcodes = require('bitcoin-ops') -module.exports = { - Block: require('./block'), - ECPair: require('./ecpair'), - Transaction: require('./transaction'), - TransactionBuilder: require('./transaction_builder'), +import * as Block from './block' +import * as ECPair from './ecpair' +import * as Transaction from './transaction' +import * as TransactionBuilder from './transaction_builder' +import * as address from './address' +import * as bip32 from 'bip32' +import * as crypto from './crypto' +import * as networks from './networks' +import * as payments from './payments' +import * as script from './script' - address: require('./address'), - bip32: require('bip32'), - crypto: require('./crypto'), - networks: require('./networks'), - opcodes: require('bitcoin-ops'), - payments: require('./payments'), - script: script +export { + Block, + ECPair, + Transaction, + TransactionBuilder, + address, + bip32, + crypto, + networks, + opcodes, + payments, + script, } -export {} diff --git a/src/networks.ts b/src/networks.ts index f8ee1aa..11147af 100644 --- a/src/networks.ts +++ b/src/networks.ts @@ -1,6 +1,6 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 -export declare type Network = { +export type Network = { messagePrefix: string; bech32: string; bip32: bip32; @@ -9,7 +9,7 @@ export declare type Network = { wif: number; } -declare type bip32 = { +type bip32 = { public: number; private: number; } From 2eb95349398ba011f63b9fcf03328ee9185281e6 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 27 Dec 2018 17:49:53 +0900 Subject: [PATCH 063/183] Move Block Class from ES6 PR --- src/block.ts | 328 +++++++++++++++++++++++++++++--------------------- src/index.ts | 2 +- test/block.js | 2 +- 3 files changed, 191 insertions(+), 141 deletions(-) diff --git a/src/block.ts b/src/block.ts index 1d69d0b..b2602dd 100644 --- a/src/block.ts +++ b/src/block.ts @@ -5,174 +5,224 @@ const typeforce = require('typeforce') const types = require('./types') const varuint = require('varuint-bitcoin') -const Transaction = require('./transaction') - -function Block () { - this.version = 1 - this.prevHash = null - this.merkleRoot = null - this.timestamp = 0 - this.bits = 0 - this.nonce = 0 +const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions') +const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block') +const errorBufferTooSmall = new Error('Buffer too small (< 80 bytes)') + +function txesHaveWitness (transactions: Array): boolean { + return transactions !== undefined && + transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0 } -Block.fromBuffer = function (buffer) { - if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)') - - let offset = 0 - function readSlice (n) { - offset += n - return buffer.slice(offset - n, offset) - } - - function readUInt32 () { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i - } +const Transaction = require('./transaction') - function readInt32 () { - const i = buffer.readInt32LE(offset) - offset += 4 - return i +export class Block { + version: number + prevHash: Buffer + merkleRoot: Buffer + timestamp: number + witnessCommit: Buffer + bits: number + nonce: number + transactions: Array + + constructor () { + this.version = 1 + this.timestamp = 0 + this.bits = 0 + this.nonce = 0 } - const block = new Block() - block.version = readInt32() - block.prevHash = readSlice(32) - block.merkleRoot = readSlice(32) - block.timestamp = readUInt32() - block.bits = readUInt32() - block.nonce = readUInt32() - - if (buffer.length === 80) return block - - function readVarInt () { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi + static fromBuffer (buffer: Buffer): Block { + if (buffer.length < 80) throw errorBufferTooSmall + + let offset: number = 0 + const readSlice = (n: number): Buffer => { + offset += n + return buffer.slice(offset - n, offset) + } + + const readUInt32 = (): number => { + const i = buffer.readUInt32LE(offset) + offset += 4 + return i + } + + const readInt32 = (): number => { + const i = buffer.readInt32LE(offset) + offset += 4 + return i + } + + const block = new Block() + block.version = readInt32() + block.prevHash = readSlice(32) + block.merkleRoot = readSlice(32) + block.timestamp = readUInt32() + block.bits = readUInt32() + block.nonce = readUInt32() + + if (buffer.length === 80) return block + + const readVarInt = (): number => { + const vi = varuint.decode(buffer, offset) + offset += varuint.decode.bytes + return vi + } + + const readTransaction = (): any => { + const tx = Transaction.fromBuffer(buffer.slice(offset), true) + offset += tx.byteLength() + return tx + } + + const nTransactions = readVarInt() + block.transactions = [] + + for (var i = 0; i < nTransactions; ++i) { + const tx = readTransaction() + block.transactions.push(tx) + } + + // This Block contains a witness commit + if (block.hasWitnessCommit()) { + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + let witnessCommits = block.transactions[0].outs + .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) + .map(out => out.script.slice(6, 38)) + + // Use the commit with the highest output (should only be one though) + block.witnessCommit = witnessCommits[witnessCommits.length - 1] + } + + return block } - function readTransaction () { - const tx = Transaction.fromBuffer(buffer.slice(offset), true) - offset += tx.byteLength() - return tx + static fromHex (hex: string): Block { + return Block.fromBuffer(Buffer.from(hex, 'hex')) } - const nTransactions = readVarInt() - block.transactions = [] - - for (var i = 0; i < nTransactions; ++i) { - const tx = readTransaction() - block.transactions.push(tx) + static calculateTarget (bits: number): Buffer { + const exponent = ((bits & 0xff000000) >> 24) - 3 + const mantissa = bits & 0x007fffff + const target = Buffer.alloc(32, 0) + target.writeUIntBE(mantissa, 29 - exponent, 3) + return target } - return block -} - -Block.prototype.byteLength = function (headersOnly) { - if (headersOnly || !this.transactions) return 80 - - return 80 + varuint.encodingLength(this.transactions.length) + this.transactions.reduce(function (a, x) { - return a + x.byteLength() - }, 0) -} - -Block.fromHex = function (hex) { - return Block.fromBuffer(Buffer.from(hex, 'hex')) -} - -Block.prototype.getHash = function () { - return bcrypto.hash256(this.toBuffer(true)) -} - -Block.prototype.getId = function () { - return this.getHash().reverse().toString('hex') -} - -Block.prototype.getUTCDate = function () { - const date = new Date(0) // epoch - date.setUTCSeconds(this.timestamp) + static calculateMerkleRoot (transactions: Array, forWitness: boolean | void): Buffer { + typeforce([{ getHash: types.Function }], transactions) + if (transactions.length === 0) throw errorMerkleNoTxes + if (forWitness && !txesHaveWitness(transactions)) throw errorWitnessNotSegwit - return date -} + const hashes = transactions.map(transaction => transaction.getHash(forWitness)) -// TODO: buffer, offset compatibility -Block.prototype.toBuffer = function (headersOnly) { - const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)) + const rootHash = fastMerkleRoot(hashes, bcrypto.hash256) - let offset = 0 - function writeSlice (slice) { - slice.copy(buffer, offset) - offset += slice.length + return forWitness + ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) + : rootHash } - function writeInt32 (i) { - buffer.writeInt32LE(i, offset) - offset += 4 - } - function writeUInt32 (i) { - buffer.writeUInt32LE(i, offset) - offset += 4 + hasWitnessCommit (): boolean { + return txesHaveWitness(this.transactions) } - writeInt32(this.version) - writeSlice(this.prevHash) - writeSlice(this.merkleRoot) - writeUInt32(this.timestamp) - writeUInt32(this.bits) - writeUInt32(this.nonce) + byteLength (headersOnly: boolean): number { + if (headersOnly || !this.transactions) return 80 - if (headersOnly || !this.transactions) return buffer + return 80 + varuint.encodingLength(this.transactions.length) + + this.transactions.reduce((a, x) => a + x.byteLength(), 0) + } - varuint.encode(this.transactions.length, buffer, offset) - offset += varuint.encode.bytes + getHash (): Buffer { + return bcrypto.hash256(this.toBuffer(true)) + } - this.transactions.forEach(function (tx) { - const txSize = tx.byteLength() // TODO: extract from toBuffer? - tx.toBuffer(buffer, offset) - offset += txSize - }) + getId (): string { + return Buffer.from(this.getHash().reverse()).toString('hex') + } - return buffer -} + getUTCDate (): Date { + const date = new Date(0) // epoch + date.setUTCSeconds(this.timestamp) -Block.prototype.toHex = function (headersOnly) { - return this.toBuffer(headersOnly).toString('hex') -} + return date + } -Block.calculateTarget = function (bits) { - const exponent = ((bits & 0xff000000) >> 24) - 3 - const mantissa = bits & 0x007fffff - const target = Buffer.alloc(32, 0) - target.writeUIntBE(mantissa, 29 - exponent, 3) - return target -} + // TODO: buffer, offset compatibility + toBuffer (headersOnly: boolean): Buffer { + const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)) + + let offset: number = 0 + const writeSlice = (slice: Buffer): void => { + slice.copy(buffer, offset) + offset += slice.length + } + + const writeInt32 = (i: number): void => { + buffer.writeInt32LE(i, offset) + offset += 4 + } + const writeUInt32 = (i: number): void => { + buffer.writeUInt32LE(i, offset) + offset += 4 + } + + writeInt32(this.version) + writeSlice(this.prevHash) + writeSlice(this.merkleRoot) + writeUInt32(this.timestamp) + writeUInt32(this.bits) + writeUInt32(this.nonce) + + if (headersOnly || !this.transactions) return buffer + + varuint.encode(this.transactions.length, buffer, offset) + offset += varuint.encode.bytes + + this.transactions.forEach(tx => { + const txSize = tx.byteLength() // TODO: extract from toBuffer? + tx.toBuffer(buffer, offset) + offset += txSize + }) + + return buffer + } -Block.calculateMerkleRoot = function (transactions) { - typeforce([{ getHash: types.Function }], transactions) - if (transactions.length === 0) throw TypeError('Cannot compute merkle root for zero transactions') + toHex (headersOnly: boolean): string { + return this.toBuffer(headersOnly).toString('hex') + } - const hashes = transactions.map(function (transaction) { - return transaction.getHash() - }) + checkMerkleRoot (): boolean { + if (!this.transactions) throw errorMerkleNoTxes - return fastMerkleRoot(hashes, bcrypto.hash256) -} + const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) + return this.merkleRoot.compare(actualMerkleRoot) === 0 + } -Block.prototype.checkMerkleRoot = function () { - if (!this.transactions) return false + checkWitnessCommit (): boolean { + if (!this.transactions) throw errorMerkleNoTxes + if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit - const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) - return this.merkleRoot.compare(actualMerkleRoot) === 0 -} + const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true) + return this.witnessCommit.compare(actualWitnessCommit) === 0 + } -Block.prototype.checkProofOfWork = function () { - const hash = this.getHash().reverse() - const target = Block.calculateTarget(this.bits) + checkProofOfWork (): boolean { + const hash: Buffer = Buffer.from(this.getHash().reverse()) + const target = Block.calculateTarget(this.bits) - return hash.compare(target) <= 0 + return hash.compare(target) <= 0 + } } - -module.exports = Block -export {} diff --git a/src/index.ts b/src/index.ts index d1b897b..4d840a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ const opcodes = require('bitcoin-ops') -import * as Block from './block' +import { Block } from './block' import * as ECPair from './ecpair' import * as Transaction from './transaction' import * as TransactionBuilder from './transaction_builder' diff --git a/test/block.js b/test/block.js index eb52c0c..07d0741 100644 --- a/test/block.js +++ b/test/block.js @@ -1,6 +1,6 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const Block = require('../dist/src/block') +const Block = require('..').Block const fixtures = require('./fixtures/block') From a652d0492dac9a8c05ae77da54471ff6eda13b8b Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 27 Dec 2018 18:26:08 +0900 Subject: [PATCH 064/183] Added Transaction --- src/block.ts | 11 +- src/index.ts | 2 +- src/transaction.ts | 826 ++++++++++++++++++++---------------- src/transaction_builder.ts | 7 +- test/block.js | 15 + test/fixtures/block.json | 15 + test/transaction.js | 2 +- test/transaction_builder.js | 2 +- 8 files changed, 493 insertions(+), 387 deletions(-) diff --git a/src/block.ts b/src/block.ts index b2602dd..92c4fb1 100644 --- a/src/block.ts +++ b/src/block.ts @@ -1,3 +1,4 @@ +import { Transaction } from './transaction' const Buffer = require('safe-buffer').Buffer const bcrypto = require('./crypto') const fastMerkleRoot = require('merkle-lib/fastRoot') @@ -9,7 +10,7 @@ const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero tra const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block') const errorBufferTooSmall = new Error('Buffer too small (< 80 bytes)') -function txesHaveWitness (transactions: Array): boolean { +function txesHaveWitness (transactions: Array): boolean { return transactions !== undefined && transactions instanceof Array && transactions[0] && @@ -21,8 +22,6 @@ function txesHaveWitness (transactions: Array): boolean { transactions[0].ins[0].witness.length > 0 } -const Transaction = require('./transaction') - export class Block { version: number prevHash: Buffer @@ -31,7 +30,7 @@ export class Block { witnessCommit: Buffer bits: number nonce: number - transactions: Array + transactions: Array constructor () { this.version = 1 @@ -120,12 +119,12 @@ export class Block { return target } - static calculateMerkleRoot (transactions: Array, forWitness: boolean | void): Buffer { + static calculateMerkleRoot (transactions: Array, forWitness: boolean | void): Buffer { typeforce([{ getHash: types.Function }], transactions) if (transactions.length === 0) throw errorMerkleNoTxes if (forWitness && !txesHaveWitness(transactions)) throw errorWitnessNotSegwit - const hashes = transactions.map(transaction => transaction.getHash(forWitness)) + const hashes = transactions.map(transaction => transaction.getHash((forWitness))) const rootHash = fastMerkleRoot(hashes, bcrypto.hash256) diff --git a/src/index.ts b/src/index.ts index 4d840a9..389e2b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ const opcodes = require('bitcoin-ops') import { Block } from './block' import * as ECPair from './ecpair' -import * as Transaction from './transaction' +import { Transaction } from './transaction' import * as TransactionBuilder from './transaction_builder' import * as address from './address' import * as bip32 from 'bip32' diff --git a/src/transaction.ts b/src/transaction.ts index 4ee08d3..88e4280 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -1,5 +1,5 @@ +import * as bcrypto from './crypto' const Buffer = require('safe-buffer').Buffer -const bcrypto = require('./crypto') const bscript = require('./script') const bufferutils = require('./bufferutils') const opcodes = require('bitcoin-ops') @@ -7,487 +7,563 @@ const typeforce = require('typeforce') const types = require('./types') const varuint = require('varuint-bitcoin') -function varSliceSize (someScript) { +function varSliceSize (someScript: Buffer): number { const length = someScript.length return varuint.encodingLength(length) + length } -function vectorSize (someVector) { +function vectorSize (someVector: Array): number { const length = someVector.length - return varuint.encodingLength(length) + someVector.reduce(function (sum, witness) { + return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { return sum + varSliceSize(witness) }, 0) } -function Transaction () { - this.version = 1 - this.locktime = 0 - this.ins = [] - this.outs = [] -} - -Transaction.DEFAULT_SEQUENCE = 0xffffffff -Transaction.SIGHASH_ALL = 0x01 -Transaction.SIGHASH_NONE = 0x02 -Transaction.SIGHASH_SINGLE = 0x03 -Transaction.SIGHASH_ANYONECANPAY = 0x80 -Transaction.ADVANCED_TRANSACTION_MARKER = 0x00 -Transaction.ADVANCED_TRANSACTION_FLAG = 0x01 - -const EMPTY_SCRIPT = Buffer.allocUnsafe(0) -const EMPTY_WITNESS = [] -const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex') -const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex') -const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex') -const BLANK_OUTPUT = { +const EMPTY_SCRIPT: Buffer = Buffer.allocUnsafe(0) +const EMPTY_WITNESS: Array = [] +const ZERO: Buffer = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex') +const ONE: Buffer = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex') +const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex') +const BLANK_OUTPUT: BlankOutput = { script: EMPTY_SCRIPT, valueBuffer: VALUE_UINT64_MAX } -Transaction.fromBuffer = function (buffer, __noStrict) { - let offset = 0 - function readSlice (n) { - offset += n - return buffer.slice(offset - n, offset) - } +function isOutput(out: Output | BlankOutput): out is Output { + return (out).value !== undefined +} - function readUInt32 () { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i - } +export type BlankOutput = { + script: Buffer + valueBuffer: Buffer +} - function readInt32 () { - const i = buffer.readInt32LE(offset) - offset += 4 - return i - } +export type Output = { + script: Buffer + value: number +} - function readUInt64 () { - const i = bufferutils.readUInt64LE(buffer, offset) - offset += 8 - return i - } +export type Input = { + hash: Buffer + index: number + script: Buffer + sequence: number + witness: Array +} - function readVarInt () { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi +export class Transaction { + version: number + locktime: number + ins: Array + outs: Array + + static readonly DEFAULT_SEQUENCE = 0xffffffff + static readonly SIGHASH_ALL = 0x01 + static readonly SIGHASH_NONE = 0x02 + static readonly SIGHASH_SINGLE = 0x03 + static readonly SIGHASH_ANYONECANPAY = 0x80 + static readonly ADVANCED_TRANSACTION_MARKER = 0x00 + static readonly ADVANCED_TRANSACTION_FLAG = 0x01 + + constructor () { + this.version = 1 + this.locktime = 0 + this.ins = [] + this.outs = [] } + + static fromBuffer (buffer: Buffer, __noStrict: boolean): Transaction { + let offset: number = 0 - function readVarSlice () { - return readSlice(readVarInt()) - } + function readSlice (n: number): Buffer { + offset += n + return buffer.slice(offset - n, offset) + } - function readVector () { - const count = readVarInt() - const vector = [] - for (var i = 0; i < count; i++) vector.push(readVarSlice()) - return vector - } + function readUInt32 (): number { + const i = buffer.readUInt32LE(offset) + offset += 4 + return i + } - const tx = new Transaction() - tx.version = readInt32() + function readInt32 (): number { + const i = buffer.readInt32LE(offset) + offset += 4 + return i + } - const marker = buffer.readUInt8(offset) - const flag = buffer.readUInt8(offset + 1) + function readUInt64 (): number { + const i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i + } - let hasWitnesses = false - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && + function readVarInt (): number { + const vi = varuint.decode(buffer, offset) + offset += varuint.decode.bytes + return vi + } + + function readVarSlice (): Buffer { + return readSlice(readVarInt()) + } + + function readVector (): Array { + const count = readVarInt() + const vector: Array = [] + for (var i = 0; i < count; i++) vector.push(readVarSlice()) + return vector + } + + const tx = new Transaction() + tx.version = readInt32() + + const marker = buffer.readUInt8(offset) + const flag = buffer.readUInt8(offset + 1) + + let hasWitnesses = false + if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - offset += 2 - hasWitnesses = true - } + offset += 2 + hasWitnesses = true + } - const vinLen = readVarInt() - for (var i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), - witness: EMPTY_WITNESS - }) - } + const vinLen = readVarInt() + for (var i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readVarSlice(), + sequence: readUInt32(), + witness: EMPTY_WITNESS + }) + } - const voutLen = readVarInt() - for (i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: readUInt64(), - script: readVarSlice() - }) - } + const voutLen = readVarInt() + for (i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readVarSlice() + }) + } - if (hasWitnesses) { - for (i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector() + if (hasWitnesses) { + for (i = 0; i < vinLen; ++i) { + tx.ins[i].witness = readVector() + } + + // was this pointless? + if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') } - // was this pointless? - if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') - } + tx.locktime = readUInt32() - tx.locktime = readUInt32() + if (__noStrict) return tx + if (offset !== buffer.length) throw new Error('Transaction has unexpected data') - if (__noStrict) return tx - if (offset !== buffer.length) throw new Error('Transaction has unexpected data') + return tx + } - return tx -} + static fromHex (hex: string): Transaction { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false) + } -Transaction.fromHex = function (hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), undefined) -} + static isCoinbaseHash (buffer: Buffer): boolean { + typeforce(types.Hash256bit, buffer) + for (var i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false + } + return true + } -Transaction.isCoinbaseHash = function (buffer) { - typeforce(types.Hash256bit, buffer) - for (var i = 0; i < 32; ++i) { - if (buffer[i] !== 0) return false + isCoinbase (): boolean { + return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) } - return true -} -Transaction.prototype.isCoinbase = function () { - return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) -} + addInput (hash: Buffer, index: number, sequence: number, scriptSig: Buffer): number { + typeforce(types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer) + ), arguments) -Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) { - typeforce(types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer) - ), arguments) + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE + } - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE + // Add the input and return the input's index + return (this.ins.push({ + hash: hash, + index: index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS + }) - 1) } - // Add the input and return the input's index - return (this.ins.push({ - hash: hash, - index: index, - script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, - witness: EMPTY_WITNESS - }) - 1) -} + addOutput (scriptPubKey: Buffer, value: number): number { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) -Transaction.prototype.addOutput = function (scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value: value + }) - 1) + } - // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value: value - }) - 1) -} + hasWitnesses (): boolean { + return this.ins.some((x) => { + return x.witness.length !== 0 + }) + } -Transaction.prototype.hasWitnesses = function () { - return this.ins.some(function (x) { - return x.witness.length !== 0 - }) -} + weight (): number { + const base = this.__byteLength(false) + const total = this.__byteLength(true) + return base * 3 + total + } -Transaction.prototype.weight = function () { - const base = this.__byteLength(false) - const total = this.__byteLength(true) - return base * 3 + total -} + virtualSize (): number { + return Math.ceil(this.weight() / 4) + } -Transaction.prototype.virtualSize = function () { - return Math.ceil(this.weight() / 4) -} + byteLength (): number { + return this.__byteLength(true) + } -Transaction.prototype.byteLength = function () { - return this.__byteLength(true) -} + __byteLength (__allowWitness: boolean): number { + const hasWitnesses = __allowWitness && this.hasWitnesses() + + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script) + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script) + }, 0) + + (hasWitnesses ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness) + }, 0) : 0) + ) + } -Transaction.prototype.__byteLength = function (__allowWitness) { - const hasWitnesses = __allowWitness && this.hasWitnesses() - - return ( - (hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) + - this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) + - (hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0) - ) -} + clone (): Transaction { + const newTx = new Transaction() + newTx.version = this.version + newTx.locktime = this.locktime + + newTx.ins = this.ins.map((txIn) => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness + } + }) -Transaction.prototype.clone = function () { - const newTx = new Transaction() - newTx.version = this.version - newTx.locktime = this.locktime + newTx.outs = this.outs.map((txOut) => { + return { + script: txOut.script, + value: (txOut).value + } + }) - newTx.ins = this.ins.map(function (txIn) { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness - } - }) + return newTx + } - newTx.outs = this.outs.map(function (txOut) { - return { - script: txOut.script, - value: txOut.value + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature (inIndex: number, prevOutScript: Buffer, hashType: number): Buffer { + typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) + + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE + + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { + return x !== opcodes.OP_CODESEPARATOR + })) + + const txTmp = this.clone() + + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = [] + + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) return + + input.sequence = 0 + }) + + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE + + // truncate outputs after + txTmp.outs.length = inIndex + 1 + + // "blank" outputs before + for (var i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT + } + + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) return + + input.sequence = 0 + }) } - }) - return newTx -} + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]] + txTmp.ins[0].script = ourScript -/** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ -Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach((input) => { + input.script = EMPTY_SCRIPT + }) + txTmp.ins[inIndex].script = ourScript + } - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) return ONE + // serialize and hash + const buffer: Buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) + buffer.writeInt32LE(hashType, buffer.length - 4) + txTmp.__toBuffer(buffer, 0, false) - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) { - return x !== opcodes.OP_CODESEPARATOR - })) + return bcrypto.hash256(buffer) + } - const txTmp = this.clone() + hashForWitnessV0 (inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer { + typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = [] + let tbuffer: Buffer = Buffer.from([]) + let toffset: number = 0 - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach(function (input, i) { - if (i === inIndex) return + function writeSlice (slice: Buffer): void { + toffset += slice.copy(tbuffer, toffset) + } - input.sequence = 0 - }) + function writeUInt32 (i: number): void { + toffset = tbuffer.writeUInt32LE(i, toffset) + } - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) return ONE + function writeUInt64 (i: number): void { + toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) + } - // truncate outputs after - txTmp.outs.length = inIndex + 1 + function writeVarInt (i: number): void { + varuint.encode(i, tbuffer, toffset) + toffset += varuint.encode.bytes + } - // "blank" outputs before - for (var i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT + function writeVarSlice (slice: Buffer): void { + writeVarInt(slice.length) + writeSlice(slice) } - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach(function (input, y) { - if (y === inIndex) return + let hashOutputs = ZERO + let hashPrevouts = ZERO + let hashSequence = ZERO - input.sequence = 0 - }) - } + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length) + toffset = 0 - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]] - txTmp.ins[0].script = ourScript + this.ins.forEach((txIn) => { + writeSlice(txIn.hash) + writeUInt32(txIn.index) + }) - // SIGHASH_ALL: only ignore input scripts - } else { - // "blank" others input scripts - txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT }) - txTmp.ins[inIndex].script = ourScript - } + hashPrevouts = bcrypto.hash256(tbuffer) + } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) - buffer.writeInt32LE(hashType, buffer.length - 4) - txTmp.__toBuffer(buffer, 0, false) + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length) + toffset = 0 - return bcrypto.hash256(buffer) -} + this.ins.forEach((txIn) => { + writeUInt32(txIn.sequence) + }) -Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) + hashSequence = bcrypto.hash256(tbuffer) + } - let tbuffer, toffset - function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) } - function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) } - function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) } - function writeVarInt (i) { - varuint.encode(i, tbuffer, toffset) - toffset += varuint.encode.bytes - } - function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } + if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script) + }, 0) - let hashOutputs = ZERO - let hashPrevouts = ZERO - let hashSequence = ZERO + tbuffer = Buffer.allocUnsafe(txOutsSize) + toffset = 0 - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length) - toffset = 0 + this.outs.forEach((out) => { + writeUInt64((out).value) + writeVarSlice(out.script) + }) - this.ins.forEach(function (txIn) { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - }) + hashOutputs = bcrypto.hash256(tbuffer) + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { + const output = this.outs[inIndex] - hashPrevouts = bcrypto.hash256(tbuffer) - } + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) + toffset = 0 + writeUInt64((output).value) + writeVarSlice(output.script) - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length) + hashOutputs = bcrypto.hash256(tbuffer) + } + + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) toffset = 0 - this.ins.forEach(function (txIn) { - writeUInt32(txIn.sequence) - }) + const input = this.ins[inIndex] + writeUInt32(this.version) + writeSlice(hashPrevouts) + writeSlice(hashSequence) + writeSlice(input.hash) + writeUInt32(input.index) + writeVarSlice(prevOutScript) + writeUInt64(value) + writeUInt32(input.sequence) + writeSlice(hashOutputs) + writeUInt32(this.locktime) + writeUInt32(hashType) + return bcrypto.hash256(tbuffer) + } - hashSequence = bcrypto.hash256(tbuffer) + getHash (forWitness: boolean): Buffer { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0) + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)) } - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - const txOutsSize = this.outs.reduce(function (sum, output) { - return sum + 8 + varSliceSize(output.script) - }, 0) + getId (): string { + // transaction hash's are displayed in reverse order + return Buffer.from(this.getHash(false).reverse()).toString('hex') + } - tbuffer = Buffer.allocUnsafe(txOutsSize) - toffset = 0 + toBuffer (buffer: Buffer | void, initialOffset: number | void): Buffer { + return this.__toBuffer(buffer, initialOffset, true) + } - this.outs.forEach(function (out) { - writeUInt64(out.value) - writeVarSlice(out.script) - }) + __toBuffer (buffer: Buffer | void, initialOffset: number | void, __allowWitness: boolean | void): Buffer { + if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength((__allowWitness))) - hashOutputs = bcrypto.hash256(tbuffer) - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { - const output = this.outs[inIndex] + let offset = initialOffset || 0 - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) - toffset = 0 - writeUInt64(output.value) - writeVarSlice(output.script) + function writeSlice (slice) { + offset += slice.copy(buffer, offset) + } - hashOutputs = bcrypto.hash256(tbuffer) - } + function writeUInt8 (i) { + offset = (buffer).writeUInt8(i, offset) + } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) - toffset = 0 - - const input = this.ins[inIndex] - writeUInt32(this.version) - writeSlice(hashPrevouts) - writeSlice(hashSequence) - writeSlice(input.hash) - writeUInt32(input.index) - writeVarSlice(prevOutScript) - writeUInt64(value) - writeUInt32(input.sequence) - writeSlice(hashOutputs) - writeUInt32(this.locktime) - writeUInt32(hashType) - return bcrypto.hash256(tbuffer) -} + function writeUInt32 (i) { + offset = (buffer).writeUInt32LE(i, offset) + } -Transaction.prototype.getHash = function () { - return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) -} + function writeInt32 (i) { + offset = (buffer).writeInt32LE(i, offset) + } -Transaction.prototype.getId = function () { - // transaction hash's are displayed in reverse order - return this.getHash().reverse().toString('hex') -} + function writeUInt64 (i) { + offset = bufferutils.writeUInt64LE(buffer, i, offset) + } -Transaction.prototype.toBuffer = function (buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true) -} + function writeVarInt (i) { + varuint.encode(i, buffer, offset) + offset += varuint.encode.bytes + } -Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) { - if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)) - - let offset = initialOffset || 0 - function writeSlice (slice) { offset += slice.copy(buffer, offset) } - function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) } - function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) } - function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) } - function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } - function writeVarInt (i) { - varuint.encode(i, buffer, offset) - offset += varuint.encode.bytes - } - function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } - function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) } + function writeVarSlice (slice) { + writeVarInt(slice.length) + writeSlice(slice) + } - writeInt32(this.version) + function writeVector (vector) { + writeVarInt(vector.length) + vector.forEach(writeVarSlice) + } - const hasWitnesses = __allowWitness && this.hasWitnesses() + writeInt32(this.version) - if (hasWitnesses) { - writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) - writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) - } + const hasWitnesses = __allowWitness && this.hasWitnesses() - writeVarInt(this.ins.length) + if (hasWitnesses) { + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) + } - this.ins.forEach(function (txIn) { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - writeVarSlice(txIn.script) - writeUInt32(txIn.sequence) - }) + writeVarInt(this.ins.length) - writeVarInt(this.outs.length) - this.outs.forEach(function (txOut) { - if (!txOut.valueBuffer) { - writeUInt64(txOut.value) - } else { - writeSlice(txOut.valueBuffer) - } + this.ins.forEach((txIn) => { + writeSlice(txIn.hash) + writeUInt32(txIn.index) + writeVarSlice(txIn.script) + writeUInt32(txIn.sequence) + }) - writeVarSlice(txOut.script) - }) + writeVarInt(this.outs.length) + this.outs.forEach((txOut) => { + if (isOutput(txOut)) { + writeUInt64(txOut.value) + } else { + writeSlice(txOut.valueBuffer) + } - if (hasWitnesses) { - this.ins.forEach(function (input) { - writeVector(input.witness) + writeVarSlice(txOut.script) }) - } - writeUInt32(this.locktime) + if (hasWitnesses) { + this.ins.forEach((input) => { + writeVector(input.witness) + }) + } - // avoid slicing unless necessary - if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) - return buffer -} + writeUInt32(this.locktime) -Transaction.prototype.toHex = function () { - return this.toBuffer().toString('hex') -} + // avoid slicing unless necessary + if (initialOffset !== undefined) return buffer.slice((initialOffset), offset) + return buffer + } -Transaction.prototype.setInputScript = function (index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments) + toHex () { + return this.toBuffer(undefined, undefined).toString('hex') + } - this.ins[index].script = scriptSig -} + setInputScript (index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments) -Transaction.prototype.setWitness = function (index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments) + this.ins[index].script = scriptSig + } - this.ins[index].witness = witness -} + setWitness (index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments) -module.exports = Transaction -export {} + this.ins[index].witness = witness + } +} diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index 56368bf..83fbe2b 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -1,3 +1,5 @@ +import { Transaction, Output } from './transaction' + const Buffer = require('safe-buffer').Buffer const baddress = require('./address') const bcrypto = require('./crypto') @@ -11,7 +13,6 @@ const classify = require('./classify') const SCRIPT_TYPES = classify.types const ECPair = require('./ecpair') -const Transaction = require('./transaction') function expandInput (scriptSig, witnessStack, type, scriptPubKey) { if (scriptSig.length === 0 && witnessStack.length === 0) return {} @@ -517,9 +518,9 @@ TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOu } else if (txHash instanceof Transaction) { const txOut = txHash.outs[vout] prevOutScript = txOut.script - value = txOut.value + value = (txOut).value - txHash = txHash.getHash() + txHash = txHash.getHash(false) } return this.__addInputUnsafe(txHash, vout, { diff --git a/test/block.js b/test/block.js index 07d0741..76b043d 100644 --- a/test/block.js +++ b/test/block.js @@ -32,6 +32,9 @@ describe('Block', function () { assert.strictEqual(block.version, f.version) assert.strictEqual(block.prevHash.toString('hex'), f.prevHash) assert.strictEqual(block.merkleRoot.toString('hex'), f.merkleRoot) + if (block.witnessCommit) { + assert.strictEqual(block.witnessCommit.toString('hex'), f.witnessCommit) + } assert.strictEqual(block.timestamp, f.timestamp) assert.strictEqual(block.bits, f.bits) assert.strictEqual(block.nonce, f.nonce) @@ -113,6 +116,12 @@ describe('Block', function () { it('returns ' + f.merkleRoot + ' for ' + f.id, function () { assert.strictEqual(Block.calculateMerkleRoot(block.transactions).toString('hex'), f.merkleRoot) }) + + if (f.witnessCommit) { + it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, function () { + assert.strictEqual(Block.calculateMerkleRoot(block.transactions, true).toString('hex'), f.witnessCommit) + }) + } }) }) @@ -129,6 +138,12 @@ describe('Block', function () { it('returns ' + f.valid + ' for ' + f.id, function () { assert.strictEqual(block.checkMerkleRoot(), true) }) + + if (f.witnessCommit) { + it('validates witness commit for ' + f.id, function () { + assert.strictEqual(block.checkWitnessCommit(), true) + }) + } }) }) diff --git a/test/fixtures/block.json b/test/fixtures/block.json index b4a1cfe..c60685e 100644 --- a/test/fixtures/block.json +++ b/test/fixtures/block.json @@ -119,6 +119,21 @@ "timestamp": 1231006505, "valid": true, "version": 1 + }, + { + "description": "Block with witness commit", + "bits": 388503969, + "hash": "ec61d8d62a4945034a1df40dd3dfda364221c0562c3a14000000000000000000", + "height": 542213, + "hex": "000000208980ebb11236bacc66c447d5ad961bc546c0f9cc385a08000000000000000000135e9b653aee9a70028aff2db53d4f43f4484ad52558c3ae300410b79cb6a864df50a35ba11928171396e30104010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff5003054608174d696e656420627920416e74506f6f6c393b205ba350dffabe6d6d3a3e92d9efff857664de632e89fa3182f1e793d00be2e71a117b273145945a810400000000000000db250000acba0500ffffffff028a8f814a000000001976a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac0000000000000000266a24aa21a9ed4a657fcaa2149342376247e2e283a55a6b92dcc35d4d89e4ac7b74488cb63be201200000000000000000000000000000000000000000000000000000000000000000000000000100000001b898273f98d49399ecb5194ffdb1ed15c2fb37cf6d7696b4389bc7d1b76b63db010000006b483045022100e2e9bc1f6bae2deed086e935bb49fd6ac1e13dc3a44c36cd8b9a6f4257efb70d022076537c7021f12d761e1202796029f13798503bc22ab8c2ee8cb98207cbfeb414012102071c2c88e4560b47a03c033c736149a2ddd6071aea54ab85c5169cee156712f8ffffffff02b0710b00000000001976a914849a95fc65eeaa2ac47b6b6fc1f1883edb2c6c9788ace6b62501000000001976a9142964198f7ae9f7b920a2ab7c0b96b90e4ec9b14d88ac000000000100000000010152405e2660055b3540f63424a1b0b3b7bb9bbef10ceec970cd18f6f86f84a7880000000017160014dde2f1a9a4bfda011ba9ec4062990c7e1a531585ffffffff0266d418000000000017a914adc5ec550548f087371e645047170864d5fbdc03877e0400000000000016001441f6746110cc0fec102e83053d4c0ae56fab1bdd02483045022100f93bd5d3529418f60dddd477f169c32ea5ab340c99573438ee7c40d705db9ba20220323f1b4d8840098b1271c95365cdc7e8f81d0bf1fcc568c68fc7de8b871b4bee012103211d047d92547bca4aa116bc51ec4b09188e5991f69f0432fe1b5dfd8947859700000000010000000ac1a19854e5b92792ae96d08eb9f7fc016fb57c51a9047161c342e6b8de8ce721000000006b483045022100fa00a6651015ac807b03d8d54559831db40d80329f46a886b93ca6b3996daf9b02201d0fafccc88c4654a9c3d205ef0828e32376ecb42f79587615203f23fc8f2d42012102a2cda42f6954605e40cbc5601f65673621c057f8c12f16149fbbf632e8be8ed8ffffffffda16ff4a7324f78f16d5e5d4a740168de9df426cf53df569c9a33d1b94e2c25f000000006a4730440220167b4777a23db304f50ac75febfae5db0b1578c90d85769bc76e0f5458484319022023f763e95ea7771c15ea0df91c17519014b2223cd726a3b0a8b1a6f67f99b2bf012103b9492a823f03b70a1750e0fac44f58f5c81e09f4c18d0b28755b44c911ffab5ffffffffff1533f2ea34b859d2be05bbb6859d6105ad4389c911545487187437acae21b70000000006b483045022100be0b8dc174f4136e3fb4f3ccf1a2be67a44d2086179c5726c61a1af010d5232f02205c0fb4cdd7c9cb8698ceed05e688e10a0cbdd0ee5db1a0a2ef92f322e1a60e9f0121020b9f404317cc6ab5a699f607a9bb0acd0bf5588777672f8f7f4c1a13304e9f76ffffffff1395191837aa5b1cfa4cc2a79d6d6bda7d198e8a795a0f7a85f556c446119572000000006b483045022100ef3c61b5ba155b94fd02a96bf788e9a9be2de0ee53e3fe1fa6c24dd9d9aaee12022044c07be54a9c59fed96dfb778da0079f6753ab634d1920bf0fac25ebf7ac49d0012103f93e29be8b393773228f704151964662a91df4c1a3e15364e4cfb38a8cacbda9ffffffff55120f684d5fbb845fd0198cd734e46fc29f40dc8f906bf36743d7f740f5fd7c000000006a4730440220421aef290bbd39a18d1281ecfbb420b43daf2cc1c315b6bb44c895f88cb3cfcc022007a512c65b7768b1505f789b6d78479063d04ffb243072f2061eeb66fb1ade81012102712eea19c72fd644b2698c5480ebe77ce6face0bed64238a34a32085567f2f8efffffffff3553d19ce3156464e9cfa06a5260f9d9d01b16ccad6e2ebaab233ba10472ba6000000006b483045022100a29aea775d2c46028f40dceb1707b23e720bb314cef455854313569200c83162022009d0cdcef2e1f0a9217794991fa838fe6ce2bdc6e3c04ad490343c7e4a0ee7d3012102ed59ec6d98f9c2a4dd1324d46d74c56ff7e15935925f69799e547969a523ea98ffffffff530ab6d95f0d83669bfb12cbe983febe6ca638255139ce2ba0e35887f2fe3db6000000006b483045022100fad9f10989ab4ab019da4f6e430f9fe9ebe76941a9200d7346447358e93b1dce0220756c864b029a64ed9d6eedc13cf8b7d602572fcd7a3d3cb528350bb032d7e3ec012102e3e0c78d034627b1616cf196aa69bfaf20009ba9ebf09cf069453cc0423239e2ffffffff4b8e70824941d965df99703cacadfabcf79bc040029e528ff931e9ba4a7ee4d8000000006b48304502210095f37fb2700c9f96d5e5c02d4b043a7cd804f79dd071d8b221b7ae781f0f5b4e02200ae3135b8bebf813449956ae19e7c02db5eff2472da023afa8b8d4e9baba0cdd01210226cc53dfc0a41cc0cf7117dfd406db2b87161e89e2bab9908a2382173fc6dbe1ffffffff5262129e9881722b217f7e4882ed2b83ee53d9e23b9bc647494c9487ae9fabdf000000006a473044022032361f724fe006079cf37b3df61cb6c51cb0c5fd77f29b61a318134ca4948d0e02202fbe6d484a78730899230244f3662fd5578b87e9eaaccdf9bf8f05d23917de8301210254e84223b3d7f7cfd14315be8fa0c7d7eb1a1a34a672f08e2b8ec134472a66d4ffffffff067040e03288282ebe5db7b705130849c9984458b13ea7ca3c755f07b9d1b9f4000000006b483045022100b78b9c24f5f3e950aba637b827d5b11615c17ae2f43105941d172cc4a8b73c80022064998c17becd06abbcfde47c91b9d87da5ac67873ed9a412010b08b954e0b5cd01210329a0acc2b0d60dd243eef46073a672ed0caf467c92f63ef7293f2036a3851a1effffffff02027f0000000000001976a914c6a396ae979670eeaa6929df3dd1c2d8fba31c3d88ac85a19b020000000017a914409dbd0e9a1ab27853186367130e6aab2509e47f8700000000", + "id": "000000000000000000143a2c56c0214236dadfd30df41d4a0345492ad6d861ec", + "merkleRoot": "135e9b653aee9a70028aff2db53d4f43f4484ad52558c3ae300410b79cb6a864", + "witnessCommit": "4a657fcaa2149342376247e2e283a55a6b92dcc35d4d89e4ac7b74488cb63be2", + "nonce": 31692307, + "prevHash": "8980ebb11236bacc66c447d5ad961bc546c0f9cc385a08000000000000000000", + "timestamp": 1537429727, + "valid": true, + "version": 536870912 } ], "invalid": [ diff --git a/test/transaction.js b/test/transaction.js index f315a7d..74afc8f 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -2,7 +2,7 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const bscript = require('../dist/src/script') const fixtures = require('./fixtures/transaction') -const Transaction = require('../dist/src/transaction') +const Transaction = require('..').Transaction describe('Transaction', function () { function fromRaw (raw, noWitness) { diff --git a/test/transaction_builder.js b/test/transaction_builder.js index a4b309a..c416846 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -5,7 +5,7 @@ const bscript = require('../dist/src/script') const payments = require('../dist/src/payments') const ECPair = require('../dist/src/ecpair') -const Transaction = require('../dist/src/transaction') +const Transaction = require('..').Transaction const TransactionBuilder = require('../dist/src/transaction_builder') const NETWORKS = require('../dist/src/networks') From 58a6b0e54532036bd5a9f7ea1bbf5dbddf0c78fd Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 10:35:28 +0900 Subject: [PATCH 065/183] Convert ECPair --- src/ecpair.ts | 80 +++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/src/ecpair.ts b/src/ecpair.ts index 0c9fd83..15b3d0c 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -1,51 +1,62 @@ +import { Network } from './networks' +import * as NETWORKS from './networks' const ecc = require('tiny-secp256k1') const randomBytes = require('randombytes') const typeforce = require('typeforce') const types = require('./types') const wif = require('wif') -const NETWORKS = require('./networks') const isOptions = typeforce.maybe(typeforce.compile({ compressed: types.maybe(types.Boolean), network: types.maybe(types.Network) })) -function ECPair (d, Q, options) { - options = options || {} - - this.compressed = options.compressed === undefined ? true : options.compressed - this.network = options.network || NETWORKS.bitcoin - - this.__d = d || null - this.__Q = null - if (Q) this.__Q = ecc.pointCompress(Q, this.compressed) +export interface ECPairOptions { + compressed?: boolean + network?: Network + rng?(Buffer): Buffer } -Object.defineProperty(ECPair.prototype, 'privateKey', { - enumerable: false, - get: function () { return this.__d } -}) +class ECPair { + compressed: boolean + network: Network + private __d: Buffer + private __Q: Buffer + constructor (d: Buffer | void, Q: Buffer | void, options: ECPairOptions) { + if (options === undefined) options = {} + this.compressed = options.compressed === undefined ? true : options.compressed + this.network = options.network || NETWORKS.bitcoin + + this.__d = d || null + this.__Q = null + if (Q) this.__Q = ecc.pointCompress(Q, this.compressed) + } -Object.defineProperty(ECPair.prototype, 'publicKey', { get: function () { - if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed) - return this.__Q -}}) + get privateKey (): Buffer { + return this.__d + } -ECPair.prototype.toWIF = function () { - if (!this.__d) throw new Error('Missing private key') - return wif.encode(this.network.wif, this.__d, this.compressed) -} + get publicKey (): Buffer { + if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed) + return this.__Q + } -ECPair.prototype.sign = function (hash) { - if (!this.__d) throw new Error('Missing private key') - return ecc.sign(hash, this.__d) -} + toWIF (): string { + if (!this.__d) throw new Error('Missing private key') + return wif.encode(this.network.wif, this.__d, this.compressed) + } -ECPair.prototype.verify = function (hash, signature) { - return ecc.verify(hash, this.publicKey, signature) + sign (hash: Buffer): Buffer { + if (!this.__d) throw new Error('Missing private key') + return ecc.sign(hash, this.__d) + } + + verify (hash: Buffer, signature: Buffer): Buffer { + return ecc.verify(hash, this.publicKey, signature) + } } -function fromPrivateKey (buffer, options) { +function fromPrivateKey (buffer: Buffer, options: ECPairOptions): ECPair { typeforce(types.Buffer256bit, buffer) if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)') typeforce(isOptions, options) @@ -53,13 +64,13 @@ function fromPrivateKey (buffer, options) { return new ECPair(buffer, null, options) } -function fromPublicKey (buffer, options) { +function fromPublicKey (buffer, options): ECPair { typeforce(ecc.isPoint, buffer) typeforce(isOptions, options) return new ECPair(null, buffer, options) } -function fromWIF (string, network) { +function fromWIF (string, network): ECPair { const decoded = wif.decode(string) const version = decoded.version @@ -84,9 +95,9 @@ function fromWIF (string, network) { }) } -function makeRandom (options) { +function makeRandom (options: ECPairOptions): ECPair { typeforce(isOptions, options) - options = options || {} + if (options === undefined) options = {} const rng = options.rng || randomBytes let d @@ -98,10 +109,9 @@ function makeRandom (options) { return fromPrivateKey(d, options) } -module.exports = { +export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF } -export {} From fce08352f57d23150da5abead1c50261e760a60c Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 11:56:03 +0900 Subject: [PATCH 066/183] Add TransactionBuilder --- src/ecpair.ts | 15 +- src/index.ts | 2 +- src/transaction_builder.ts | 724 +++++++++++++++++++----------------- test/transaction_builder.js | 2 +- 4 files changed, 395 insertions(+), 348 deletions(-) diff --git a/src/ecpair.ts b/src/ecpair.ts index 15b3d0c..eceb2a1 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -11,13 +11,24 @@ const isOptions = typeforce.maybe(typeforce.compile({ network: types.maybe(types.Network) })) -export interface ECPairOptions { +interface ECPairOptions { compressed?: boolean network?: Network rng?(Buffer): Buffer } -class ECPair { +export interface ECPairInterface { + compressed: boolean + network: Network + privateKey: Buffer + publicKey: Buffer + toWIF(): string + sign(hash: Buffer): Buffer + verify(hash: Buffer, signature: Buffer): Buffer + getPublicKey?(): Buffer +} + +class ECPair implements ECPairInterface { compressed: boolean network: Network private __d: Buffer diff --git a/src/index.ts b/src/index.ts index 389e2b1..8019cb7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ const opcodes = require('bitcoin-ops') import { Block } from './block' import * as ECPair from './ecpair' import { Transaction } from './transaction' -import * as TransactionBuilder from './transaction_builder' +import { TransactionBuilder } from './transaction_builder' import * as address from './address' import * as bip32 from 'bip32' import * as crypto from './crypto' diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index 83fbe2b..01717ab 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -1,10 +1,11 @@ +import { Network } from './networks' +import * as networks from './networks' import { Transaction, Output } from './transaction' - +import { ECPairInterface } from './ecpair' const Buffer = require('safe-buffer').Buffer const baddress = require('./address') const bcrypto = require('./crypto') const bscript = require('./script') -const networks = require('./networks') const ops = require('bitcoin-ops') const payments = require('./payments') const typeforce = require('typeforce') @@ -14,7 +15,370 @@ const SCRIPT_TYPES = classify.types const ECPair = require('./ecpair') -function expandInput (scriptSig, witnessStack, type, scriptPubKey) { +interface TxbInput { + value?: number + hasWitness?: boolean + signScript?: Buffer + signType?: string + prevOutScript?: Buffer + redeemScript?: Buffer + redeemScriptType?: string + prevOutType?: string + pubkeys?: Array + signatures?: Array + witness?: Array + witnessScript?: Buffer + witnessScriptType?: string + script?: Buffer + sequence?: number + scriptSig?: Buffer + maxSignatures?: number +} + +interface TxbOutput { + type: string + pubkeys?: Array + signatures?: Array + maxSignatures?: number +} + +function txIsString(tx: Buffer | string | Transaction): tx is string { + return typeof (tx) === 'string' || tx instanceof String +} + +function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { + return (tx) instanceof Transaction +} + +export class TransactionBuilder { + network: Network + maximumFeeRate: number + private __prevTxSet: Object + private __inputs: Array + private __tx: Transaction + + constructor (network: Network, maximumFeeRate?: number) { + this.__prevTxSet = {} + this.network = network || networks.bitcoin + + // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) + this.maximumFeeRate = maximumFeeRate || 2500 + + this.__inputs = [] + this.__tx = new Transaction() + this.__tx.version = 2 + } + + static fromTransaction (transaction: Transaction, network?: Network): TransactionBuilder { + const txb = new TransactionBuilder(network) + + // Copy transaction fields + txb.setVersion(transaction.version) + txb.setLockTime(transaction.locktime) + + // Copy outputs (done first to avoid signature invalidation) + transaction.outs.forEach(txOut => { + txb.addOutput(txOut.script, (txOut).value) + }) + + // Copy inputs + transaction.ins.forEach(txIn => { + txb.__addInputUnsafe(txIn.hash, txIn.index, { + sequence: txIn.sequence, + script: txIn.script, + witness: txIn.witness + }) + }) + + // fix some things not possible through the public API + txb.__inputs.forEach((input, i) => { + fixMultisigOrder(input, transaction, i) + }) + + return txb + } + + setLockTime (locktime: number): void { + typeforce(types.UInt32, locktime) + + // if any signatures exist, throw + if (this.__inputs.some(input => { + if (!input.signatures) return false + + return input.signatures.some(s => s !== undefined) + })) { + throw new Error('No, this would invalidate signatures') + } + + this.__tx.locktime = locktime + } + + setVersion (version: number): void { + typeforce(types.UInt32, version) + + // XXX: this might eventually become more complex depending on what the versions represent + this.__tx.version = version + } + + addInput (txHash: Buffer | string | Transaction, vout: number, sequence: number, prevOutScript: Buffer): number { + if (!this.__canModifyInputs()) { + throw new Error('No, this would invalidate signatures') + } + + let value: number + + // is it a hex string? + if (txIsString(txHash)) { + // transaction hashs's are displayed in reverse order, un-reverse it + txHash = Buffer.from(txHash, 'hex').reverse() + + // is it a Transaction object? + } else if (txIsTransaction(txHash)) { + const txOut = txHash.outs[vout] + prevOutScript = txOut.script + value = (txOut).value + + txHash = txHash.getHash(false) + } + + return this.__addInputUnsafe(txHash, vout, { + sequence: sequence, + prevOutScript: prevOutScript, + value: value + }) + } + + private __addInputUnsafe (txHash: Buffer, vout: number, options: TxbInput): number { + if (Transaction.isCoinbaseHash(txHash)) { + throw new Error('coinbase inputs not supported') + } + + const prevTxOut = txHash.toString('hex') + ':' + vout + if (this.__prevTxSet[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut) + + let input = {} + + // derive what we can from the scriptSig + if (options.script !== undefined) { + input = expandInput(options.script, options.witness || []) + } + + // if an input value was given, retain it + if (options.value !== undefined) { + input.value = options.value + } + + // derive what we can from the previous transactions output script + if (!input.prevOutScript && options.prevOutScript) { + let prevOutType + + if (!input.pubkeys && !input.signatures) { + const expanded = expandOutput(options.prevOutScript) + if (expanded.pubkeys) { + input.pubkeys = expanded.pubkeys + input.signatures = expanded.signatures + } + + prevOutType = expanded.type + } + + input.prevOutScript = options.prevOutScript + input.prevOutType = prevOutType || classify.output(options.prevOutScript) + } + + const vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig) + this.__inputs[vin] = input + this.__prevTxSet[prevTxOut] = true + return vin + } + + addOutput (scriptPubKey: string | Buffer, value): number { + if (!this.__canModifyOutputs()) { + throw new Error('No, this would invalidate signatures') + } + + // Attempt to get a script if it's a base58 or bech32 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network) + } + + return this.__tx.addOutput(scriptPubKey, value) + } + + build (): Transaction { + return this.__build(false) + } + + buildIncomplete (): Transaction { + return this.__build(true) + } + + private __build (allowIncomplete?: boolean): Transaction { + if (!allowIncomplete) { + if (!this.__tx.ins.length) throw new Error('Transaction has no inputs') + if (!this.__tx.outs.length) throw new Error('Transaction has no outputs') + } + + const tx = this.__tx.clone() + + // create script signatures from inputs + this.__inputs.forEach((input, i) => { + if (!input.prevOutType && !allowIncomplete) throw new Error('Transaction is not complete') + + const result = build(input.prevOutType, input, allowIncomplete) + if (!result) { + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) throw new Error('Unknown input type') + if (!allowIncomplete) throw new Error('Not enough information') + return + } + + tx.setInputScript(i, result.input) + tx.setWitness(i, result.witness) + }) + + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__overMaximumFees(tx.virtualSize())) { + throw new Error('Transaction has absurd fees') + } + } + + return tx + } + + sign (vin: number, keyPair: ECPairInterface, redeemScript: Buffer, hashType: number, witnessValue: number, witnessScript: Buffer) { + // TODO: remove keyPair.network matching in 4.0.0 + if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network') + if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin) + + hashType = hashType || Transaction.SIGHASH_ALL + if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs') + + const input = this.__inputs[vin] + + // if redeemScript was previously provided, enforce consistency + if (input.redeemScript !== undefined && + redeemScript && + !input.redeemScript.equals(redeemScript)) { + throw new Error('Inconsistent redeemScript') + } + + const ourPubKey = keyPair.publicKey || keyPair.getPublicKey() + if (!canSign(input)) { + if (witnessValue !== undefined) { + if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue') + typeforce(types.Satoshi, witnessValue) + input.value = witnessValue + } + + if (!canSign(input)) { + const prepared = prepareInput(input, ourPubKey, redeemScript, witnessValue, witnessScript) + + // updates inline + Object.assign(input, prepared) + } + + if (!canSign(input)) throw Error(input.prevOutType + ' not supported') + } + + // ready to sign + let signatureHash + if (input.hasWitness) { + signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) + } else { + signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType) + } + + // enforce in order signing of public keys + const signed = input.pubkeys.some((pubKey, i) => { + if (!ourPubKey.equals(pubKey)) return false + if (input.signatures[i]) throw new Error('Signature already exists') + + // TODO: add tests + if (ourPubKey.length !== 33 && input.hasWitness) { + throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH') + } + + const signature = keyPair.sign(signatureHash) + input.signatures[i] = bscript.signature.encode(signature, hashType) + return true + }) + + if (!signed) throw new Error('Key pair cannot sign for this input') + } + + private __canModifyInputs (): boolean { + return this.__inputs.every(input => { + if (!input.signatures) return true + + return input.signatures.every(signature => { + if (!signature) return true + const hashType = signatureHashType(signature) + + // if SIGHASH_ANYONECANPAY is set, signatures would not + // be invalidated by more inputs + return (hashType & Transaction.SIGHASH_ANYONECANPAY) !== 0 + }) + }) + } + + private __needsOutputs (signingHashType: number): boolean { + if (signingHashType === Transaction.SIGHASH_ALL) { + return this.__tx.outs.length === 0 + } + + // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs + // .build() will fail, but .buildIncomplete() is OK + return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { + if (!input.signatures) return false + + return input.signatures.some((signature) => { + if (!signature) return false // no signature, no issue + const hashType = signatureHashType(signature) + if (hashType & Transaction.SIGHASH_NONE) return false // SIGHASH_NONE doesn't care about outputs + return true // SIGHASH_* does care + }) + }) + } + + private __canModifyOutputs (): boolean { + const nInputs = this.__tx.ins.length + const nOutputs = this.__tx.outs.length + + return this.__inputs.every(input => { + if (input.signatures === undefined) return true + + return input.signatures.every(signature => { + if (!signature) return true + const hashType = signatureHashType(signature) + + const hashTypeMod = hashType & 0x1f + if (hashTypeMod === Transaction.SIGHASH_NONE) return true + if (hashTypeMod === Transaction.SIGHASH_SINGLE) { + // if SIGHASH_SINGLE is set, and nInputs > nOutputs + // some signatures would be invalidated by the addition + // of more outputs + return nInputs <= nOutputs + } + }) + }) + } + + private __overMaximumFees (bytes: number): boolean { + // not all inputs will have .value defined + const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0) + + // but all outputs do, and if we have any input value + // we can immediately determine if the outputs are too small + const outgoing = this.__tx.outs.reduce((a, x) => a + (x).value, 0) + const fee = incoming - outgoing + const feeRate = fee / bytes + + return feeRate > this.maximumFeeRate + } +} + +function expandInput (scriptSig: Buffer, witnessStack: Array, type?: string, scriptPubKey?: Buffer): TxbInput { if (scriptSig.length === 0 && witnessStack.length === 0) return {} if (!type) { let ssType = classify.input(scriptSig, true) @@ -103,7 +467,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { const outputType = classify.output(redeem.output) let expanded if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput(redeem.input, redeem.witness, outputType, undefined) + expanded = expandInput(redeem.input, redeem.witness, outputType) } else { expanded = expandInput(bscript.compile(redeem.witness), [], outputType, redeem.output) } @@ -127,18 +491,18 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) { } // could be done in expandInput, but requires the original Transaction for hashForSignature -function fixMultisigOrder (input, transaction, vin) { +function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: number): void { if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return if (input.pubkeys.length === input.signatures.length) return const unmatched = input.signatures.concat() - input.signatures = input.pubkeys.map(function (pubKey) { + input.signatures = input.pubkeys.map(pubKey => { const keyPair = ECPair.fromPublicKey(pubKey) let match // check for a signature - unmatched.some(function (signature, i) { + unmatched.some((signature, i) => { // skip if undefined || OP_0 if (!signature) return false @@ -160,7 +524,7 @@ function fixMultisigOrder (input, transaction, vin) { }) } -function expandOutput (script, ourPubKey) { +function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { typeforce(types.Buffer, script) const type = classify.output(script) @@ -218,7 +582,7 @@ function expandOutput (script, ourPubKey) { return { type } } -function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScript) { +function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, witnessValue: number, witnessScript: Buffer): TxbInput { if (redeemScript && witnessScript) { const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) const p2wshAlt = payments.p2wsh({ output: redeemScript }) @@ -231,7 +595,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri const expanded = expandOutput(p2wsh.redeem.output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') - if (input.signatures && input.signatures.some(x => x)) { + if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures } @@ -271,7 +635,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri const expanded = expandOutput(p2sh.redeem.output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')') - if (input.signatures && input.signatures.some(x => x)) { + if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures } @@ -307,7 +671,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri const expanded = expandOutput(p2wsh.redeem.output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') - if (input.signatures && input.signatures.some(x => x)) { + if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures } @@ -339,7 +703,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri const expanded = expandOutput(input.prevOutScript, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported (' + bscript.toASM(input.prevOutScript) + ')') - if (input.signatures && input.signatures.some(x => x)) { + if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures } @@ -376,7 +740,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri } } -function build (type, input, allowIncomplete) { +function build (type: string, input: TxbInput, allowIncomplete: boolean): any { //TODO payment type const pubkeys = input.pubkeys || [] let signatures = input.signatures || [] @@ -439,201 +803,7 @@ function build (type, input, allowIncomplete) { } } -function TransactionBuilder (network, maximumFeeRate) { - this.__prevTxSet = {} - this.network = network || networks.bitcoin - - // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500 - - this.__inputs = [] - this.__tx = new Transaction() - this.__tx.version = 2 -} - -TransactionBuilder.prototype.setLockTime = function (locktime) { - typeforce(types.UInt32, locktime) - - // if any signatures exist, throw - if (this.__inputs.some(function (input) { - if (!input.signatures) return false - - return input.signatures.some(function (s) { return s }) - })) { - throw new Error('No, this would invalidate signatures') - } - - this.__tx.locktime = locktime -} - -TransactionBuilder.prototype.setVersion = function (version) { - typeforce(types.UInt32, version) - - // XXX: this might eventually become more complex depending on what the versions represent - this.__tx.version = version -} - -TransactionBuilder.fromTransaction = function (transaction, network) { - const txb = new TransactionBuilder(network, undefined) - - // Copy transaction fields - txb.setVersion(transaction.version) - txb.setLockTime(transaction.locktime) - - // Copy outputs (done first to avoid signature invalidation) - transaction.outs.forEach(function (txOut) { - txb.addOutput(txOut.script, txOut.value) - }) - - // Copy inputs - transaction.ins.forEach(function (txIn) { - txb.__addInputUnsafe(txIn.hash, txIn.index, { - sequence: txIn.sequence, - script: txIn.script, - witness: txIn.witness - }) - }) - - // fix some things not possible through the public API - txb.__inputs.forEach(function (input, i) { - fixMultisigOrder(input, transaction, i) - }) - - return txb -} - -TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) { - if (!this.__canModifyInputs()) { - throw new Error('No, this would invalidate signatures') - } - - let value - - // is it a hex string? - if (typeof txHash === 'string') { - // transaction hashs's are displayed in reverse order, un-reverse it - txHash = Buffer.from(txHash, 'hex').reverse() - - // is it a Transaction object? - } else if (txHash instanceof Transaction) { - const txOut = txHash.outs[vout] - prevOutScript = txOut.script - value = (txOut).value - - txHash = txHash.getHash(false) - } - - return this.__addInputUnsafe(txHash, vout, { - sequence: sequence, - prevOutScript: prevOutScript, - value: value - }) -} - -TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) { - if (Transaction.isCoinbaseHash(txHash)) { - throw new Error('coinbase inputs not supported') - } - - const prevTxOut = txHash.toString('hex') + ':' + vout - if (this.__prevTxSet[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut) - - let input = { - value: undefined, - prevOutScript: undefined, - pubkeys: undefined, - signatures: undefined, - prevOutType: undefined, - } - - // derive what we can from the scriptSig - if (options.script !== undefined) { - input = expandInput(options.script, options.witness || [], undefined, undefined) - } - - // if an input value was given, retain it - if (options.value !== undefined) { - input.value = options.value - } - - // derive what we can from the previous transactions output script - if (!input.prevOutScript && options.prevOutScript) { - let prevOutType - - if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript, undefined) - if (expanded.pubkeys) { - input.pubkeys = expanded.pubkeys - input.signatures = expanded.signatures - } - - prevOutType = expanded.type - } - - input.prevOutScript = options.prevOutScript - input.prevOutType = prevOutType || classify.output(options.prevOutScript) - } - - const vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig) - this.__inputs[vin] = input - this.__prevTxSet[prevTxOut] = true - return vin -} - -TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { - if (!this.__canModifyOutputs()) { - throw new Error('No, this would invalidate signatures') - } - - // Attempt to get a script if it's a base58 or bech32 address string - if (typeof scriptPubKey === 'string') { - scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network) - } - - return this.__tx.addOutput(scriptPubKey, value) -} - -TransactionBuilder.prototype.build = function () { - return this.__build(false) -} -TransactionBuilder.prototype.buildIncomplete = function () { - return this.__build(true) -} - -TransactionBuilder.prototype.__build = function (allowIncomplete) { - if (!allowIncomplete) { - if (!this.__tx.ins.length) throw new Error('Transaction has no inputs') - if (!this.__tx.outs.length) throw new Error('Transaction has no outputs') - } - - const tx = this.__tx.clone() - - // create script signatures from inputs - this.__inputs.forEach(function (input, i) { - if (!input.prevOutType && !allowIncomplete) throw new Error('Transaction is not complete') - - const result = build(input.prevOutType, input, allowIncomplete) - if (!result) { - if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) throw new Error('Unknown input type') - if (!allowIncomplete) throw new Error('Not enough information') - return - } - - tx.setInputScript(i, result.input) - tx.setWitness(i, result.witness) - }) - - if (!allowIncomplete) { - // do not rely on this, its merely a last resort - if (this.__overMaximumFees(tx.virtualSize())) { - throw new Error('Transaction has absurd fees') - } - } - - return tx -} - -function canSign (input) { +function canSign (input: TxbInput): boolean { return input.signScript !== undefined && input.signType !== undefined && input.pubkeys !== undefined && @@ -646,140 +816,6 @@ function canSign (input) { ) } -TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { - // TODO: remove keyPair.network matching in 4.0.0 - if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network') - if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin) - - hashType = hashType || Transaction.SIGHASH_ALL - if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs') - - const input = this.__inputs[vin] - - // if redeemScript was previously provided, enforce consistency - if (input.redeemScript !== undefined && - redeemScript && - !input.redeemScript.equals(redeemScript)) { - throw new Error('Inconsistent redeemScript') - } - - const ourPubKey = keyPair.publicKey || keyPair.getPublicKey() - if (!canSign(input)) { - if (witnessValue !== undefined) { - if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue') - typeforce(types.Satoshi, witnessValue) - input.value = witnessValue - } - - if (!canSign(input)) { - const prepared = prepareInput(input, ourPubKey, redeemScript, witnessValue, witnessScript) - - // updates inline - Object.assign(input, prepared) - } - - if (!canSign(input)) throw Error(input.prevOutType + ' not supported') - } - - // ready to sign - let signatureHash - if (input.hasWitness) { - signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) - } else { - signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType) - } - - // enforce in order signing of public keys - const signed = input.pubkeys.some(function (pubKey, i) { - if (!ourPubKey.equals(pubKey)) return false - if (input.signatures[i]) throw new Error('Signature already exists') - - // TODO: add tests - if (ourPubKey.length !== 33 && input.hasWitness) { - throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH') - } - - const signature = keyPair.sign(signatureHash) - input.signatures[i] = bscript.signature.encode(signature, hashType) - return true - }) - - if (!signed) throw new Error('Key pair cannot sign for this input') -} - -function signatureHashType (buffer) { +function signatureHashType (buffer: Buffer): number { return buffer.readUInt8(buffer.length - 1) } - -TransactionBuilder.prototype.__canModifyInputs = function () { - return (this.__inputs || []).every(function (input) { - if (!input.signatures) return true - - return (input.signatures || []).every(function (signature) { - if (!signature) return true - const hashType = signatureHashType(signature) - - // if SIGHASH_ANYONECANPAY is set, signatures would not - // be invalidated by more inputs - return hashType & Transaction.SIGHASH_ANYONECANPAY - }) - }) -} - -TransactionBuilder.prototype.__needsOutputs = function (signingHashType) { - if (signingHashType === Transaction.SIGHASH_ALL) { - return this.__tx.outs.length === 0 - } - - // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs - // .build() will fail, but .buildIncomplete() is OK - return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { - if (!input.signatures) return false - - return input.signatures.some((signature) => { - if (!signature) return false // no signature, no issue - const hashType = signatureHashType(signature) - if (hashType & Transaction.SIGHASH_NONE) return false // SIGHASH_NONE doesn't care about outputs - return true // SIGHASH_* does care - }) - }) -} - -TransactionBuilder.prototype.__canModifyOutputs = function () { - const nInputs = this.__tx.ins.length - const nOutputs = this.__tx.outs.length - - return this.__inputs.every(function (input) { - if (input.signatures === undefined) return true - - return input.signatures.every(function (signature) { - if (!signature) return true - const hashType = signatureHashType(signature) - - const hashTypeMod = hashType & 0x1f - if (hashTypeMod === Transaction.SIGHASH_NONE) return true - if (hashTypeMod === Transaction.SIGHASH_SINGLE) { - // if SIGHASH_SINGLE is set, and nInputs > nOutputs - // some signatures would be invalidated by the addition - // of more outputs - return nInputs <= nOutputs - } - }) - }) -} - -TransactionBuilder.prototype.__overMaximumFees = function (bytes) { - // not all inputs will have .value defined - const incoming = this.__inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0) - - // but all outputs do, and if we have any input value - // we can immediately determine if the outputs are too small - const outgoing = this.__tx.outs.reduce(function (a, x) { return a + x.value }, 0) - const fee = incoming - outgoing - const feeRate = fee / bytes - - return feeRate > this.maximumFeeRate -} - -module.exports = TransactionBuilder -export {} diff --git a/test/transaction_builder.js b/test/transaction_builder.js index c416846..34d9270 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -6,7 +6,7 @@ const payments = require('../dist/src/payments') const ECPair = require('../dist/src/ecpair') const Transaction = require('..').Transaction -const TransactionBuilder = require('../dist/src/transaction_builder') +const TransactionBuilder = require('..').TransactionBuilder const NETWORKS = require('../dist/src/networks') const fixtures = require('./fixtures/transaction_builder') From 3b77caa4f16aba9a676abe5bad32c633333a0365 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 12:59:43 +0900 Subject: [PATCH 067/183] Fixed script, script number and signature --- src/script.ts | 74 ++++++++++++++++++++--------------------- src/script_number.ts | 10 ++---- src/script_signature.ts | 19 +++++------ 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/script.ts b/src/script.ts index 514e992..98b018a 100644 --- a/src/script.ts +++ b/src/script.ts @@ -10,37 +10,49 @@ const OPS = require('bitcoin-ops') const REVERSE_OPS = require('bitcoin-ops/map') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 -function isOPInt (value) { +function isOPInt (value:number): boolean { return types.Number(value) && ((value === OPS.OP_0) || (value >= OPS.OP_1 && value <= OPS.OP_16) || (value === OPS.OP_1NEGATE)) } -function isPushOnlyChunk (value) { - return types.Buffer(value) || isOPInt(value) +function isPushOnlyChunk (value: number | Buffer): boolean { + return types.Buffer(value) || isOPInt(value) } -function isPushOnly (value) { +export function isPushOnly (value: Array) { return types.Array(value) && value.every(isPushOnlyChunk) } -function asMinimalOP (buffer) { +function asMinimalOP (buffer: Buffer): number | void { if (buffer.length === 0) return OPS.OP_0 if (buffer.length !== 1) return if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0] if (buffer[0] === 0x81) return OPS.OP_1NEGATE } -function compile (chunks) { +function chunksIsBuffer(buf: Buffer | Array): buf is Buffer { + return Buffer.isBuffer(buf) +} + +function chunksIsArray(buf: Buffer | Array): buf is Array { + return types.Array(buf) +} + +function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer { + return Buffer.isBuffer(buf) +} + +export function compile (chunks: Buffer | Array): Buffer { // TODO: remove me - if (Buffer.isBuffer(chunks)) return chunks + if (chunksIsBuffer(chunks)) return chunks typeforce(types.Array, chunks) - const bufferSize = chunks.reduce(function (accum, chunk) { + const bufferSize = chunks.reduce(function (accum: number, chunk) { // data chunk - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { return accum + 1 @@ -58,7 +70,7 @@ function compile (chunks) { chunks.forEach(function (chunk) { // data chunk - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk) if (opcode !== undefined) { @@ -82,9 +94,9 @@ function compile (chunks) { return buffer } -function decompile (buffer) { +export function decompile (buffer: Buffer | Array): Array { // TODO: remove me - if (types.Array(buffer)) return buffer + if (chunksIsArray(buffer)) return buffer typeforce(types.Buffer, buffer) @@ -127,17 +139,17 @@ function decompile (buffer) { return chunks } -function toASM (chunks) { - if (Buffer.isBuffer(chunks)) { +export function toASM (chunks: Buffer | Array): string { + if (chunksIsBuffer(chunks)) { chunks = decompile(chunks) } return chunks.map(function (chunk) { // data? - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk) if (op === undefined) return chunk.toString('hex') - chunk = op + chunk = op } // opcode! @@ -145,7 +157,7 @@ function toASM (chunks) { }).join(' ') } -function fromASM (asm) { +export function fromASM (asm: string): Buffer { typeforce(types.String, asm) return compile(asm.split(' ').map(function (chunkStr) { @@ -158,49 +170,35 @@ function fromASM (asm) { })) } -function toStack (chunks) { +export function toStack (chunks: Buffer | Array): Array { chunks = decompile(chunks) typeforce(isPushOnly, chunks) return chunks.map(function (op) { - if (Buffer.isBuffer(op)) return op + if (singleChunkIsBuffer(op)) return op if (op === OPS.OP_0) return Buffer.allocUnsafe(0) return scriptNumber.encode(op - OP_INT_BASE) }) } -function isCanonicalPubKey (buffer) { +export function isCanonicalPubKey (buffer: Buffer): boolean { return ecc.isPoint(buffer) } -function isDefinedHashType (hashType) { +export function isDefinedHashType (hashType: number): boolean { const hashTypeMod = hashType & ~0x80 // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04 } -function isCanonicalScriptSignature (buffer) { +export function isCanonicalScriptSignature (buffer: Buffer): boolean { if (!Buffer.isBuffer(buffer)) return false if (!isDefinedHashType(buffer[buffer.length - 1])) return false return bip66.check(buffer.slice(0, -1)) } -module.exports = { - compile: compile, - decompile: decompile, - fromASM: fromASM, - toASM: toASM, - toStack: toStack, - - number: require('./script_number'), - signature: require('./script_signature'), - - isCanonicalPubKey: isCanonicalPubKey, - isCanonicalScriptSignature: isCanonicalScriptSignature, - isPushOnly: isPushOnly, - isDefinedHashType: isDefinedHashType -} -export {} +export const number = require('./script_number') +export const signature = require('./script_signature') diff --git a/src/script_number.ts b/src/script_number.ts index 4df4704..8178c95 100644 --- a/src/script_number.ts +++ b/src/script_number.ts @@ -1,6 +1,6 @@ const Buffer = require('safe-buffer').Buffer -function decode (buffer, maxLength, minimal) { +export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): number { maxLength = maxLength || 4 minimal = minimal === undefined ? true : minimal @@ -41,7 +41,7 @@ function scriptNumSize (i) { : 0 } -function encode (number) { +export function encode (number: number): Buffer { let value = Math.abs(number) const size = scriptNumSize(value) const buffer = Buffer.allocUnsafe(size) @@ -60,9 +60,3 @@ function encode (number) { return buffer } - -module.exports = { - decode: decode, - encode: encode -} -export {} diff --git a/src/script_signature.ts b/src/script_signature.ts index b1f933a..fefd09d 100644 --- a/src/script_signature.ts +++ b/src/script_signature.ts @@ -4,7 +4,7 @@ const typeforce = require('typeforce') const types = require('./types') const ZERO = Buffer.alloc(1, 0) -function toDER (x) { +function toDER (x: Buffer): Buffer { let i = 0 while (x[i] === 0) ++i if (i === x.length) return ZERO @@ -13,7 +13,7 @@ function toDER (x) { return x } -function fromDER (x) { +function fromDER (x: Buffer): Buffer { if (x[0] === 0x00) x = x.slice(1) const buffer = Buffer.alloc(32, 0) const bstart = Math.max(0, 32 - x.length) @@ -21,8 +21,13 @@ function fromDER (x) { return buffer } +interface ScriptSignature { + signature: Buffer + hashType: number +} + // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) -function decode (buffer) { +export function decode (buffer: Buffer): ScriptSignature { const hashType = buffer.readUInt8(buffer.length - 1) const hashTypeMod = hashType & ~0x80 if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) @@ -37,7 +42,7 @@ function decode (buffer) { } } -function encode (signature, hashType) { +export function encode (signature: Buffer, hashType: number): Buffer { typeforce({ signature: types.BufferN(64), hashType: types.UInt8 @@ -57,9 +62,3 @@ function encode (signature, hashType) { hashTypeBuffer ]) } - -module.exports = { - decode: decode, - encode: encode -} -export {} From 2f32ea6bc97e460d635d10c57060e1c1b16c0495 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 13:18:42 +0900 Subject: [PATCH 068/183] OP_RETURN and Multisig templates --- package.json | 2 +- src/templates/multisig/index.ts | 10 ++++++---- src/templates/multisig/input.ts | 9 +++------ src/templates/multisig/output.ts | 15 ++++++--------- src/templates/nulldata.ts | 5 ++--- src/types.ts | 1 + 6 files changed, 19 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index e704249..777a210 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha", + "coverage": "nyc --check-coverage --branches 85 --functions 90 mocha", "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", diff --git a/src/templates/multisig/index.ts b/src/templates/multisig/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/multisig/index.ts +++ b/src/templates/multisig/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/multisig/input.ts b/src/templates/multisig/input.ts index d395108..864c793 100644 --- a/src/templates/multisig/input.ts +++ b/src/templates/multisig/input.ts @@ -1,13 +1,13 @@ // OP_0 [signatures ...] -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') function partialSignature (value) { return value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) } -function check (script, allowIncomplete) { +export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { const chunks = bscript.decompile(script) if (chunks.length < 2) return false if (chunks[0] !== OPS.OP_0) return false @@ -16,9 +16,6 @@ function check (script, allowIncomplete) { return chunks.slice(1).every(partialSignature) } - return chunks.slice(1).every(bscript.isCanonicalScriptSignature) + return (>chunks.slice(1)).every(bscript.isCanonicalScriptSignature) } check.toJSON = function () { return 'multisig input' } - -module.exports = { check } -export {} diff --git a/src/templates/multisig/output.ts b/src/templates/multisig/output.ts index 5ff18f1..50c701e 100644 --- a/src/templates/multisig/output.ts +++ b/src/templates/multisig/output.ts @@ -1,19 +1,19 @@ // m [pubKeys ...] n OP_CHECKMULTISIG -const bscript = require('../../script') -const types = require('../../types') +import * as bscript from '../../script' +import * as types from '../../types' const OPS = require('bitcoin-ops') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 -function check (script, allowIncomplete) { +export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { const chunks = bscript.decompile(script) if (chunks.length < 4) return false if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false if (!types.Number(chunks[0])) return false if (!types.Number(chunks[chunks.length - 2])) return false - const m = chunks[0] - OP_INT_BASE - const n = chunks[chunks.length - 2] - OP_INT_BASE + const m = chunks[0] - OP_INT_BASE + const n = chunks[chunks.length - 2] - OP_INT_BASE if (m <= 0) return false if (n > 16) return false @@ -21,10 +21,7 @@ function check (script, allowIncomplete) { if (n !== chunks.length - 3) return false if (allowIncomplete) return true - const keys = chunks.slice(1, -2) + const keys = > chunks.slice(1, -2) return keys.every(bscript.isCanonicalPubKey) } check.toJSON = function () { return 'multi-sig output' } - -module.exports = { check } -export {} diff --git a/src/templates/nulldata.ts b/src/templates/nulldata.ts index 48b0365..91c1713 100644 --- a/src/templates/nulldata.ts +++ b/src/templates/nulldata.ts @@ -1,9 +1,8 @@ // OP_RETURN {data} - -const bscript = require('../script') +import * as bscript from '../script' const OPS = require('bitcoin-ops') -export function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length > 1 && diff --git a/src/types.ts b/src/types.ts index 57431ca..790b95e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,3 +34,4 @@ export const Buffer256bit = typeforce.BufferN(32) export const Hash160bit = typeforce.BufferN(20) export const Hash256bit = typeforce.BufferN(32) export * from 'typeforce' +export { Number } from 'typeforce' From 9da1c95f890ef7dc7142a2be338d487149d93886 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 13:23:23 +0900 Subject: [PATCH 069/183] Add P2PK templates --- src/templates/multisig/input.ts | 4 ++-- src/templates/pubkey/index.ts | 10 ++++++---- src/templates/pubkey/input.ts | 11 +++-------- src/templates/pubkey/output.ts | 9 +++------ 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/templates/multisig/input.ts b/src/templates/multisig/input.ts index 864c793..2060242 100644 --- a/src/templates/multisig/input.ts +++ b/src/templates/multisig/input.ts @@ -3,8 +3,8 @@ import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function partialSignature (value) { - return value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) +function partialSignature (value: number | Buffer): boolean { + return value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) } export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { diff --git a/src/templates/pubkey/index.ts b/src/templates/pubkey/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/pubkey/index.ts +++ b/src/templates/pubkey/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/pubkey/input.ts b/src/templates/pubkey/input.ts index b6963e7..f4b8bf7 100644 --- a/src/templates/pubkey/input.ts +++ b/src/templates/pubkey/input.ts @@ -1,16 +1,11 @@ // {signature} -const bscript = require('../../script') +import * as bscript from '../../script' -function check (script) { +export function check (script: Buffer | Array): boolean { const chunks = bscript.decompile(script) return chunks.length === 1 && - bscript.isCanonicalScriptSignature(chunks[0]) + bscript.isCanonicalScriptSignature(chunks[0]) } check.toJSON = function () { return 'pubKey input' } - -module.exports = { - check: check -} -export {} diff --git a/src/templates/pubkey/output.ts b/src/templates/pubkey/output.ts index b64c596..2728f68 100644 --- a/src/templates/pubkey/output.ts +++ b/src/templates/pubkey/output.ts @@ -1,16 +1,13 @@ // {pubKey} OP_CHECKSIG -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function check (script) { +export function check (script: Buffer | Array): boolean { const chunks = bscript.decompile(script) return chunks.length === 2 && - bscript.isCanonicalPubKey(chunks[0]) && + bscript.isCanonicalPubKey(chunks[0]) && chunks[1] === OPS.OP_CHECKSIG } check.toJSON = function () { return 'pubKey output' } - -module.exports = { check } -export {} From 3db951fc6454d61e7ebb40d6c873124e8f9f75db Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 14:32:20 +0900 Subject: [PATCH 070/183] Add p2pkh template --- src/templates/pubkeyhash/index.ts | 10 ++++++---- src/templates/pubkeyhash/input.ts | 11 ++++------- src/templates/pubkeyhash/output.ts | 7 ++----- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/templates/pubkeyhash/index.ts b/src/templates/pubkeyhash/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/pubkeyhash/index.ts +++ b/src/templates/pubkeyhash/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/pubkeyhash/input.ts b/src/templates/pubkeyhash/input.ts index cab6f0a..ffdc929 100644 --- a/src/templates/pubkeyhash/input.ts +++ b/src/templates/pubkeyhash/input.ts @@ -1,15 +1,12 @@ // {signature} {pubKey} -const bscript = require('../../script') +import * as bscript from '../../script' -function check (script) { +export function check (script: Buffer | Array): boolean { const chunks = bscript.decompile(script) return chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - bscript.isCanonicalPubKey(chunks[1]) + bscript.isCanonicalScriptSignature(chunks[0]) && + bscript.isCanonicalPubKey(chunks[1]) } check.toJSON = function () { return 'pubKeyHash input' } - -module.exports = { check } -export {} diff --git a/src/templates/pubkeyhash/output.ts b/src/templates/pubkeyhash/output.ts index bf34b83..71c1acb 100644 --- a/src/templates/pubkeyhash/output.ts +++ b/src/templates/pubkeyhash/output.ts @@ -1,9 +1,9 @@ // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length === 25 && @@ -14,6 +14,3 @@ function check (script) { buffer[24] === OPS.OP_CHECKSIG } check.toJSON = function () { return 'pubKeyHash output' } - -module.exports = { check } -export {} From c488001b824a6c60f25af0aaf220bec98631bddf Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 14:45:17 +0900 Subject: [PATCH 071/183] Add P2WPKH --- src/templates/witnesspubkeyhash/index.ts | 10 ++++++---- src/templates/witnesspubkeyhash/input.ts | 13 +++++-------- src/templates/witnesspubkeyhash/output.ts | 9 ++------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/templates/witnesspubkeyhash/index.ts b/src/templates/witnesspubkeyhash/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/witnesspubkeyhash/index.ts +++ b/src/templates/witnesspubkeyhash/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/witnesspubkeyhash/input.ts b/src/templates/witnesspubkeyhash/input.ts index ec93c47..36f0606 100644 --- a/src/templates/witnesspubkeyhash/input.ts +++ b/src/templates/witnesspubkeyhash/input.ts @@ -1,19 +1,16 @@ // {signature} {pubKey} -const bscript = require('../../script') +import * as bscript from '../../script' -function isCompressedCanonicalPubKey (pubKey) { +function isCompressedCanonicalPubKey (pubKey: Buffer): boolean { return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33 } -function check (script) { +export function check (script: Buffer | Array): boolean { const chunks = bscript.decompile(script) return chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - isCompressedCanonicalPubKey(chunks[1]) + bscript.isCanonicalScriptSignature(chunks[0]) && + isCompressedCanonicalPubKey(chunks[1]) } check.toJSON = function () { return 'witnessPubKeyHash input' } - -module.exports = { check } -export {} diff --git a/src/templates/witnesspubkeyhash/output.ts b/src/templates/witnesspubkeyhash/output.ts index a289038..46fb444 100644 --- a/src/templates/witnesspubkeyhash/output.ts +++ b/src/templates/witnesspubkeyhash/output.ts @@ -1,9 +1,9 @@ // OP_0 {pubKeyHash} -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length === 22 && @@ -11,8 +11,3 @@ function check (script) { buffer[1] === 0x14 } check.toJSON = function () { return 'Witness pubKeyHash output' } - -module.exports = { - check -} -export {} From 528dff01c11ab7c25d0a56dd56a0f733818db77b Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 14:55:30 +0900 Subject: [PATCH 072/183] Add P2WSH --- src/templates/witnessscripthash/index.ts | 10 ++++++---- src/templates/witnessscripthash/input.ts | 16 ++++++---------- src/templates/witnessscripthash/output.ts | 7 ++----- src/types.ts | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/templates/witnessscripthash/index.ts b/src/templates/witnessscripthash/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/witnessscripthash/index.ts +++ b/src/templates/witnessscripthash/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/witnessscripthash/input.ts b/src/templates/witnessscripthash/input.ts index c6d47e3..7f7e415 100644 --- a/src/templates/witnessscripthash/input.ts +++ b/src/templates/witnessscripthash/input.ts @@ -1,15 +1,14 @@ // {serialized scriptPubKey script} -const bscript = require('../../script') -const types = require('../../types') +import * as bscript from '../../script' const typeforce = require('typeforce') -const p2ms = require('../multisig/') -const p2pk = require('../pubkey/') -const p2pkh = require('../pubkeyhash/') +import * as p2ms from '../multisig' +import * as p2pk from '../pubkey' +import * as p2pkh from '../pubkeyhash' -function check (chunks, allowIncomplete) { - typeforce(types.Array, chunks) +export function check (chunks: Array, allowIncomplete?: boolean): boolean { + typeforce(typeforce.Array, chunks) if (chunks.length < 1) return false const witnessScript = chunks[chunks.length - 1] @@ -35,6 +34,3 @@ function check (chunks, allowIncomplete) { return false } check.toJSON = function () { return 'witnessScriptHash input' } - -module.exports = { check } -export {} diff --git a/src/templates/witnessscripthash/output.ts b/src/templates/witnessscripthash/output.ts index 3bc327f..0b13cd1 100644 --- a/src/templates/witnessscripthash/output.ts +++ b/src/templates/witnessscripthash/output.ts @@ -1,9 +1,9 @@ // OP_0 {scriptHash} -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length === 34 && @@ -11,6 +11,3 @@ function check (script) { buffer[1] === 0x20 } check.toJSON = function () { return 'Witness scriptHash output' } - -module.exports = { check } -export {} diff --git a/src/types.ts b/src/types.ts index 790b95e..ad603c5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,4 +34,4 @@ export const Buffer256bit = typeforce.BufferN(32) export const Hash160bit = typeforce.BufferN(20) export const Hash256bit = typeforce.BufferN(32) export * from 'typeforce' -export { Number } from 'typeforce' +export { Number, Array } from 'typeforce' From 604072ffaded0f9a982aa8cefd39227044b62da3 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 14:57:30 +0900 Subject: [PATCH 073/183] Add P2SH --- src/templates/scripthash/index.ts | 10 ++++++---- src/templates/scripthash/input.ts | 21 +++++++++------------ src/templates/scripthash/output.ts | 7 ++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/templates/scripthash/index.ts b/src/templates/scripthash/index.ts index 7192cfd..42aeb7b 100644 --- a/src/templates/scripthash/index.ts +++ b/src/templates/scripthash/index.ts @@ -1,5 +1,7 @@ -module.exports = { - input: require('./input'), - output: require('./output') +import * as input from './input' +import * as output from './output' + +export { + input, + output, } -export {} diff --git a/src/templates/scripthash/input.ts b/src/templates/scripthash/input.ts index ad53df9..908a87b 100644 --- a/src/templates/scripthash/input.ts +++ b/src/templates/scripthash/input.ts @@ -1,15 +1,15 @@ // {serialized scriptPubKey script} -const Buffer = require('safe-buffer').Buffer -const bscript = require('../../script') +import * as bscript from '../../script' +import * as p2ms from '../multisig' +import * as p2pk from '../pubkey' +import * as p2pkh from '../pubkeyhash' +import * as p2wpkho from '../witnesspubkeyhash/output' +import * as p2wsho from '../witnessscripthash/output' -const p2ms = require('../multisig/') -const p2pk = require('../pubkey/') -const p2pkh = require('../pubkeyhash/') -const p2wpkho = require('../witnesspubkeyhash/output') -const p2wsho = require('../witnessscripthash/output') +const Buffer = require('safe-buffer').Buffer -function check (script, allowIncomplete) { +export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { const chunks = bscript.decompile(script) if (chunks.length < 1) return false @@ -17,7 +17,7 @@ function check (script, allowIncomplete) { if (!Buffer.isBuffer(lastChunk)) return false const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))) - const redeemScriptChunks = bscript.decompile(lastChunk) + const redeemScriptChunks = bscript.decompile(lastChunk) // is redeemScript a valid script? if (!redeemScriptChunks) return false @@ -44,6 +44,3 @@ function check (script, allowIncomplete) { return false } check.toJSON = function () { return 'scriptHash input' } - -module.exports = { check } -export {} diff --git a/src/templates/scripthash/output.ts b/src/templates/scripthash/output.ts index 9f91f17..3215c25 100644 --- a/src/templates/scripthash/output.ts +++ b/src/templates/scripthash/output.ts @@ -1,9 +1,9 @@ // OP_HASH160 {scriptHash} OP_EQUAL -const bscript = require('../../script') +import * as bscript from '../../script' const OPS = require('bitcoin-ops') -function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length === 23 && @@ -12,6 +12,3 @@ function check (script) { buffer[22] === OPS.OP_EQUAL } check.toJSON = function () { return 'scriptHash output' } - -module.exports = { check } -export {} From 5c34b4ce22d2e6d9471c69cad5f761f9e793ab2a Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 28 Dec 2018 15:09:51 +0900 Subject: [PATCH 074/183] Add Witness Commitment --- src/templates/witnesscommitment/index.ts | 7 ++++--- src/templates/witnesscommitment/output.ts | 21 +++++++-------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/templates/witnesscommitment/index.ts b/src/templates/witnesscommitment/index.ts index d274d6b..c36a2b8 100644 --- a/src/templates/witnesscommitment/index.ts +++ b/src/templates/witnesscommitment/index.ts @@ -1,4 +1,5 @@ -module.exports = { - output: require('./output') +import * as output from './output' + +export { + output, } -export {} diff --git a/src/templates/witnesscommitment/output.ts b/src/templates/witnesscommitment/output.ts index db92e54..1b3a182 100644 --- a/src/templates/witnesscommitment/output.ts +++ b/src/templates/witnesscommitment/output.ts @@ -1,14 +1,14 @@ // OP_RETURN {aa21a9ed} {commitment} +import * as bscript from '../../script' +import * as types from '../../types' const Buffer = require('safe-buffer').Buffer -const bscript = require('../../script') -const types = require('../../types') const typeforce = require('typeforce') const OPS = require('bitcoin-ops') -const HEADER = Buffer.from('aa21a9ed', 'hex') +const HEADER: Buffer = Buffer.from('aa21a9ed', 'hex') -function check (script) { +export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) return buffer.length > 37 && @@ -19,7 +19,7 @@ function check (script) { check.toJSON = function () { return 'Witness commitment output' } -function encode (commitment) { +export function encode (commitment: Buffer): Buffer { typeforce(types.Hash256bit, commitment) const buffer = Buffer.allocUnsafe(36) @@ -29,15 +29,8 @@ function encode (commitment) { return bscript.compile([OPS.OP_RETURN, buffer]) } -function decode (buffer) { +export function decode (buffer: Buffer): Buffer { typeforce(check, buffer) - return bscript.decompile(buffer)[1].slice(4, 36) + return (bscript.decompile(buffer)[1]).slice(4, 36) } - -module.exports = { - check: check, - decode: decode, - encode: encode -} -export {} From 867f4b59f93fb894381000e721bf66ec5ce9c5ef Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 00:00:52 +0900 Subject: [PATCH 075/183] Add payments --- package.json | 2 +- src/payments/embed.ts | 20 +++++++------------- src/payments/index.ts | 40 +++++++++++++++++++++++++++++++--------- src/payments/lazy.ts | 9 +++------ src/payments/p2ms.ts | 40 +++++++++++++++------------------------- src/payments/p2pk.ts | 20 ++++++-------------- src/payments/p2pkh.ts | 24 +++++++++++------------- src/payments/p2sh.ts | 26 ++++++++++++-------------- src/payments/p2wpkh.ts | 23 ++++++++--------------- src/payments/p2wsh.ts | 25 +++++++++---------------- test/payments.js | 8 +++++++- 11 files changed, 110 insertions(+), 127 deletions(-) diff --git a/package.json b/package.json index 777a210..2583afc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 85 --functions 90 mocha", + "coverage": "nyc --check-coverage --branches 80 --functions 80 mocha", "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", diff --git a/src/payments/embed.ts b/src/payments/embed.ts index bfb70e5..a28747f 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -1,11 +1,11 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin - -function stacksEqual (a, b) { +function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false return a.every(function (x, i) { @@ -14,7 +14,7 @@ function stacksEqual (a, b) { } // output: OP_RETURN ... -function p2data (a, opts) { +export function p2data (a: Payment, opts: PaymentOpts): Payment { if ( !a.data && !a.output @@ -28,10 +28,7 @@ function p2data (a, opts) { }, a) const network = a.network || BITCOIN_NETWORK - const o = { - network, - data: undefined - } + const o = { network } lazy.prop(o, 'output', function () { if (!a.data) return @@ -55,6 +52,3 @@ function p2data (a, opts) { return Object.assign(o, a) } - -module.exports = p2data -export {} diff --git a/src/payments/index.ts b/src/payments/index.ts index bb4e0e6..08a8409 100644 --- a/src/payments/index.ts +++ b/src/payments/index.ts @@ -1,13 +1,35 @@ -const embed = require('./embed') -const p2ms = require('./p2ms') -const p2pk = require('./p2pk') -const p2pkh = require('./p2pkh') -const p2sh = require('./p2sh') -const p2wpkh = require('./p2wpkh') -const p2wsh = require('./p2wsh') +import { Network } from '../networks' +import { p2data as embed } from './embed' +import { p2ms } from './p2ms' +import { p2pk } from './p2pk' +import { p2pkh } from './p2pkh' +import { p2sh } from './p2sh' +import { p2wpkh } from './p2wpkh' +import { p2wsh } from './p2wsh' -module.exports = { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh } +export interface Payment { + network?: Network, + output?: Buffer, + data?: Array, + m?: number, + n?: number, + pubkeys?: Array, + input?: Buffer, + signatures?: Array, + pubkey?: Buffer, + signature?: Buffer, + address?: string, + hash?: Buffer, + redeem?: Payment, + witness?: Array, +} + +export interface PaymentOpts { + validate?: boolean, + allowIncomplete?: boolean, +} + +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh } // TODO // witness commitment -export {} diff --git a/src/payments/lazy.ts b/src/payments/lazy.ts index 4a9611c..6a4cbe3 100644 --- a/src/payments/lazy.ts +++ b/src/payments/lazy.ts @@ -1,4 +1,4 @@ -function prop (object, name, f) { +export function prop (object: Object, name: string, f: ()=>any): void { Object.defineProperty(object, name, { configurable: true, enumerable: true, @@ -18,14 +18,11 @@ function prop (object, name, f) { }) } -function value (f) { - let value +export function value (f: ()=>T): ()=>T { + let value: T return function () { if (value !== undefined) return value value = f() return value } } - -module.exports = { prop, value } -export {} diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index 39b38f1..2142ff1 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -1,13 +1,14 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') const ecc = require('tiny-secp256k1') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 -function stacksEqual (a, b) { +function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false return a.every(function (x, i) { @@ -17,7 +18,7 @@ function stacksEqual (a, b) { // input: OP_0 [signatures ...] // output: m [pubKeys ...] n OP_CHECKMULTISIG -function p2ms (a, opts) { +export function p2ms (a: Payment, opts: PaymentOpts): Payment { if ( !a.input && !a.output && @@ -26,8 +27,8 @@ function p2ms (a, opts) { ) throw new TypeError('Not enough data') opts = Object.assign({ validate: true }, opts || {}) - function isAcceptableSignature (x) { - return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) + function isAcceptableSignature (x: Buffer | number) { + return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) } typef({ @@ -42,25 +43,17 @@ function p2ms (a, opts) { }, a) const network = a.network || BITCOIN_NETWORK - const o = { - network, - m: undefined, - n: undefined, - pubkeys: undefined, - output: undefined, - input: undefined, - signatures: undefined, - } + const o: Payment = { network } - let chunks + let chunks: Array let decoded = false - function decode (output) { + function decode (output: Buffer | Array): void { if (decoded) return decoded = true chunks = bscript.decompile(output) - o.m = chunks[0] - OP_INT_BASE - o.n = chunks[chunks.length - 2] - OP_INT_BASE - o.pubkeys = chunks.slice(1, -2) + o.m = chunks[0] - OP_INT_BASE + o.n = chunks[chunks.length - 2] - OP_INT_BASE + o.pubkeys = >chunks.slice(1, -2) } lazy.prop(o, 'output', function () { @@ -137,13 +130,10 @@ function p2ms (a, opts) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - if (a.signatures && !stacksEqual(a.signatures.equals(o.signatures), undefined)) throw new TypeError('Signature mismatch') + if (a.signatures && !stacksEqual(a.signatures, o.signatures)) throw new TypeError('Signature mismatch') if (a.m !== undefined && a.m !== a.signatures.length) throw new TypeError('Signature count mismatch') } } return Object.assign(o, a) } - -module.exports = p2ms -export {} diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index b810d48..a1ac5e8 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -1,14 +1,14 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') const ecc = require('tiny-secp256k1') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin - // input: {signature} // output: {pubKey} OP_CHECKSIG -function p2pk (a, opts) { +export function p2pk (a: Payment, opts: PaymentOpts): Payment { if ( !a.input && !a.output && @@ -30,12 +30,7 @@ function p2pk (a, opts) { const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK - const o = { - network, - input: undefined, - pubkey: undefined, - signature: undefined, - } + const o: Payment = { network } lazy.prop(o, 'output', function () { if (!a.pubkey) return @@ -81,6 +76,3 @@ function p2pk (a, opts) { return Object.assign(o, a) } - -module.exports = p2pk -export {} diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index c322fc7..4324c2a 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -1,16 +1,17 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as bcrypto from '../crypto' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') const ecc = require('tiny-secp256k1') -const bcrypto = require('../crypto') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin const bs58check = require('bs58check') // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG -function p2pkh (a, opts) { +export function p2pkh (a: Payment, opts: PaymentOpts): Payment { if ( !a.address && !a.hash && @@ -90,7 +91,7 @@ function p2pkh (a, opts) { // extended validation if (opts.validate) { - let hash + let hash: Buffer if (a.address) { if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch') if (_address().hash.length !== 20) throw new TypeError('Invalid address') @@ -125,19 +126,16 @@ function p2pkh (a, opts) { if (a.input) { const chunks = _chunks() if (chunks.length !== 2) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature') + if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature') if (!ecc.isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey') - if (a.signature && !a.signature.equals(chunks[0])) throw new TypeError('Signature mismatch') - if (a.pubkey && !a.pubkey.equals(chunks[1])) throw new TypeError('Pubkey mismatch') + if (a.signature && !a.signature.equals(chunks[0])) throw new TypeError('Signature mismatch') + if (a.pubkey && !a.pubkey.equals(chunks[1])) throw new TypeError('Pubkey mismatch') - const pkh = bcrypto.hash160(chunks[1]) + const pkh = bcrypto.hash160(chunks[1]) if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') } } return Object.assign(o, a) } - -module.exports = p2pkh -export {} diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index 07bb32e..efd453a 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -1,13 +1,14 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as bcrypto from '../crypto' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') -const bcrypto = require('../crypto') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin const bs58check = require('bs58check') -function stacksEqual (a, b) { +function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false return a.every(function (x, i) { @@ -18,7 +19,7 @@ function stacksEqual (a, b) { // input: [redeemScriptSig ...] {redeemScript} // witness: // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL -function p2sh (a, opts) { +export function p2sh (a: Payment, opts: PaymentOpts): Payment { if ( !a.address && !a.hash && @@ -64,11 +65,11 @@ function p2sh (a, opts) { return { version, hash } }) const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) - const _redeem = lazy.value(function () { + const _redeem = lazy.value(function (): Payment { const chunks = _chunks() return { network, - output: chunks[chunks.length - 1], + output: chunks[chunks.length - 1], input: bscript.compile(chunks.slice(0, -1)), witness: a.witness || [] } @@ -116,7 +117,7 @@ function p2sh (a, opts) { }) if (opts.validate) { - let hash + let hash: Buffer if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch') if (_address().hash.length !== 20) throw new TypeError('Invalid address') @@ -141,7 +142,7 @@ function p2sh (a, opts) { } // inlined to prevent 'no-inner-declarations' failing - const checkRedeem = function (redeem) { + const checkRedeem = function (redeem: Payment): void { // is the redeem output empty/invalid? if (redeem.output) { const decompile = bscript.decompile(redeem.output) @@ -177,7 +178,7 @@ function p2sh (a, opts) { if (a.redeem.network && a.redeem.network !== network) throw new TypeError('Network mismatch') if (a.input) { const redeem = _redeem() - if (a.redeem.output && !a.redeem.output.equals(redeem.output)) throw new TypeError('Redeem.output mismatch') + if (a.redeem.output && !a.redeem.output.equals(redeem.output)) throw new TypeError('Redeem.output mismatch') if (a.redeem.input && !a.redeem.input.equals(redeem.input)) throw new TypeError('Redeem.input mismatch') } @@ -194,6 +195,3 @@ function p2sh (a, opts) { return Object.assign(o, a) } - -module.exports = p2sh -export {} diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index 1ab21b5..a25d037 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -1,19 +1,20 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as bcrypto from '../crypto' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') const ecc = require('tiny-secp256k1') -const bcrypto = require('../crypto') const bech32 = require('bech32') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin const EMPTY_BUFFER = Buffer.alloc(0) // witness: {signature} {pubKey} // input: <> // output: OP_0 {pubKeyHash} -function p2wpkh (a, opts) { +export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { if ( !a.address && !a.hash && @@ -46,12 +47,7 @@ function p2wpkh (a, opts) { }) const network = a.network || BITCOIN_NETWORK - const o = { - network, - hash: undefined, - pubkey: undefined, - witness: undefined, - } + const o: Payment = { network } lazy.prop(o, 'address', function () { if (!o.hash) return @@ -93,7 +89,7 @@ function p2wpkh (a, opts) { // extended validation if (opts.validate) { - let hash + let hash: Buffer if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') @@ -136,6 +132,3 @@ function p2wpkh (a, opts) { return Object.assign(o, a) } - -module.exports = p2wpkh -export {} diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index fe19314..d94d446 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -1,15 +1,16 @@ -const lazy = require('./lazy') +import { Payment, PaymentOpts } from './index' +import * as bscript from '../script' +import * as bcrypto from '../crypto' +import * as lazy from './lazy' +import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') const OPS = require('bitcoin-ops') const bech32 = require('bech32') -const bcrypto = require('../crypto') -const bscript = require('../script') -const BITCOIN_NETWORK = require('../networks').bitcoin const EMPTY_BUFFER = Buffer.alloc(0) -function stacksEqual (a, b) { +function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false return a.every(function (x, i) { @@ -20,7 +21,7 @@ function stacksEqual (a, b) { // input: <> // witness: [redeemScriptSig ...] {redeemScript} // output: OP_0 {sha256(redeemScript)} -function p2wsh (a, opts) { +export function p2wsh (a: Payment, opts: PaymentOpts): Payment { if ( !a.address && !a.hash && @@ -64,12 +65,7 @@ function p2wsh (a, opts) { network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK } - const o = { - network, - hash: undefined, - redeem: undefined, - witness: undefined, - } + const o: Payment = { network } lazy.prop(o, 'address', function () { if (!o.hash) return @@ -126,7 +122,7 @@ function p2wsh (a, opts) { // extended validation if (opts.validate) { - let hash + let hash: Buffer if (a.address) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') @@ -181,6 +177,3 @@ function p2wsh (a, opts) { return Object.assign(o, a) } - -module.exports = p2wsh -export {} diff --git a/test/payments.js b/test/payments.js index 53e3f16..6617047 100644 --- a/test/payments.js +++ b/test/payments.js @@ -4,7 +4,13 @@ const u = require('./payments.utils') ;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) { describe(p, function () { - const fn = require('../dist/src/payments/' + p) + let fn + let payment = require('../dist/src/payments/' + p) + if (p === 'embed') { + fn = payment.p2data + } else { + fn = payment[p] + } const fixtures = require('./fixtures/' + p) fixtures.valid.forEach(function (f, i) { From 4cddc83016af9fbbaf677a72b09bfe97e7756e19 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 00:53:54 +0900 Subject: [PATCH 076/183] noImplicitAny is now true --- package.json | 2 +- src/address.ts | 6 +++--- src/block.ts | 2 +- src/ecpair.ts | 14 +++++++------- src/index.ts | 2 +- src/payments/p2pkh.ts | 7 +------ src/payments/p2sh.ts | 7 +------ src/script.ts | 6 +++--- src/script_number.ts | 2 +- src/script_signature.ts | 2 +- src/transaction.ts | 32 ++++++++++++++++---------------- src/transaction_builder.ts | 10 +++++----- src/types.ts | 16 ++++++++++++++-- tsconfig.json | 2 +- 14 files changed, 56 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 2583afc..55454bc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 80 --functions 80 mocha", + "coverage": "nyc --check-coverage --branches 80 --functions 80 --lines 80 mocha", "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", diff --git a/src/address.ts b/src/address.ts index e657d24..f273b43 100644 --- a/src/address.ts +++ b/src/address.ts @@ -1,13 +1,13 @@ +import * as Networks from './networks' +import { Network } from './networks' +import * as types from './types' const Buffer = require('safe-buffer').Buffer const bech32 = require('bech32') const bs58check = require('bs58check') const bscript = require('./script') const networks = require('./networks') const typeforce = require('typeforce') -const types = require('./types') const payments = require('./payments') -import * as Networks from './networks' -import { Network } from './networks' export type Base58CheckResult = { hash: Buffer; diff --git a/src/block.ts b/src/block.ts index 92c4fb1..03ff901 100644 --- a/src/block.ts +++ b/src/block.ts @@ -1,9 +1,9 @@ import { Transaction } from './transaction' +import * as types from './types' const Buffer = require('safe-buffer').Buffer const bcrypto = require('./crypto') const fastMerkleRoot = require('merkle-lib/fastRoot') const typeforce = require('typeforce') -const types = require('./types') const varuint = require('varuint-bitcoin') const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions') diff --git a/src/ecpair.ts b/src/ecpair.ts index eceb2a1..cb835d1 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -1,9 +1,9 @@ import { Network } from './networks' import * as NETWORKS from './networks' +import * as types from './types' const ecc = require('tiny-secp256k1') const randomBytes = require('randombytes') const typeforce = require('typeforce') -const types = require('./types') const wif = require('wif') const isOptions = typeforce.maybe(typeforce.compile({ @@ -14,7 +14,7 @@ const isOptions = typeforce.maybe(typeforce.compile({ interface ECPairOptions { compressed?: boolean network?: Network - rng?(Buffer): Buffer + rng?(arg0: Buffer): Buffer } export interface ECPairInterface { @@ -75,19 +75,19 @@ function fromPrivateKey (buffer: Buffer, options: ECPairOptions): ECPair { return new ECPair(buffer, null, options) } -function fromPublicKey (buffer, options): ECPair { +function fromPublicKey (buffer: Buffer, options: ECPairOptions): ECPair { typeforce(ecc.isPoint, buffer) typeforce(isOptions, options) return new ECPair(null, buffer, options) } -function fromWIF (string, network): ECPair { +function fromWIF (string: string, network: Network | Array): ECPair { const decoded = wif.decode(string) const version = decoded.version // list of networks? if (types.Array(network)) { - network = network.filter(function (x) { + network = (>network).filter(function (x: Network) { return version === x.wif }).pop() @@ -97,12 +97,12 @@ function fromWIF (string, network): ECPair { } else { network = network || NETWORKS.bitcoin - if (version !== network.wif) throw new Error('Invalid network version') + if (version !== (network).wif) throw new Error('Invalid network version') } return fromPrivateKey(decoded.privateKey, { compressed: decoded.compressed, - network: network + network: network }) } diff --git a/src/index.ts b/src/index.ts index 8019cb7..d93f587 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ const opcodes = require('bitcoin-ops') +const bip32 = require('bip32') import { Block } from './block' import * as ECPair from './ecpair' import { Transaction } from './transaction' import { TransactionBuilder } from './transaction_builder' import * as address from './address' -import * as bip32 from 'bip32' import * as crypto from './crypto' import * as networks from './networks' import * as payments from './payments' diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index 4324c2a..e32f933 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -41,12 +41,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK - const o = { - network, - hash: undefined, - pubkey: undefined, - input: undefined, - } + const o: Payment = { network } lazy.prop(o, 'address', function () { if (!o.hash) return diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index efd453a..2219f33 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -51,12 +51,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK } - const o = { - network, - hash: undefined, - redeem: undefined, - input: undefined, - } + const o: Payment = { network } const _address = lazy.value(function () { const payload = bs58check.decode(a.address) diff --git a/src/script.ts b/src/script.ts index 98b018a..88bc46e 100644 --- a/src/script.ts +++ b/src/script.ts @@ -1,9 +1,9 @@ +import * as types from './types' const Buffer = require('safe-buffer').Buffer const bip66 = require('bip66') const ecc = require('tiny-secp256k1') const pushdata = require('pushdata-bitcoin') const typeforce = require('typeforce') -const types = require('./types') const scriptNumber = require('./script_number') const OPS = require('bitcoin-ops') @@ -100,7 +100,7 @@ export function decompile (buffer: Buffer | Array): Array = [] let i = 0 while (i < buffer.length) { @@ -123,7 +123,7 @@ export function decompile (buffer: Buffer | Array): Arrayop) } else { chunks.push(data) } diff --git a/src/script_number.ts b/src/script_number.ts index 8178c95..0ff4a7e 100644 --- a/src/script_number.ts +++ b/src/script_number.ts @@ -32,7 +32,7 @@ export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): return result } -function scriptNumSize (i) { +function scriptNumSize (i: number): number { return i > 0x7fffffff ? 5 : i > 0x7fffff ? 4 : i > 0x7fff ? 3 diff --git a/src/script_signature.ts b/src/script_signature.ts index fefd09d..c24e88a 100644 --- a/src/script_signature.ts +++ b/src/script_signature.ts @@ -1,7 +1,7 @@ +import * as types from './types' const bip66 = require('bip66') const Buffer = require('safe-buffer').Buffer const typeforce = require('typeforce') -const types = require('./types') const ZERO = Buffer.alloc(1, 0) function toDER (x: Buffer): Buffer { diff --git a/src/transaction.ts b/src/transaction.ts index 88e4280..91956c5 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -1,10 +1,10 @@ import * as bcrypto from './crypto' +import * as bscript from './script' +import * as types from './types' const Buffer = require('safe-buffer').Buffer -const bscript = require('./script') const bufferutils = require('./bufferutils') const opcodes = require('bitcoin-ops') const typeforce = require('typeforce') -const types = require('./types') const varuint = require('varuint-bitcoin') function varSliceSize (someScript: Buffer): number { @@ -73,7 +73,7 @@ export class Transaction { this.ins = [] this.outs = [] } - + static fromBuffer (buffer: Buffer, __noStrict: boolean): Transaction { let offset: number = 0 @@ -294,7 +294,7 @@ export class Transaction { // ignore OP_CODESEPARATOR const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { - return x !== opcodes.OP_CODESEPARATOR + return x !== opcodes.OP_CODESEPARATOR })) const txTmp = this.clone() @@ -465,46 +465,46 @@ export class Transaction { return Buffer.from(this.getHash(false).reverse()).toString('hex') } - toBuffer (buffer: Buffer | void, initialOffset: number | void): Buffer { + toBuffer (buffer?: Buffer, initialOffset?: number): Buffer { return this.__toBuffer(buffer, initialOffset, true) } - __toBuffer (buffer: Buffer | void, initialOffset: number | void, __allowWitness: boolean | void): Buffer { + __toBuffer (buffer?: Buffer, initialOffset?: number, __allowWitness?: boolean): Buffer { if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength((__allowWitness))) let offset = initialOffset || 0 - function writeSlice (slice) { + function writeSlice (slice: Buffer): void { offset += slice.copy(buffer, offset) } - function writeUInt8 (i) { + function writeUInt8 (i: number) { offset = (buffer).writeUInt8(i, offset) } - function writeUInt32 (i) { + function writeUInt32 (i: number) { offset = (buffer).writeUInt32LE(i, offset) } - function writeInt32 (i) { + function writeInt32 (i: number) { offset = (buffer).writeInt32LE(i, offset) } - function writeUInt64 (i) { + function writeUInt64 (i: number) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } - function writeVarInt (i) { + function writeVarInt (i: number) { varuint.encode(i, buffer, offset) offset += varuint.encode.bytes } - function writeVarSlice (slice) { + function writeVarSlice (slice: Buffer) { writeVarInt(slice.length) writeSlice(slice) } - function writeVector (vector) { + function writeVector (vector: Array) { writeVarInt(vector.length) vector.forEach(writeVarSlice) } @@ -555,13 +555,13 @@ export class Transaction { return this.toBuffer(undefined, undefined).toString('hex') } - setInputScript (index, scriptSig) { + setInputScript (index: number, scriptSig: Buffer) { typeforce(types.tuple(types.Number, types.Buffer), arguments) this.ins[index].script = scriptSig } - setWitness (index, witness) { + setWitness (index: number, witness: Array) { typeforce(types.tuple(types.Number, [types.Buffer]), arguments) this.ins[index].witness = witness diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index 01717ab..e4c9c09 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -2,6 +2,7 @@ import { Network } from './networks' import * as networks from './networks' import { Transaction, Output } from './transaction' import { ECPairInterface } from './ecpair' +import * as types from './types' const Buffer = require('safe-buffer').Buffer const baddress = require('./address') const bcrypto = require('./crypto') @@ -9,7 +10,6 @@ const bscript = require('./script') const ops = require('bitcoin-ops') const payments = require('./payments') const typeforce = require('typeforce') -const types = require('./types') const classify = require('./classify') const SCRIPT_TYPES = classify.types @@ -53,7 +53,7 @@ function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { export class TransactionBuilder { network: Network maximumFeeRate: number - private __prevTxSet: Object + private __prevTxSet: { [index: string]: boolean } private __inputs: Array private __tx: Transaction @@ -192,7 +192,7 @@ export class TransactionBuilder { return vin } - addOutput (scriptPubKey: string | Buffer, value): number { + addOutput (scriptPubKey: string | Buffer, value: number): number { if (!this.__canModifyOutputs()) { throw new Error('No, this would invalidate signatures') } @@ -282,7 +282,7 @@ export class TransactionBuilder { } // ready to sign - let signatureHash + let signatureHash: Buffer if (input.hasWitness) { signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) } else { @@ -573,7 +573,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { return { type, pubkeys: p2ms.pubkeys, - signatures: p2ms.pubkeys.map(() => undefined), + signatures: p2ms.pubkeys.map((): undefined => undefined), maxSignatures: p2ms.m } } diff --git a/src/types.ts b/src/types.ts index ad603c5..8eacbdc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -33,5 +33,17 @@ export const Network = typeforce.compile({ export const Buffer256bit = typeforce.BufferN(32) export const Hash160bit = typeforce.BufferN(20) export const Hash256bit = typeforce.BufferN(32) -export * from 'typeforce' -export { Number, Array } from 'typeforce' +export const Number = typeforce.Number +export const Array = typeforce.Array +export const Boolean = typeforce.Boolean +export const String = typeforce.String +export const Buffer = typeforce.Buffer +export const Hex = typeforce.Hex +export const maybe = typeforce.maybe +export const tuple = typeforce.tuple +export const UInt8 = typeforce.UInt8 +export const UInt32 = typeforce.UInt32 +export const Function = typeforce.Function +export const BufferN = typeforce.BufferN +export const Null = typeforce.Null +export const oneOf = typeforce.oneOf diff --git a/tsconfig.json b/tsconfig.json index 8803b83..f8bd5e2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ ], "allowJs": false, "strict": false, - "noImplicitAny": false, + "noImplicitAny": true, "strictNullChecks": false, "strictFunctionTypes": true, "strictBindCallApply": true, From fdf0006fdeb54f6bcd6d4e244b4ba5eb354ace81 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 01:55:07 +0900 Subject: [PATCH 077/183] Add strictNullChecks --- src/address.ts | 4 +- src/ecpair.ts | 16 ++++---- src/payments/embed.ts | 8 ++-- src/payments/lazy.ts | 2 +- src/payments/p2ms.ts | 32 ++++++++-------- src/payments/p2pk.ts | 10 ++--- src/payments/p2pkh.ts | 18 ++++----- src/payments/p2sh.ts | 21 ++++++----- src/payments/p2wpkh.ts | 12 +++--- src/payments/p2wsh.ts | 19 +++++----- src/script.ts | 6 +-- src/templates/multisig/input.ts | 2 +- src/templates/multisig/output.ts | 2 +- src/templates/pubkey/input.ts | 2 +- src/templates/pubkey/output.ts | 2 +- src/templates/pubkeyhash/input.ts | 2 +- src/templates/scripthash/input.ts | 4 +- src/templates/witnesscommitment/output.ts | 2 +- src/templates/witnesspubkeyhash/input.ts | 2 +- src/transaction.ts | 8 ++-- src/transaction_builder.ts | 46 +++++++++++------------ tsconfig.json | 6 +-- 22 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/address.ts b/src/address.ts index f273b43..c9ffeeb 100644 --- a/src/address.ts +++ b/src/address.ts @@ -75,8 +75,8 @@ export function fromOutputScript (output: Buffer, network: Network): string { // export function toOutputScript (address: string, network: Network): Buffer { network = network || networks.bitcoin - let decodeBase58: Base58CheckResult - let decodeBech32: Bech32Result + let decodeBase58: Base58CheckResult | undefined = undefined + let decodeBech32: Bech32Result | undefined = undefined try { decodeBase58 = fromBase58Check(address) } catch (e) {} diff --git a/src/ecpair.ts b/src/ecpair.ts index cb835d1..a7426ae 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -20,8 +20,8 @@ interface ECPairOptions { export interface ECPairInterface { compressed: boolean network: Network - privateKey: Buffer - publicKey: Buffer + privateKey: Buffer | null + publicKey: Buffer | null toWIF(): string sign(hash: Buffer): Buffer verify(hash: Buffer, signature: Buffer): Buffer @@ -31,9 +31,9 @@ export interface ECPairInterface { class ECPair implements ECPairInterface { compressed: boolean network: Network - private __d: Buffer - private __Q: Buffer - constructor (d: Buffer | void, Q: Buffer | void, options: ECPairOptions) { + private __d: Buffer | null + private __Q: Buffer | null + constructor (d: Buffer | null, Q: Buffer | null, options: ECPairOptions) { if (options === undefined) options = {} this.compressed = options.compressed === undefined ? true : options.compressed this.network = options.network || NETWORKS.bitcoin @@ -43,11 +43,11 @@ class ECPair implements ECPairInterface { if (Q) this.__Q = ecc.pointCompress(Q, this.compressed) } - get privateKey (): Buffer { + get privateKey (): Buffer | null { return this.__d } - get publicKey (): Buffer { + get publicKey (): Buffer | null { if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed) return this.__Q } @@ -87,7 +87,7 @@ function fromWIF (string: string, network: Network | Array): ECPair { // list of networks? if (types.Array(network)) { - network = (>network).filter(function (x: Network) { + network = (>network).filter(function (x: Network) { return version === x.wif }).pop() diff --git a/src/payments/embed.ts b/src/payments/embed.ts index a28747f..2526fe0 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -36,17 +36,17 @@ export function p2data (a: Payment, opts: PaymentOpts): Payment { }) lazy.prop(o, 'data', function () { if (!a.output) return - return bscript.decompile(a.output).slice(1) + return (>bscript.decompile(a.output)).slice(1) }) // extended validation if (opts.validate) { if (a.output) { const chunks = bscript.decompile(a.output) - if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') - if (!chunks.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') + if ((>chunks)[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') + if (!(>chunks).slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') - if (a.data && !stacksEqual(a.data, o.data)) throw new TypeError('Data mismatch') + if (a.data && !stacksEqual(a.data, >o.data)) throw new TypeError('Data mismatch') } } diff --git a/src/payments/lazy.ts b/src/payments/lazy.ts index 6a4cbe3..1d4af68 100644 --- a/src/payments/lazy.ts +++ b/src/payments/lazy.ts @@ -20,7 +20,7 @@ export function prop (object: Object, name: string, f: ()=>any): void { export function value (f: ()=>T): ()=>T { let value: T - return function () { + return function (): T { if (value !== undefined) return value value = f() return value diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index 2142ff1..b8a05b3 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -28,7 +28,7 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { opts = Object.assign({ validate: true }, opts || {}) function isAcceptableSignature (x: Buffer | number) { - return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) + return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) !== undefined } typef({ @@ -45,12 +45,12 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { const network = a.network || BITCOIN_NETWORK const o: Payment = { network } - let chunks: Array + let chunks: Array = [] let decoded = false function decode (output: Buffer | Array): void { if (decoded) return decoded = true - chunks = bscript.decompile(output) + chunks = >bscript.decompile(output) o.m = chunks[0] - OP_INT_BASE o.n = chunks[chunks.length - 2] - OP_INT_BASE o.pubkeys = >chunks.slice(1, -2) @@ -60,7 +60,7 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { if (!a.m) return if (!o.n) return if (!a.pubkeys) return - return bscript.compile([].concat( + return bscript.compile((>[]).concat( OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, @@ -83,7 +83,7 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { }) lazy.prop(o, 'signatures', function () { if (!a.input) return - return bscript.decompile(a.input).slice(1) + return (>bscript.decompile(a.input)).slice(1) }) lazy.prop(o, 'input', function () { if (!a.signatures) return @@ -103,35 +103,35 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid') if ( - o.m <= 0 || - o.n > 16 || - o.m > o.n || + (o).m <= 0 || + (o).n > 16 || + (o).m > (o).n || o.n !== chunks.length - 3) throw new TypeError('Output is invalid') - if (!o.pubkeys.every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') + if (!(>o.pubkeys).every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch') if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch') - if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) throw new TypeError('Pubkeys mismatch') + if (a.pubkeys && !stacksEqual(a.pubkeys, (>o.pubkeys))) throw new TypeError('Pubkeys mismatch') } if (a.pubkeys) { if (a.n !== undefined && a.n !== a.pubkeys.length) throw new TypeError('Pubkey count mismatch') o.n = a.pubkeys.length - if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m') + if (o.n < (o).m) throw new TypeError('Pubkey count cannot be less than m') } if (a.signatures) { - if (a.signatures.length < o.m) throw new TypeError('Not enough signatures provided') - if (a.signatures.length > o.m) throw new TypeError('Too many signatures provided') + if (a.signatures.length < (o).m) throw new TypeError('Not enough signatures provided') + if (a.signatures.length > (o).m) throw new TypeError('Too many signatures provided') } if (a.input) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') - if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') + if ((>o.signatures).length === 0 || !(>o.signatures).every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - if (a.signatures && !stacksEqual(a.signatures, o.signatures)) throw new TypeError('Signature mismatch') - if (a.m !== undefined && a.m !== a.signatures.length) throw new TypeError('Signature count mismatch') + if (a.signatures && !stacksEqual(a.signatures, (>o.signatures))) throw new TypeError('Signature mismatch') + if (a.m !== undefined && a.m !== (>a.signatures).length) throw new TypeError('Signature count mismatch') } } diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index a1ac5e8..45b3577 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -27,7 +27,7 @@ export function p2pk (a: Payment, opts: PaymentOpts): Payment { input: typef.maybe(typef.Buffer) }, a) - const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK const o: Payment = { network } @@ -45,7 +45,7 @@ export function p2pk (a: Payment, opts: PaymentOpts): Payment { }) lazy.prop(o, 'signature', function () { if (!a.input) return - return _chunks()[0] + return _chunks()[0] }) lazy.prop(o, 'input', function () { if (!a.signature) return @@ -61,16 +61,16 @@ export function p2pk (a: Payment, opts: PaymentOpts): Payment { if (a.output) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') if (!ecc.isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid') - if (a.pubkey && !a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch') + if (a.pubkey && !a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch') } if (a.signature) { - if (a.input && !a.input.equals(o.input)) throw new TypeError('Signature mismatch') + if (a.input && !a.input.equals(o.input)) throw new TypeError('Signature mismatch') } if (a.input) { if (_chunks().length !== 1) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(o.signature)) throw new TypeError('Input has invalid signature') + if (!bscript.isCanonicalScriptSignature(o.signature)) throw new TypeError('Input has invalid signature') } } diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index e32f933..f2054b0 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -38,7 +38,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { const hash = payload.slice(1) return { version, hash } }) - const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) const network = a.network || BITCOIN_NETWORK const o: Payment = { network } @@ -54,7 +54,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(3, 23) if (a.address) return _address().hash - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) }) lazy.prop(o, 'output', function () { if (!o.hash) return @@ -68,11 +68,11 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { }) lazy.prop(o, 'pubkey', function () { if (!a.input) return - return _chunks()[1] + return _chunks()[1] }) lazy.prop(o, 'signature', function () { if (!a.input) return - return _chunks()[0] + return _chunks()[0] }) lazy.prop(o, 'input', function () { if (!a.pubkey) return @@ -86,7 +86,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { // extended validation if (opts.validate) { - let hash: Buffer + let hash: Buffer = Buffer.from([]) if (a.address) { if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch') if (_address().hash.length !== 20) throw new TypeError('Invalid address') @@ -94,7 +94,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { } if (a.hash) { - if (hash && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') else hash = a.hash } @@ -108,13 +108,13 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { a.output[24] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') const hash2 = a.output.slice(3, 23) - if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey) - if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') else hash = pkh } @@ -128,7 +128,7 @@ export function p2pkh (a: Payment, opts: PaymentOpts): Payment { if (a.pubkey && !a.pubkey.equals(chunks[1])) throw new TypeError('Pubkey mismatch') const pkh = bcrypto.hash160(chunks[1]) - if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') } } diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index 2219f33..6facde9 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -1,4 +1,5 @@ import { Payment, PaymentOpts } from './index' +import { Network } from '../networks' import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' @@ -59,7 +60,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { const hash = payload.slice(1) return { version, hash } }) - const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) const _redeem = lazy.value(function (): Payment { const chunks = _chunks() return { @@ -75,7 +76,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { if (!o.hash) return const payload = Buffer.allocUnsafe(21) - payload.writeUInt8(network.scriptHash, 0) + payload.writeUInt8((o.network).scriptHash, 0) o.hash.copy(payload, 1) return bs58check.encode(payload) }) @@ -101,8 +102,8 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { }) lazy.prop(o, 'input', function () { if (!a.redeem || !a.redeem.input || !a.redeem.output) return - return bscript.compile([].concat( - bscript.decompile(a.redeem.input), + return bscript.compile((>[]).concat( + >bscript.decompile(a.redeem.input), a.redeem.output )) }) @@ -112,7 +113,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { }) if (opts.validate) { - let hash: Buffer + let hash: Buffer = Buffer.from([]) if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch') if (_address().hash.length !== 20) throw new TypeError('Invalid address') @@ -120,7 +121,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { } if (a.hash) { - if (hash && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') else hash = a.hash } @@ -132,7 +133,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { a.output[22] !== OPS.OP_EQUAL) throw new TypeError('Output is invalid') const hash2 = a.output.slice(2, 22) - if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 } @@ -145,7 +146,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { // match hash against other sources const hash2 = bcrypto.hash160(redeem.output) - if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 } @@ -155,7 +156,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { if (!hasInput && !hasWitness) throw new TypeError('Empty input') if (hasInput && hasWitness) throw new TypeError('Input and witness provided') if (hasInput) { - const richunks = bscript.decompile(redeem.input) + const richunks = >bscript.decompile(redeem.input) if (!bscript.isPushOnly(richunks)) throw new TypeError('Non push-only scriptSig') } } @@ -174,7 +175,7 @@ export function p2sh (a: Payment, opts: PaymentOpts): Payment { if (a.input) { const redeem = _redeem() if (a.redeem.output && !a.redeem.output.equals(redeem.output)) throw new TypeError('Redeem.output mismatch') - if (a.redeem.input && !a.redeem.input.equals(redeem.input)) throw new TypeError('Redeem.input mismatch') + if (a.redeem.input && !a.redeem.input.equals(redeem.input)) throw new TypeError('Redeem.input mismatch') } checkRedeem(a.redeem) diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index a25d037..7089246 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -59,7 +59,7 @@ export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(2, 22) if (a.address) return _address().data - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) }) lazy.prop(o, 'output', function () { if (!o.hash) return @@ -89,7 +89,7 @@ export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { // extended validation if (opts.validate) { - let hash: Buffer + let hash: Buffer = Buffer.from([]) if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') @@ -98,7 +98,7 @@ export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { } if (a.hash) { - if (hash && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') else hash = a.hash } @@ -107,13 +107,13 @@ export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { a.output.length !== 22 || a.output[0] !== OPS.OP_0 || a.output[1] !== 0x14) throw new TypeError('Output is invalid') - if (hash && !hash.equals(a.output.slice(2))) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(a.output.slice(2))) throw new TypeError('Hash mismatch') else hash = a.output.slice(2) } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey) - if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') else hash = pkh } @@ -126,7 +126,7 @@ export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { if (a.pubkey && !a.pubkey.equals(a.witness[1])) throw new TypeError('Pubkey mismatch') const pkh = bcrypto.hash160(a.witness[1]) - if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') } } diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index d94d446..c70cfb6 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -1,4 +1,5 @@ import { Payment, PaymentOpts } from './index' +import { Network } from '../networks' import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' @@ -58,7 +59,7 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { data: Buffer.from(data) } }) - const _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input) }) + const _rchunks = <()=>Array>lazy.value(function () { return bscript.decompile((a.redeem).input) }) let network = a.network if (!network) { @@ -71,7 +72,7 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { if (!o.hash) return const words = bech32.toWords(o.hash) words.unshift(0x00) - return bech32.encode(network.bech32, words) + return bech32.encode((network).bech32, words) }) lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(2) @@ -111,18 +112,18 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { // assign, and blank the existing input o.redeem = Object.assign({ witness: stack }, a.redeem) o.redeem.input = EMPTY_BUFFER - return [].concat(stack, a.redeem.output) + return (>[]).concat(stack, a.redeem.output) } if (!a.redeem) return if (!a.redeem.output) return if (!a.redeem.witness) return - return [].concat(a.redeem.witness, a.redeem.output) + return (>[]).concat(a.redeem.witness, a.redeem.output) }) // extended validation if (opts.validate) { - let hash: Buffer + let hash: Buffer = Buffer.from([]) if (a.address) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch') if (_address().version !== 0x00) throw new TypeError('Invalid address version') @@ -131,7 +132,7 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { } if (a.hash) { - if (hash && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') else hash = a.hash } @@ -141,7 +142,7 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { a.output[0] !== OPS.OP_0 || a.output[1] !== 0x20) throw new TypeError('Output is invalid') const hash2 = a.output.slice(2) - if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 } @@ -158,11 +159,11 @@ export function p2wsh (a: Payment, opts: PaymentOpts): Payment { // is the redeem output non-empty? if (a.redeem.output) { - if (bscript.decompile(a.redeem.output).length === 0) throw new TypeError('Redeem.output is invalid') + if ((>bscript.decompile(a.redeem.output)).length === 0) throw new TypeError('Redeem.output is invalid') // match hash against other sources const hash2 = bcrypto.sha256(a.redeem.output) - if (hash && !hash.equals(hash2)) throw new TypeError('Hash mismatch') + if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') else hash = hash2 } diff --git a/src/script.ts b/src/script.ts index 88bc46e..6d9bfc9 100644 --- a/src/script.ts +++ b/src/script.ts @@ -94,7 +94,7 @@ export function compile (chunks: Buffer | Array): Buffer { return buffer } -export function decompile (buffer: Buffer | Array): Array { +export function decompile (buffer: Buffer | Array): Array | null { // TODO: remove me if (chunksIsArray(buffer)) return buffer @@ -141,7 +141,7 @@ export function decompile (buffer: Buffer | Array): Array): string { if (chunksIsBuffer(chunks)) { - chunks = decompile(chunks) + chunks = >decompile(chunks) } return chunks.map(function (chunk) { @@ -171,7 +171,7 @@ export function fromASM (asm: string): Buffer { } export function toStack (chunks: Buffer | Array): Array { - chunks = decompile(chunks) + chunks = >decompile(chunks) typeforce(isPushOnly, chunks) return chunks.map(function (op) { diff --git a/src/templates/multisig/input.ts b/src/templates/multisig/input.ts index 2060242..abf0982 100644 --- a/src/templates/multisig/input.ts +++ b/src/templates/multisig/input.ts @@ -8,7 +8,7 @@ function partialSignature (value: number | Buffer): boolean { } export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) if (chunks.length < 2) return false if (chunks[0] !== OPS.OP_0) return false diff --git a/src/templates/multisig/output.ts b/src/templates/multisig/output.ts index 50c701e..e4fa333 100644 --- a/src/templates/multisig/output.ts +++ b/src/templates/multisig/output.ts @@ -6,7 +6,7 @@ const OPS = require('bitcoin-ops') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) if (chunks.length < 4) return false if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false diff --git a/src/templates/pubkey/input.ts b/src/templates/pubkey/input.ts index f4b8bf7..f9245e4 100644 --- a/src/templates/pubkey/input.ts +++ b/src/templates/pubkey/input.ts @@ -3,7 +3,7 @@ import * as bscript from '../../script' export function check (script: Buffer | Array): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) return chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]) diff --git a/src/templates/pubkey/output.ts b/src/templates/pubkey/output.ts index 2728f68..f60cc05 100644 --- a/src/templates/pubkey/output.ts +++ b/src/templates/pubkey/output.ts @@ -4,7 +4,7 @@ import * as bscript from '../../script' const OPS = require('bitcoin-ops') export function check (script: Buffer | Array): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) return chunks.length === 2 && bscript.isCanonicalPubKey(chunks[0]) && diff --git a/src/templates/pubkeyhash/input.ts b/src/templates/pubkeyhash/input.ts index ffdc929..f27f809 100644 --- a/src/templates/pubkeyhash/input.ts +++ b/src/templates/pubkeyhash/input.ts @@ -3,7 +3,7 @@ import * as bscript from '../../script' export function check (script: Buffer | Array): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) return chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && diff --git a/src/templates/scripthash/input.ts b/src/templates/scripthash/input.ts index 908a87b..93e7d58 100644 --- a/src/templates/scripthash/input.ts +++ b/src/templates/scripthash/input.ts @@ -10,13 +10,13 @@ import * as p2wsho from '../witnessscripthash/output' const Buffer = require('safe-buffer').Buffer export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) if (chunks.length < 1) return false const lastChunk = chunks[chunks.length - 1] if (!Buffer.isBuffer(lastChunk)) return false - const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))) + const scriptSigChunks = >bscript.decompile(bscript.compile(chunks.slice(0, -1))) const redeemScriptChunks = bscript.decompile(lastChunk) // is redeemScript a valid script? diff --git a/src/templates/witnesscommitment/output.ts b/src/templates/witnesscommitment/output.ts index 1b3a182..d89b8e2 100644 --- a/src/templates/witnesscommitment/output.ts +++ b/src/templates/witnesscommitment/output.ts @@ -32,5 +32,5 @@ export function encode (commitment: Buffer): Buffer { export function decode (buffer: Buffer): Buffer { typeforce(check, buffer) - return (bscript.decompile(buffer)[1]).slice(4, 36) + return ((>bscript.decompile(buffer))[1]).slice(4, 36) } diff --git a/src/templates/witnesspubkeyhash/input.ts b/src/templates/witnesspubkeyhash/input.ts index 36f0606..91b8357 100644 --- a/src/templates/witnesspubkeyhash/input.ts +++ b/src/templates/witnesspubkeyhash/input.ts @@ -7,7 +7,7 @@ function isCompressedCanonicalPubKey (pubKey: Buffer): boolean { } export function check (script: Buffer | Array): boolean { - const chunks = bscript.decompile(script) + const chunks = >bscript.decompile(script) return chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && diff --git a/src/transaction.ts b/src/transaction.ts index 91956c5..af17449 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -182,7 +182,7 @@ export class Transaction { return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) } - addInput (hash: Buffer, index: number, sequence: number, scriptSig: Buffer): number { + addInput (hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number { typeforce(types.tuple( types.Hash256bit, types.UInt32, @@ -199,7 +199,7 @@ export class Transaction { hash: hash, index: index, script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, + sequence: sequence, witness: EMPTY_WITNESS }) - 1) } @@ -293,7 +293,7 @@ export class Transaction { if (inIndex >= this.ins.length) return ONE // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { + const ourScript = bscript.compile((>bscript.decompile(prevOutScript)).filter((x) => { return x !== opcodes.OP_CODESEPARATOR })) @@ -475,7 +475,7 @@ export class Transaction { let offset = initialOffset || 0 function writeSlice (slice: Buffer): void { - offset += slice.copy(buffer, offset) + offset += slice.copy(buffer, offset) } function writeUInt8 (i: number) { diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index e4c9c09..41d524e 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -24,8 +24,8 @@ interface TxbInput { redeemScript?: Buffer redeemScriptType?: string prevOutType?: string - pubkeys?: Array - signatures?: Array + pubkeys?: Array | Array + signatures?: Array | Array witness?: Array witnessScript?: Buffer witnessScriptType?: string @@ -38,7 +38,7 @@ interface TxbInput { interface TxbOutput { type: string pubkeys?: Array - signatures?: Array + signatures?: Array | Array maxSignatures?: number } @@ -57,7 +57,7 @@ export class TransactionBuilder { private __inputs: Array private __tx: Transaction - constructor (network: Network, maximumFeeRate?: number) { + constructor (network?: Network, maximumFeeRate?: number) { this.__prevTxSet = {} this.network = network || networks.bitcoin @@ -125,7 +125,7 @@ export class TransactionBuilder { throw new Error('No, this would invalidate signatures') } - let value: number + let value: number | undefined = undefined // is it a hex string? if (txIsString(txHash)) { @@ -225,7 +225,7 @@ export class TransactionBuilder { this.__inputs.forEach((input, i) => { if (!input.prevOutType && !allowIncomplete) throw new Error('Transaction is not complete') - const result = build(input.prevOutType, input, allowIncomplete) + const result = build(input.prevOutType, input, allowIncomplete) if (!result) { if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) throw new Error('Unknown input type') if (!allowIncomplete) throw new Error('Not enough information') @@ -263,7 +263,7 @@ export class TransactionBuilder { throw new Error('Inconsistent redeemScript') } - const ourPubKey = keyPair.publicKey || keyPair.getPublicKey() + const ourPubKey = keyPair.publicKey || (<()=>Buffer>keyPair.getPublicKey)() if (!canSign(input)) { if (witnessValue !== undefined) { if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue') @@ -284,15 +284,15 @@ export class TransactionBuilder { // ready to sign let signatureHash: Buffer if (input.hasWitness) { - signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) + signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) } else { - signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType) + signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType) } // enforce in order signing of public keys - const signed = input.pubkeys.some((pubKey, i) => { + const signed = (>input.pubkeys).some((pubKey, i) => { if (!ourPubKey.equals(pubKey)) return false - if (input.signatures[i]) throw new Error('Signature already exists') + if ((>input.signatures)[i]) throw new Error('Signature already exists') // TODO: add tests if (ourPubKey.length !== 33 && input.hasWitness) { @@ -300,7 +300,7 @@ export class TransactionBuilder { } const signature = keyPair.sign(signatureHash) - input.signatures[i] = bscript.signature.encode(signature, hashType) + ;(>input.signatures)[i] = bscript.signature.encode(signature, hashType) return true }) @@ -348,7 +348,7 @@ export class TransactionBuilder { return this.__inputs.every(input => { if (input.signatures === undefined) return true - return input.signatures.every(signature => { + return input.signatures.every(<(signature: Buffer | undefined)=>boolean>(signature => { if (!signature) return true const hashType = signatureHashType(signature) @@ -360,13 +360,13 @@ export class TransactionBuilder { // of more outputs return nInputs <= nOutputs } - }) + })) }) } private __overMaximumFees (bytes: number): boolean { // not all inputs will have .value defined - const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0) + const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0) // but all outputs do, and if we have any input value // we can immediately determine if the outputs are too small @@ -493,13 +493,13 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str // could be done in expandInput, but requires the original Transaction for hashForSignature function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: number): void { if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return - if (input.pubkeys.length === input.signatures.length) return + if ((>input.pubkeys).length === (>input.signatures).length) return - const unmatched = input.signatures.concat() + const unmatched = (>input.signatures).concat() - input.signatures = input.pubkeys.map(pubKey => { + input.signatures = >(>input.pubkeys).map(pubKey => { const keyPair = ECPair.fromPublicKey(pubKey) - let match + let match: Buffer | undefined // check for a signature unmatched.some((signature, i) => { @@ -508,7 +508,7 @@ function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: numbe // TODO: avoid O(n) hashForSignature const parsed = bscript.signature.decode(signature) - const hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType) + const hash = transaction.hashForSignature(vin, (input.redeemScript), parsed.hashType) // skip if signature does not match pubKey if (!keyPair.verify(hash, parsed.signature)) return false @@ -740,7 +740,7 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, } } -function build (type: string, input: TxbInput, allowIncomplete: boolean): any { //TODO payment type +function build (type: string, input: TxbInput, allowIncomplete?: boolean): any { //TODO payment type const pubkeys = input.pubkeys || [] let signatures = input.signatures || [] @@ -777,7 +777,7 @@ function build (type: string, input: TxbInput, allowIncomplete: boolean): any { return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }) } case SCRIPT_TYPES.P2SH: { - const redeem = build(input.redeemScriptType, input, allowIncomplete) + const redeem = build(input.redeemScriptType, input, allowIncomplete) if (!redeem) return return payments.p2sh({ @@ -789,7 +789,7 @@ function build (type: string, input: TxbInput, allowIncomplete: boolean): any { }) } case SCRIPT_TYPES.P2WSH: { - const redeem = build(input.witnessScriptType, input, allowIncomplete) + const redeem = build(input.witnessScriptType, input, allowIncomplete) if (!redeem) return return payments.p2wsh({ diff --git a/tsconfig.json b/tsconfig.json index f8bd5e2..cfc286a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,12 +10,12 @@ "allowJs": false, "strict": false, "noImplicitAny": true, - "strictNullChecks": false, + "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, "strictPropertyInitialization": false, - "noImplicitThis": false, - "alwaysStrict": false, + "noImplicitThis": true, + "alwaysStrict": true, "esModuleInterop": true }, "include": [ From 9955c3c082b1c34d068167cfbfe5479fdc62f60b Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 10:35:57 +0900 Subject: [PATCH 078/183] Add strictPropertyInitialization --- src/block.ts | 22 +++++++++++++--------- tsconfig.json | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/block.ts b/src/block.ts index 03ff901..6440d8a 100644 --- a/src/block.ts +++ b/src/block.ts @@ -24,19 +24,23 @@ function txesHaveWitness (transactions: Array): boolean { export class Block { version: number - prevHash: Buffer - merkleRoot: Buffer + prevHash?: Buffer + merkleRoot?: Buffer timestamp: number - witnessCommit: Buffer + witnessCommit?: Buffer bits: number nonce: number - transactions: Array + transactions?: Array constructor () { this.version = 1 this.timestamp = 0 this.bits = 0 this.nonce = 0 + this.prevHash = undefined + this.merkleRoot = undefined + this.witnessCommit = undefined + this.transactions = undefined } static fromBuffer (buffer: Buffer): Block { @@ -134,7 +138,7 @@ export class Block { } hasWitnessCommit (): boolean { - return txesHaveWitness(this.transactions) + return txesHaveWitness(>this.transactions) } byteLength (headersOnly: boolean): number { @@ -179,8 +183,8 @@ export class Block { } writeInt32(this.version) - writeSlice(this.prevHash) - writeSlice(this.merkleRoot) + writeSlice(this.prevHash) + writeSlice(this.merkleRoot) writeUInt32(this.timestamp) writeUInt32(this.bits) writeUInt32(this.nonce) @@ -207,7 +211,7 @@ export class Block { if (!this.transactions) throw errorMerkleNoTxes const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) - return this.merkleRoot.compare(actualMerkleRoot) === 0 + return (this.merkleRoot).compare(actualMerkleRoot) === 0 } checkWitnessCommit (): boolean { @@ -215,7 +219,7 @@ export class Block { if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true) - return this.witnessCommit.compare(actualWitnessCommit) === 0 + return (this.witnessCommit).compare(actualWitnessCommit) === 0 } checkProofOfWork (): boolean { diff --git a/tsconfig.json b/tsconfig.json index cfc286a..fd2d954 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, - "strictPropertyInitialization": false, + "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, "esModuleInterop": true From 180f9ec958ce828e19b4554bf5d0c3bd4be5ecd1 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 10:38:22 +0900 Subject: [PATCH 079/183] Enable strict (HUZZAH\!) --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index fd2d954..b7e8c8e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,7 @@ "node" ], "allowJs": false, - "strict": false, + "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, From a7735ce07737e546149e1279c8ffa775128e1023 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 10:45:28 +0900 Subject: [PATCH 080/183] Match coverage targets with current level --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55454bc..130d644 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 80 --functions 80 --lines 80 mocha", + "coverage": "nyc --check-coverage --branches 83 --functions 90 --lines 89 mocha", "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", From 1aaba64acc354ac922fa0ec96c1920e48c250215 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 10:49:28 +0900 Subject: [PATCH 081/183] esModuleInterop was causing low coverage --- package.json | 2 +- tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 130d644..ceb96de 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 83 --functions 90 --lines 89 mocha", + "coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", "integration": "npm run build && mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run build && npm run standard && npm run coverage", diff --git a/tsconfig.json b/tsconfig.json index b7e8c8e..1d68be9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, - "esModuleInterop": true + "esModuleInterop": false }, "include": [ "src/**/*" From 44d88fcfb3670200c8d2e864f931b53b707a7f54 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 11:10:25 +0900 Subject: [PATCH 082/183] Clean up scripts and add postinstall for installing via git --- package.json | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index ceb96de..0a09c44 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "4.0.2", "description": "Client-side Bitcoin JavaScript library", "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", "engines": { "node": ">=8.0.0" }, @@ -14,14 +15,21 @@ "bitcoinjs" ], "scripts": { - "coverage-report": "nyc report --reporter=lcov", - "coverage-html": "nyc report --reporter=html", - "coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", - "integration": "npm run build && mocha --timeout 50000 test/integration/", - "standard": "standard", - "test": "npm run build && npm run standard && npm run coverage", - "unit": "npm run build && mocha", - "build": "tsc -d -p tsconfig.json" + "build": "tsc -d -p ./tsconfig.json", + "coverage-report": "npm run build && npm run nobuild:coverage-report", + "coverage-html": "npm run build && npm run nobuild:coverage-html", + "coverage": "npm run build && npm run nobuild:coverage", + "integration": "npm run build && npm run nobuild:integration", + "nobuild:coverage-report": "nyc report --reporter=lcov", + "nobuild:coverage-html": "nyc report --reporter=html", + "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", + "nobuild:integration": "mocha --timeout 50000 test/integration/", + "nobuild:standard": "standard", + "nobuild:unit": "mocha", + "prepare": "npm run build", + "standard": "npm run build && npm run nobuild:standard", + "test": "npm run build && npm run nobuild:standard && npm run nobuild:coverage", + "unit": "npm run build && npm run nobuild:unit" }, "repository": { "type": "git", @@ -31,6 +39,7 @@ "dist/src" ], "dependencies": { + "@types/node": "^10.12.18", "bech32": "^1.1.2", "bip32": "^1.0.0", "bip66": "^1.1.0", @@ -44,11 +53,11 @@ "safe-buffer": "^5.1.1", "tiny-secp256k1": "^1.0.0", "typeforce": "^1.11.3", + "typescript": "^3.2.2", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" }, "devDependencies": { - "@types/node": "^10.12.18", "bip39": "^2.3.0", "bip65": "^1.0.1", "bip68": "^1.0.3", @@ -60,8 +69,7 @@ "mocha": "^5.2.0", "nyc": "^11.8.0", "proxyquire": "^2.0.1", - "standard": "^11.0.1", - "typescript": "^3.2.2" + "standard": "^11.0.1" }, "license": "MIT" } From c17cdce348db972f2673c9cb203e3b7db69dfa0e Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 16:10:36 +0900 Subject: [PATCH 083/183] Move all imports to modules where possible --- src/address.ts | 22 +++++----- src/block.ts | 2 +- src/classify.ts | 22 +++++----- src/ecpair.ts | 10 ++--- src/payments/embed.ts | 2 +- src/payments/p2ms.ts | 4 +- src/payments/p2pk.ts | 2 +- src/payments/p2pkh.ts | 2 +- src/payments/p2sh.ts | 2 +- src/payments/p2wpkh.ts | 2 +- src/payments/p2wsh.ts | 2 +- src/script.ts | 7 ++-- src/transaction.ts | 4 +- src/transaction_builder.ts | 85 +++++++++++++++++++------------------- 14 files changed, 85 insertions(+), 83 deletions(-) diff --git a/src/address.ts b/src/address.ts index c9ffeeb..1e5e547 100644 --- a/src/address.ts +++ b/src/address.ts @@ -1,13 +1,13 @@ import * as Networks from './networks' import { Network } from './networks' import * as types from './types' +import * as bscript from './script' +import * as networks from './networks' +import * as payments from './payments' const Buffer = require('safe-buffer').Buffer const bech32 = require('bech32') const bs58check = require('bs58check') -const bscript = require('./script') -const networks = require('./networks') const typeforce = require('typeforce') -const payments = require('./payments') export type Base58CheckResult = { hash: Buffer; @@ -64,10 +64,10 @@ export function toBech32 (data: Buffer, version: number, prefix: string): string export function fromOutputScript (output: Buffer, network: Network): string { //TODO: Network network = network || networks.bitcoin - try { return payments.p2pkh({ output, network }).address } catch (e) {} - try { return payments.p2sh({ output, network }).address } catch (e) {} - try { return payments.p2wpkh({ output, network }).address } catch (e) {} - try { return payments.p2wsh({ output, network }).address } catch (e) {} + try { return payments.p2pkh({ output, network }).address } catch (e) {} + try { return payments.p2sh({ output, network }).address } catch (e) {} + try { return payments.p2wpkh({ output, network }).address } catch (e) {} + try { return payments.p2wsh({ output, network }).address } catch (e) {} throw new Error(bscript.toASM(output) + ' has no matching Address') } @@ -82,8 +82,8 @@ export function toOutputScript (address: string, network: Network): Buffer { } catch (e) {} if (decodeBase58) { - if (decodeBase58.version === network.pubKeyHash) return payments.p2pkh({ hash: decodeBase58.hash }).output - if (decodeBase58.version === network.scriptHash) return payments.p2sh({ hash: decodeBase58.hash }).output + if (decodeBase58.version === network.pubKeyHash) return payments.p2pkh({ hash: decodeBase58.hash }).output + if (decodeBase58.version === network.scriptHash) return payments.p2sh({ hash: decodeBase58.hash }).output } else { try { decodeBech32 = fromBech32(address) @@ -92,8 +92,8 @@ export function toOutputScript (address: string, network: Network): Buffer { if (decodeBech32) { if (decodeBech32.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix') if (decodeBech32.version === 0) { - if (decodeBech32.data.length === 20) return payments.p2wpkh({ hash: decodeBech32.data }).output - if (decodeBech32.data.length === 32) return payments.p2wsh({ hash: decodeBech32.data }).output + if (decodeBech32.data.length === 20) return payments.p2wpkh({ hash: decodeBech32.data }).output + if (decodeBech32.data.length === 32) return payments.p2wsh({ hash: decodeBech32.data }).output } } } diff --git a/src/block.ts b/src/block.ts index 6440d8a..f91ad32 100644 --- a/src/block.ts +++ b/src/block.ts @@ -1,7 +1,7 @@ import { Transaction } from './transaction' import * as types from './types' +import * as bcrypto from './crypto' const Buffer = require('safe-buffer').Buffer -const bcrypto = require('./crypto') const fastMerkleRoot = require('merkle-lib/fastRoot') const typeforce = require('typeforce') const varuint = require('varuint-bitcoin') diff --git a/src/classify.ts b/src/classify.ts index 5eabc7e..9a5c849 100644 --- a/src/classify.ts +++ b/src/classify.ts @@ -1,12 +1,12 @@ -const decompile = require('./script').decompile -const multisig = require('./templates/multisig') -const nullData = require('./templates/nulldata') -const pubKey = require('./templates/pubkey') -const pubKeyHash = require('./templates/pubkeyhash') -const scriptHash = require('./templates/scripthash') -const witnessPubKeyHash = require('./templates/witnesspubkeyhash') -const witnessScriptHash = require('./templates/witnessscripthash') -const witnessCommitment = require('./templates/witnesscommitment') +import { decompile } from './script' +import * as multisig from './templates/multisig' +import * as nullData from './templates/nulldata' +import * as pubKey from './templates/pubkey' +import * as pubKeyHash from './templates/pubkeyhash' +import * as scriptHash from './templates/scripthash' +import * as witnessPubKeyHash from './templates/witnesspubkeyhash' +import * as witnessScriptHash from './templates/witnessscripthash' +import * as witnessCommitment from './templates/witnesscommitment' const types = { P2MS: 'multisig', @@ -51,13 +51,13 @@ function classifyInput (script: Buffer, allowIncomplete: boolean): string { return types.NONSTANDARD } -function classifyWitness (script: Buffer, allowIncomplete: boolean): string { +function classifyWitness (script: Array, allowIncomplete: boolean): string { // XXX: optimization, below functions .decompile before use const chunks = decompile(script) if (!chunks) throw new TypeError('Invalid script') if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH - if (witnessScriptHash.input.check(chunks, allowIncomplete)) return types.P2WSH + if (witnessScriptHash.input.check(>chunks, allowIncomplete)) return types.P2WSH return types.NONSTANDARD } diff --git a/src/ecpair.ts b/src/ecpair.ts index a7426ae..9a54b1a 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -67,18 +67,18 @@ class ECPair implements ECPairInterface { } } -function fromPrivateKey (buffer: Buffer, options: ECPairOptions): ECPair { +function fromPrivateKey (buffer: Buffer, options?: ECPairOptions): ECPair { typeforce(types.Buffer256bit, buffer) if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)') typeforce(isOptions, options) - return new ECPair(buffer, null, options) + return new ECPair(buffer, null, options) } -function fromPublicKey (buffer: Buffer, options: ECPairOptions): ECPair { +function fromPublicKey (buffer: Buffer, options?: ECPairOptions): ECPair { typeforce(ecc.isPoint, buffer) typeforce(isOptions, options) - return new ECPair(null, buffer, options) + return new ECPair(null, buffer, options) } function fromWIF (string: string, network: Network | Array): ECPair { @@ -106,7 +106,7 @@ function fromWIF (string: string, network: Network | Array): ECPair { }) } -function makeRandom (options: ECPairOptions): ECPair { +function makeRandom (options?: ECPairOptions): ECPair { typeforce(isOptions, options) if (options === undefined) options = {} const rng = options.rng || randomBytes diff --git a/src/payments/embed.ts b/src/payments/embed.ts index 2526fe0..8d198a0 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -14,7 +14,7 @@ function stacksEqual (a: Array, b: Array): boolean { } // output: OP_RETURN ... -export function p2data (a: Payment, opts: PaymentOpts): Payment { +export function p2data (a: Payment, opts?: PaymentOpts): Payment { if ( !a.data && !a.output diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index b8a05b3..37701a5 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -18,7 +18,7 @@ function stacksEqual (a: Array, b: Array): boolean { // input: OP_0 [signatures ...] // output: m [pubKeys ...] n OP_CHECKMULTISIG -export function p2ms (a: Payment, opts: PaymentOpts): Payment { +export function p2ms (a: Payment, opts?: PaymentOpts): Payment { if ( !a.input && !a.output && @@ -28,7 +28,7 @@ export function p2ms (a: Payment, opts: PaymentOpts): Payment { opts = Object.assign({ validate: true }, opts || {}) function isAcceptableSignature (x: Buffer | number) { - return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) !== undefined + return bscript.isCanonicalScriptSignature(x) || ((opts).allowIncomplete && (x === OPS.OP_0)) !== undefined } typef({ diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index 45b3577..99b25d2 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -8,7 +8,7 @@ const ecc = require('tiny-secp256k1') // input: {signature} // output: {pubKey} OP_CHECKSIG -export function p2pk (a: Payment, opts: PaymentOpts): Payment { +export function p2pk (a: Payment, opts?: PaymentOpts): Payment { if ( !a.input && !a.output && diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index f2054b0..53c452f 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -11,7 +11,7 @@ const bs58check = require('bs58check') // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG -export function p2pkh (a: Payment, opts: PaymentOpts): Payment { +export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { if ( !a.address && !a.hash && diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index 6facde9..dfbee4c 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -20,7 +20,7 @@ function stacksEqual (a: Array, b: Array): boolean { // input: [redeemScriptSig ...] {redeemScript} // witness: // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL -export function p2sh (a: Payment, opts: PaymentOpts): Payment { +export function p2sh (a: Payment, opts?: PaymentOpts): Payment { if ( !a.address && !a.hash && diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index 7089246..96c367b 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -14,7 +14,7 @@ const EMPTY_BUFFER = Buffer.alloc(0) // witness: {signature} {pubKey} // input: <> // output: OP_0 {pubKeyHash} -export function p2wpkh (a: Payment, opts: PaymentOpts): Payment { +export function p2wpkh (a: Payment, opts?: PaymentOpts): Payment { if ( !a.address && !a.hash && diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index c70cfb6..b151b82 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -22,7 +22,7 @@ function stacksEqual (a: Array, b: Array): boolean { // input: <> // witness: [redeemScriptSig ...] {redeemScript} // output: OP_0 {sha256(redeemScript)} -export function p2wsh (a: Payment, opts: PaymentOpts): Payment { +export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { if ( !a.address && !a.hash && diff --git a/src/script.ts b/src/script.ts index 6d9bfc9..190c9cd 100644 --- a/src/script.ts +++ b/src/script.ts @@ -1,10 +1,11 @@ import * as types from './types' +import * as scriptNumber from './script_number' +import * as scriptSignature from './script_signature' const Buffer = require('safe-buffer').Buffer const bip66 = require('bip66') const ecc = require('tiny-secp256k1') const pushdata = require('pushdata-bitcoin') const typeforce = require('typeforce') -const scriptNumber = require('./script_number') const OPS = require('bitcoin-ops') const REVERSE_OPS = require('bitcoin-ops/map') @@ -200,5 +201,5 @@ export function isCanonicalScriptSignature (buffer: Buffer): boolean { return bip66.check(buffer.slice(0, -1)) } -export const number = require('./script_number') -export const signature = require('./script_signature') +export const number = scriptNumber +export const signature = scriptSignature diff --git a/src/transaction.ts b/src/transaction.ts index af17449..b40e368 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -1,8 +1,8 @@ import * as bcrypto from './crypto' import * as bscript from './script' import * as types from './types' +import * as bufferutils from './bufferutils' const Buffer = require('safe-buffer').Buffer -const bufferutils = require('./bufferutils') const opcodes = require('bitcoin-ops') const typeforce = require('typeforce') const varuint = require('varuint-bitcoin') @@ -491,7 +491,7 @@ export class Transaction { } function writeUInt64 (i: number) { - offset = bufferutils.writeUInt64LE(buffer, i, offset) + offset = bufferutils.writeUInt64LE(buffer, i, offset) } function writeVarInt (i: number) { diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index 41d524e..a6b3b48 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -2,18 +2,19 @@ import { Network } from './networks' import * as networks from './networks' import { Transaction, Output } from './transaction' import { ECPairInterface } from './ecpair' +import * as ECPair from './ecpair' import * as types from './types' -const Buffer = require('safe-buffer').Buffer -const baddress = require('./address') -const bcrypto = require('./crypto') -const bscript = require('./script') +import * as baddress from './address' +import * as bcrypto from './crypto' +import * as bscript from './script' +import { Payment } from './payments' +import * as payments from './payments' +import * as classify from './classify' const ops = require('bitcoin-ops') -const payments = require('./payments') const typeforce = require('typeforce') -const classify = require('./classify') +const Buffer = require('safe-buffer').Buffer const SCRIPT_TYPES = classify.types -const ECPair = require('./ecpair') interface TxbInput { value?: number @@ -24,7 +25,7 @@ interface TxbInput { redeemScript?: Buffer redeemScriptType?: string prevOutType?: string - pubkeys?: Array | Array + pubkeys?: Array signatures?: Array | Array witness?: Array witnessScript?: Buffer @@ -37,7 +38,7 @@ interface TxbInput { interface TxbOutput { type: string - pubkeys?: Array + pubkeys?: Array signatures?: Array | Array maxSignatures?: number } @@ -232,8 +233,8 @@ export class TransactionBuilder { return } - tx.setInputScript(i, result.input) - tx.setWitness(i, result.witness) + tx.setInputScript(i, result.input) + tx.setWitness(i, >result.witness) }) if (!allowIncomplete) { @@ -381,8 +382,8 @@ export class TransactionBuilder { function expandInput (scriptSig: Buffer, witnessStack: Array, type?: string, scriptPubKey?: Buffer): TxbInput { if (scriptSig.length === 0 && witnessStack.length === 0) return {} if (!type) { - let ssType = classify.input(scriptSig, true) - let wsType = classify.witness(witnessStack, true) + let ssType: string | undefined = classify.input(scriptSig, true) + let wsType: string | undefined = classify.witness(witnessStack, true) if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined type = ssType || wsType @@ -442,14 +443,14 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str witness: witnessStack }) - const outputType = classify.output(redeem.output) - const expanded = expandInput(redeem.input, redeem.witness, outputType, redeem.output) + const outputType = classify.output((redeem).output) + const expanded = expandInput((redeem).input, >(redeem).witness, outputType, (redeem).output) if (!expanded.prevOutType) return {} return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2SH, - redeemScript: redeem.output, + redeemScript: (redeem).output, redeemScriptType: expanded.prevOutType, witnessScript: expanded.witnessScript, witnessScriptType: expanded.witnessScriptType, @@ -464,19 +465,19 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str input: scriptSig, witness: witnessStack }) - const outputType = classify.output(redeem.output) + const outputType = classify.output((redeem).output) let expanded if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput(redeem.input, redeem.witness, outputType) + expanded = expandInput((redeem).input, >(redeem).witness, outputType) } else { - expanded = expandInput(bscript.compile(redeem.witness), [], outputType, redeem.output) + expanded = expandInput(bscript.compile(>(redeem).witness), [], outputType, (redeem).output) } if (!expanded.prevOutType) return {} return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2WSH, - witnessScript: redeem.output, + witnessScript: (redeem).output, witnessScriptType: expanded.prevOutType, pubkeys: expanded.pubkeys, @@ -535,7 +536,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { // does our hash160(pubKey) match the output scripts? const pkh1 = payments.p2pkh({ output: script }).hash const pkh2 = bcrypto.hash160(ourPubKey) - if (!pkh1.equals(pkh2)) return { type } + if (!(pkh1).equals(pkh2)) return { type } return { type, @@ -550,7 +551,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { // does our hash160(pubKey) match the output scripts? const wpkh1 = payments.p2wpkh({ output: script }).hash const wpkh2 = bcrypto.hash160(ourPubKey) - if (!wpkh1.equals(wpkh2)) return { type } + if (!(wpkh1).equals(wpkh2)) return { type } return { type, @@ -573,7 +574,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { return { type, pubkeys: p2ms.pubkeys, - signatures: p2ms.pubkeys.map((): undefined => undefined), + signatures: (>p2ms.pubkeys).map((): undefined => undefined), maxSignatures: p2ms.m } } @@ -584,16 +585,16 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, witnessValue: number, witnessScript: Buffer): TxbInput { if (redeemScript && witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) - const p2wshAlt = payments.p2wsh({ output: redeemScript }) - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) - const p2shAlt = payments.p2sh({ redeem: p2wsh }) + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) + const p2wshAlt = payments.p2wsh({ output: redeemScript }) + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) + const p2shAlt = payments.p2sh({ redeem: p2wsh }) // enforces P2SH(P2WSH(...)) - if (!p2wsh.hash.equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') - if (!p2sh.hash.equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') + if (!(p2wsh.hash).equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') + if (!(p2sh.hash).equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') - const expanded = expandOutput(p2wsh.redeem.output, ourPubKey) + const expanded = expandOutput((p2wsh.redeem).output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -623,17 +624,17 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, } if (redeemScript) { - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) if (input.prevOutScript) { let p2shAlt try { - p2shAlt = payments.p2sh({ output: input.prevOutScript }) + p2shAlt = payments.p2sh({ output: input.prevOutScript }) } catch (e) { throw new Error('PrevOutScript must be P2SH') } - if (!p2sh.hash.equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') + if (!(p2sh.hash).equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') } - const expanded = expandOutput(p2sh.redeem.output, ourPubKey) + const expanded = expandOutput((p2sh.redeem).output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -641,7 +642,7 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, let signScript = redeemScript if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output } return { @@ -662,14 +663,14 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, } if (witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) if (input.prevOutScript) { const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }) - if (!p2wsh.hash.equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') + if (!(p2wsh.hash).equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') } - const expanded = expandOutput(p2wsh.redeem.output, ourPubKey) + const expanded = expandOutput((p2wsh.redeem).output, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -709,7 +710,7 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, let signScript = input.prevOutScript if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output } return { @@ -740,9 +741,9 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, } } -function build (type: string, input: TxbInput, allowIncomplete?: boolean): any { //TODO payment type - const pubkeys = input.pubkeys || [] - let signatures = input.signatures || [] +function build (type: string, input: TxbInput, allowIncomplete?: boolean): Payment | undefined { + const pubkeys = >(input.pubkeys || []) + let signatures = >(input.signatures || []) switch (type) { case SCRIPT_TYPES.P2PKH: { From 3124e50e52a1b9fcf7f3a986f2025cb95fcbbe4b Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 16:36:36 +0900 Subject: [PATCH 084/183] TypeScript hates Buffer.prototype.reverse, so fixed it. --- src/block.ts | 5 +++-- src/bufferutils.ts | 13 +++++++++++++ src/ecpair.ts | 14 ++++++++------ src/transaction.ts | 11 ++++++----- src/transaction_builder.ts | 3 ++- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/block.ts b/src/block.ts index f91ad32..d79de9d 100644 --- a/src/block.ts +++ b/src/block.ts @@ -1,6 +1,7 @@ import { Transaction } from './transaction' import * as types from './types' import * as bcrypto from './crypto' +import { reverseBuffer } from './bufferutils' const Buffer = require('safe-buffer').Buffer const fastMerkleRoot = require('merkle-lib/fastRoot') const typeforce = require('typeforce') @@ -153,7 +154,7 @@ export class Block { } getId (): string { - return Buffer.from(this.getHash().reverse()).toString('hex') + return reverseBuffer(this.getHash()).toString('hex') } getUTCDate (): Date { @@ -223,7 +224,7 @@ export class Block { } checkProofOfWork (): boolean { - const hash: Buffer = Buffer.from(this.getHash().reverse()) + const hash: Buffer = reverseBuffer(this.getHash()) const target = Block.calculateTarget(this.bits) return hash.compare(target) <= 0 diff --git a/src/bufferutils.ts b/src/bufferutils.ts index b66c84a..3ef7492 100644 --- a/src/bufferutils.ts +++ b/src/bufferutils.ts @@ -22,3 +22,16 @@ export function writeUInt64LE (buffer: Buffer, value: number, offset: number): n buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) return offset + 8 } + +export function reverseBuffer (buffer: Buffer): Buffer { + if (buffer.length < 1) return buffer + let j = buffer.length - 1 + let tmp = 0 + for (let i = 0; i < buffer.length / 2; i++) { + tmp = buffer[i] + buffer[i] = buffer[j] + buffer[j] = tmp + j-- + } + return buffer +} diff --git a/src/ecpair.ts b/src/ecpair.ts index 9a54b1a..321a5ed 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -33,14 +33,16 @@ class ECPair implements ECPairInterface { network: Network private __d: Buffer | null private __Q: Buffer | null - constructor (d: Buffer | null, Q: Buffer | null, options: ECPairOptions) { + + constructor (d?: Buffer, Q?: Buffer, options?: ECPairOptions) { if (options === undefined) options = {} this.compressed = options.compressed === undefined ? true : options.compressed this.network = options.network || NETWORKS.bitcoin - this.__d = d || null + this.__d = null this.__Q = null - if (Q) this.__Q = ecc.pointCompress(Q, this.compressed) + if (d !== undefined) this.__d = d + if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed) } get privateKey (): Buffer | null { @@ -72,16 +74,16 @@ function fromPrivateKey (buffer: Buffer, options?: ECPairOptions): ECPair { if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)') typeforce(isOptions, options) - return new ECPair(buffer, null, options) + return new ECPair(buffer, undefined, options) } function fromPublicKey (buffer: Buffer, options?: ECPairOptions): ECPair { typeforce(ecc.isPoint, buffer) typeforce(isOptions, options) - return new ECPair(null, buffer, options) + return new ECPair(undefined, buffer, options) } -function fromWIF (string: string, network: Network | Array): ECPair { +function fromWIF (string: string, network?: Network | Array): ECPair { const decoded = wif.decode(string) const version = decoded.version diff --git a/src/transaction.ts b/src/transaction.ts index b40e368..515ffb6 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -2,6 +2,7 @@ import * as bcrypto from './crypto' import * as bscript from './script' import * as types from './types' import * as bufferutils from './bufferutils' +import { reverseBuffer } from './bufferutils' const Buffer = require('safe-buffer').Buffer const opcodes = require('bitcoin-ops') const typeforce = require('typeforce') @@ -74,7 +75,7 @@ export class Transaction { this.outs = [] } - static fromBuffer (buffer: Buffer, __noStrict: boolean): Transaction { + static fromBuffer (buffer: Buffer, __noStrict?: boolean): Transaction { let offset: number = 0 function readSlice (n: number): Buffer { @@ -234,7 +235,7 @@ export class Transaction { return this.__byteLength(true) } - __byteLength (__allowWitness: boolean): number { + private __byteLength (__allowWitness: boolean): number { const hasWitnesses = __allowWitness && this.hasWitnesses() return ( @@ -454,7 +455,7 @@ export class Transaction { return bcrypto.hash256(tbuffer) } - getHash (forWitness: boolean): Buffer { + getHash (forWitness?: boolean): Buffer { // wtxid for coinbase is always 32 bytes of 0x00 if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0) return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)) @@ -462,14 +463,14 @@ export class Transaction { getId (): string { // transaction hash's are displayed in reverse order - return Buffer.from(this.getHash(false).reverse()).toString('hex') + return reverseBuffer(this.getHash(false)).toString('hex') } toBuffer (buffer?: Buffer, initialOffset?: number): Buffer { return this.__toBuffer(buffer, initialOffset, true) } - __toBuffer (buffer?: Buffer, initialOffset?: number, __allowWitness?: boolean): Buffer { + private __toBuffer (buffer?: Buffer, initialOffset?: number, __allowWitness?: boolean): Buffer { if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength((__allowWitness))) let offset = initialOffset || 0 diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index a6b3b48..a920130 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -1,5 +1,6 @@ import { Network } from './networks' import * as networks from './networks' +import { reverseBuffer } from './bufferutils' import { Transaction, Output } from './transaction' import { ECPairInterface } from './ecpair' import * as ECPair from './ecpair' @@ -131,7 +132,7 @@ export class TransactionBuilder { // is it a hex string? if (txIsString(txHash)) { // transaction hashs's are displayed in reverse order, un-reverse it - txHash = Buffer.from(txHash, 'hex').reverse() + txHash = reverseBuffer(Buffer.from(txHash, 'hex')) // is it a Transaction object? } else if (txIsTransaction(txHash)) { From 912d6d41becf3b4b77b00038c481d71b34c64b2e Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 17:02:32 +0900 Subject: [PATCH 085/183] Fix some small bugs --- src/payments/p2ms.js | 2 +- src/transaction_builder.js | 4 ++-- test/fixtures/p2ms.json | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index 5c90a4d..8c5a380 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -129,7 +129,7 @@ function p2ms (a, opts) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - if (a.signatures && !stacksEqual(a.signatures.equals(o.signatures))) throw new TypeError('Signature mismatch') + if (a.signatures && !stacksEqual(a.signatures, o.signatures)) throw new TypeError('Signature mismatch') if (a.m !== undefined && a.m !== a.signatures.length) throw new TypeError('Signature count mismatch') } } diff --git a/src/transaction_builder.js b/src/transaction_builder.js index bea1ded..6508a86 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -217,7 +217,7 @@ function expandOutput (script, ourPubKey) { return { type } } -function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScript) { +function prepareInput (input, ourPubKey, redeemScript, witnessScript) { if (redeemScript && witnessScript) { const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) const p2wshAlt = payments.p2wsh({ output: redeemScript }) @@ -665,7 +665,7 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy } if (!canSign(input)) { - const prepared = prepareInput(input, ourPubKey, redeemScript, witnessValue, witnessScript) + const prepared = prepareInput(input, ourPubKey, redeemScript, witnessScript) // updates inline Object.assign(input, prepared) diff --git a/test/fixtures/p2ms.json b/test/fixtures/p2ms.json index 8ea033e..2f41270 100644 --- a/test/fixtures/p2ms.json +++ b/test/fixtures/p2ms.json @@ -310,6 +310,20 @@ ] } }, + { + "exception": "Signature mismatch", + "arguments": { + "m": 1, + "pubkeys": [ + "030000000000000000000000000000000000000000000000000000000000000001", + "030000000000000000000000000000000000000000000000000000000000000001" + ], + "signatures": [ + "300602010002010001" + ], + "input": "OP_0 300602010002010101" + } + }, { "exception": "Too many signatures provided", "arguments": { From e58d0126159f2da6fb85128c84c46d7de16fa969 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 21:39:19 +0900 Subject: [PATCH 086/183] Remove safe-buffer and add type to bitcoin-ops --- package.json | 1 - src/address.ts | 2 +- src/block.ts | 2 +- src/index.ts | 2 +- src/payments/embed.ts | 4 ++-- src/payments/p2ms.ts | 4 ++-- src/payments/p2pk.ts | 2 +- src/payments/p2pkh.ts | 2 +- src/payments/p2sh.ts | 2 +- src/payments/p2wpkh.ts | 2 +- src/payments/p2wsh.ts | 2 +- src/script.ts | 7 ++++--- src/script_number.ts | 2 +- src/script_signature.ts | 2 +- src/templates/multisig/input.ts | 2 +- src/templates/multisig/output.ts | 2 +- src/templates/nulldata.ts | 2 +- src/templates/pubkey/output.ts | 2 +- src/templates/pubkeyhash/output.ts | 2 +- src/templates/scripthash/input.ts | 2 +- src/templates/scripthash/output.ts | 2 +- src/templates/witnesscommitment/output.ts | 4 ++-- src/templates/witnesspubkeyhash/output.ts | 2 +- src/templates/witnessscripthash/output.ts | 2 +- src/transaction.ts | 4 ++-- src/transaction_builder.ts | 4 ++-- 26 files changed, 33 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 0a09c44..4b9557e 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "merkle-lib": "^2.0.10", "pushdata-bitcoin": "^1.0.1", "randombytes": "^2.0.1", - "safe-buffer": "^5.1.1", "tiny-secp256k1": "^1.0.0", "typeforce": "^1.11.3", "typescript": "^3.2.2", diff --git a/src/address.ts b/src/address.ts index 1e5e547..7d9d351 100644 --- a/src/address.ts +++ b/src/address.ts @@ -4,7 +4,7 @@ import * as types from './types' import * as bscript from './script' import * as networks from './networks' import * as payments from './payments' -const Buffer = require('safe-buffer').Buffer + const bech32 = require('bech32') const bs58check = require('bs58check') const typeforce = require('typeforce') diff --git a/src/block.ts b/src/block.ts index d79de9d..1483f2c 100644 --- a/src/block.ts +++ b/src/block.ts @@ -2,7 +2,7 @@ import { Transaction } from './transaction' import * as types from './types' import * as bcrypto from './crypto' import { reverseBuffer } from './bufferutils' -const Buffer = require('safe-buffer').Buffer + const fastMerkleRoot = require('merkle-lib/fastRoot') const typeforce = require('typeforce') const varuint = require('varuint-bitcoin') diff --git a/src/index.ts b/src/index.ts index d93f587..31ef042 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -const opcodes = require('bitcoin-ops') const bip32 = require('bip32') import { Block } from './block' @@ -10,6 +9,7 @@ import * as crypto from './crypto' import * as networks from './networks' import * as payments from './payments' import * as script from './script' +import { OPS as opcodes } from './script' export { Block, diff --git a/src/payments/embed.ts b/src/payments/embed.ts index 8d198a0..7e82511 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -3,7 +3,7 @@ import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false @@ -32,7 +32,7 @@ export function p2data (a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'output', function () { if (!a.data) return - return bscript.compile([OPS.OP_RETURN].concat(a.data)) + return bscript.compile((>[OPS.OP_RETURN]).concat(a.data)) }) lazy.prop(o, 'data', function () { if (!a.output) return diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index 37701a5..3c5c679 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -3,7 +3,7 @@ import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const ecc = require('tiny-secp256k1') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 @@ -87,7 +87,7 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { }) lazy.prop(o, 'input', function () { if (!a.signatures) return - return bscript.compile([OPS.OP_0].concat(a.signatures)) + return bscript.compile((>[OPS.OP_0]).concat(a.signatures)) }) lazy.prop(o, 'witness', function () { if (!o.input) return diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index 99b25d2..f383a1c 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -3,7 +3,7 @@ import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const ecc = require('tiny-secp256k1') // input: {signature} diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index 53c452f..4fb49de 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -4,7 +4,7 @@ import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const ecc = require('tiny-secp256k1') const bs58check = require('bs58check') diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index dfbee4c..d25b616 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -5,7 +5,7 @@ import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const bs58check = require('bs58check') diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index 96c367b..918e909 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -4,7 +4,7 @@ import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const ecc = require('tiny-secp256k1') const bech32 = require('bech32') diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index b151b82..1a8e86e 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -5,7 +5,7 @@ import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../script' const bech32 = require('bech32') diff --git a/src/script.ts b/src/script.ts index 190c9cd..79e3342 100644 --- a/src/script.ts +++ b/src/script.ts @@ -1,14 +1,15 @@ import * as types from './types' import * as scriptNumber from './script_number' import * as scriptSignature from './script_signature' -const Buffer = require('safe-buffer').Buffer const bip66 = require('bip66') const ecc = require('tiny-secp256k1') const pushdata = require('pushdata-bitcoin') const typeforce = require('typeforce') -const OPS = require('bitcoin-ops') -const REVERSE_OPS = require('bitcoin-ops/map') +export type OpCode = number +export const OPS = <{[index:string]: OpCode}> require('bitcoin-ops') + +const REVERSE_OPS = <{[index:number]: string}> require('bitcoin-ops/map') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 function isOPInt (value:number): boolean { diff --git a/src/script_number.ts b/src/script_number.ts index 0ff4a7e..d88c463 100644 --- a/src/script_number.ts +++ b/src/script_number.ts @@ -1,4 +1,4 @@ -const Buffer = require('safe-buffer').Buffer + export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): number { maxLength = maxLength || 4 diff --git a/src/script_signature.ts b/src/script_signature.ts index c24e88a..3b5bc6e 100644 --- a/src/script_signature.ts +++ b/src/script_signature.ts @@ -1,6 +1,6 @@ import * as types from './types' const bip66 = require('bip66') -const Buffer = require('safe-buffer').Buffer + const typeforce = require('typeforce') const ZERO = Buffer.alloc(1, 0) diff --git a/src/templates/multisig/input.ts b/src/templates/multisig/input.ts index abf0982..1ec2874 100644 --- a/src/templates/multisig/input.ts +++ b/src/templates/multisig/input.ts @@ -1,7 +1,7 @@ // OP_0 [signatures ...] import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' function partialSignature (value: number | Buffer): boolean { return value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) diff --git a/src/templates/multisig/output.ts b/src/templates/multisig/output.ts index e4fa333..e46fa78 100644 --- a/src/templates/multisig/output.ts +++ b/src/templates/multisig/output.ts @@ -2,7 +2,7 @@ import * as bscript from '../../script' import * as types from '../../types' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { diff --git a/src/templates/nulldata.ts b/src/templates/nulldata.ts index 91c1713..8889fb9 100644 --- a/src/templates/nulldata.ts +++ b/src/templates/nulldata.ts @@ -1,6 +1,6 @@ // OP_RETURN {data} import * as bscript from '../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../script' export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) diff --git a/src/templates/pubkey/output.ts b/src/templates/pubkey/output.ts index f60cc05..aa321b3 100644 --- a/src/templates/pubkey/output.ts +++ b/src/templates/pubkey/output.ts @@ -1,7 +1,7 @@ // {pubKey} OP_CHECKSIG import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' export function check (script: Buffer | Array): boolean { const chunks = >bscript.decompile(script) diff --git a/src/templates/pubkeyhash/output.ts b/src/templates/pubkeyhash/output.ts index 71c1acb..242cb0e 100644 --- a/src/templates/pubkeyhash/output.ts +++ b/src/templates/pubkeyhash/output.ts @@ -1,7 +1,7 @@ // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) diff --git a/src/templates/scripthash/input.ts b/src/templates/scripthash/input.ts index 93e7d58..90af0fe 100644 --- a/src/templates/scripthash/input.ts +++ b/src/templates/scripthash/input.ts @@ -7,7 +7,7 @@ import * as p2pkh from '../pubkeyhash' import * as p2wpkho from '../witnesspubkeyhash/output' import * as p2wsho from '../witnessscripthash/output' -const Buffer = require('safe-buffer').Buffer + export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { const chunks = >bscript.decompile(script) diff --git a/src/templates/scripthash/output.ts b/src/templates/scripthash/output.ts index 3215c25..0b968bf 100644 --- a/src/templates/scripthash/output.ts +++ b/src/templates/scripthash/output.ts @@ -1,7 +1,7 @@ // OP_HASH160 {scriptHash} OP_EQUAL import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) diff --git a/src/templates/witnesscommitment/output.ts b/src/templates/witnesscommitment/output.ts index d89b8e2..71e8df3 100644 --- a/src/templates/witnesscommitment/output.ts +++ b/src/templates/witnesscommitment/output.ts @@ -2,9 +2,9 @@ import * as bscript from '../../script' import * as types from '../../types' -const Buffer = require('safe-buffer').Buffer + const typeforce = require('typeforce') -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' const HEADER: Buffer = Buffer.from('aa21a9ed', 'hex') diff --git a/src/templates/witnesspubkeyhash/output.ts b/src/templates/witnesspubkeyhash/output.ts index 46fb444..bc7a3a0 100644 --- a/src/templates/witnesspubkeyhash/output.ts +++ b/src/templates/witnesspubkeyhash/output.ts @@ -1,7 +1,7 @@ // OP_0 {pubKeyHash} import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) diff --git a/src/templates/witnessscripthash/output.ts b/src/templates/witnessscripthash/output.ts index 0b13cd1..deffe1f 100644 --- a/src/templates/witnessscripthash/output.ts +++ b/src/templates/witnessscripthash/output.ts @@ -1,7 +1,7 @@ // OP_0 {scriptHash} import * as bscript from '../../script' -const OPS = require('bitcoin-ops') +import { OPS } from '../../script' export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) diff --git a/src/transaction.ts b/src/transaction.ts index 515ffb6..29b49c8 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -3,8 +3,8 @@ import * as bscript from './script' import * as types from './types' import * as bufferutils from './bufferutils' import { reverseBuffer } from './bufferutils' -const Buffer = require('safe-buffer').Buffer -const opcodes = require('bitcoin-ops') +import { OPS as opcodes } from './script' + const typeforce = require('typeforce') const varuint = require('varuint-bitcoin') diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index a920130..8977364 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -11,9 +11,9 @@ import * as bscript from './script' import { Payment } from './payments' import * as payments from './payments' import * as classify from './classify' -const ops = require('bitcoin-ops') +import { OPS as ops } from './script' const typeforce = require('typeforce') -const Buffer = require('safe-buffer').Buffer + const SCRIPT_TYPES = classify.types From 572fd159b0393e80bcc4bb29b5c6c3b82f691676 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 22:49:35 +0900 Subject: [PATCH 087/183] Added TypeScript standard linter to tests --- package.json | 14 +++++++++++--- src/block.ts | 2 +- src/payments/embed.ts | 4 ++-- src/payments/index.ts | 2 +- src/payments/lazy.ts | 2 +- src/payments/p2ms.ts | 18 ++++++++++-------- src/payments/p2pk.ts | 4 ++-- src/payments/p2pkh.ts | 6 +++--- src/payments/p2sh.ts | 7 +++---- src/payments/p2wpkh.ts | 6 +++--- src/payments/p2wsh.ts | 7 +++---- src/templates/nulldata.ts | 2 +- 12 files changed, 41 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 4b9557e..2d89027 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "nobuild:coverage-html": "nyc report --reporter=html", "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", "nobuild:integration": "mocha --timeout 50000 test/integration/", - "nobuild:standard": "standard", + "nobuild:standard": "standard src/**/*.ts", "nobuild:unit": "mocha", "prepare": "npm run build", "standard": "npm run build && npm run nobuild:standard", @@ -63,12 +63,20 @@ "bn.js": "^4.11.8", "bs58": "^4.0.0", "dhttp": "^3.0.0", + "eslint-plugin-typescript": "^0.14.0", "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", "nyc": "^11.8.0", "proxyquire": "^2.0.1", - "standard": "^11.0.1" + "standard": "^11.0.1", + "typescript-eslint-parser": "^21.0.2" }, - "license": "MIT" + "license": "MIT", + "standard": { + "parser": "typescript-eslint-parser", + "plugins": [ + "typescript" + ] + } } diff --git a/src/block.ts b/src/block.ts index 1483f2c..82700aa 100644 --- a/src/block.ts +++ b/src/block.ts @@ -124,7 +124,7 @@ export class Block { return target } - static calculateMerkleRoot (transactions: Array, forWitness: boolean | void): Buffer { + static calculateMerkleRoot (transactions: Array, forWitness?: boolean): Buffer { typeforce([{ getHash: types.Function }], transactions) if (transactions.length === 0) throw errorMerkleNoTxes if (forWitness && !txesHaveWitness(transactions)) throw errorWitnessNotSegwit diff --git a/src/payments/embed.ts b/src/payments/embed.ts index 7e82511..8cc8899 100644 --- a/src/payments/embed.ts +++ b/src/payments/embed.ts @@ -1,9 +1,9 @@ -import { Payment, PaymentOpts } from './index' +import { Payment, PaymentOpts } from './index' // eslint-disable-line import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS function stacksEqual (a: Array, b: Array): boolean { if (a.length !== b.length) return false diff --git a/src/payments/index.ts b/src/payments/index.ts index 08a8409..7fc72d8 100644 --- a/src/payments/index.ts +++ b/src/payments/index.ts @@ -1,4 +1,4 @@ -import { Network } from '../networks' +import { Network } from '../networks' // eslint-disable-line import { p2data as embed } from './embed' import { p2ms } from './p2ms' import { p2pk } from './p2pk' diff --git a/src/payments/lazy.ts b/src/payments/lazy.ts index 1d4af68..a6f0951 100644 --- a/src/payments/lazy.ts +++ b/src/payments/lazy.ts @@ -18,7 +18,7 @@ export function prop (object: Object, name: string, f: ()=>any): void { }) } -export function value (f: ()=>T): ()=>T { +export function value (f: ()=>T): ()=>T { let value: T return function (): T { if (value !== undefined) return value diff --git a/src/payments/p2ms.ts b/src/payments/p2ms.ts index 3c5c679..67b9692 100644 --- a/src/payments/p2ms.ts +++ b/src/payments/p2ms.ts @@ -1,9 +1,9 @@ -import { Payment, PaymentOpts } from './index' +import { Payment, PaymentOpts } from './index' // eslint-disable-line import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' +const OPS = bscript.OPS const typef = require('typeforce') -import { OPS } from '../script' const ecc = require('tiny-secp256k1') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 @@ -28,7 +28,9 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { opts = Object.assign({ validate: true }, opts || {}) function isAcceptableSignature (x: Buffer | number) { - return bscript.isCanonicalScriptSignature(x) || ((opts).allowIncomplete && (x === OPS.OP_0)) !== undefined + return bscript.isCanonicalScriptSignature(x) || + ((opts).allowIncomplete && + ( x === OPS.OP_0)) !== undefined // eslint-disable-line } typef({ @@ -51,8 +53,8 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { if (decoded) return decoded = true chunks = >bscript.decompile(output) - o.m = chunks[0] - OP_INT_BASE - o.n = chunks[chunks.length - 2] - OP_INT_BASE + o.m = chunks[0] - OP_INT_BASE // eslint-disable-line + o.n = chunks[chunks.length - 2] - OP_INT_BASE // eslint-disable-line o.pubkeys = >chunks.slice(1, -2) } @@ -103,9 +105,9 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid') if ( - (o).m <= 0 || - (o).n > 16 || - (o).m > (o).n || + (o).m <= 0 || // eslint-disable-line + (o).n > 16 || // eslint-disable-line + (o).m > (o).n || // eslint-disable-line o.n !== chunks.length - 3) throw new TypeError('Output is invalid') if (!(>o.pubkeys).every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') diff --git a/src/payments/p2pk.ts b/src/payments/p2pk.ts index f383a1c..0825955 100644 --- a/src/payments/p2pk.ts +++ b/src/payments/p2pk.ts @@ -1,9 +1,9 @@ -import { Payment, PaymentOpts } from './index' +import { Payment, PaymentOpts } from './index' // eslint-disable-line import * as bscript from '../script' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS const ecc = require('tiny-secp256k1') // input: {signature} diff --git a/src/payments/p2pkh.ts b/src/payments/p2pkh.ts index 4fb49de..f12faf8 100644 --- a/src/payments/p2pkh.ts +++ b/src/payments/p2pkh.ts @@ -1,10 +1,10 @@ -import { Payment, PaymentOpts } from './index' +import { Payment, PaymentOpts } from './index' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS const ecc = require('tiny-secp256k1') const bs58check = require('bs58check') @@ -54,7 +54,7 @@ export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(3, 23) if (a.address) return _address().hash - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) + if (a.pubkey || o.pubkey) return bcrypto.hash160( a.pubkey || o.pubkey) // eslint-disable-line }) lazy.prop(o, 'output', function () { if (!o.hash) return diff --git a/src/payments/p2sh.ts b/src/payments/p2sh.ts index d25b616..e0292f3 100644 --- a/src/payments/p2sh.ts +++ b/src/payments/p2sh.ts @@ -1,11 +1,10 @@ -import { Payment, PaymentOpts } from './index' -import { Network } from '../networks' +import { Payment, PaymentOpts } from './index' // eslint-disable-line +import { Network, bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS const bs58check = require('bs58check') diff --git a/src/payments/p2wpkh.ts b/src/payments/p2wpkh.ts index 918e909..b40085b 100644 --- a/src/payments/p2wpkh.ts +++ b/src/payments/p2wpkh.ts @@ -1,10 +1,10 @@ -import { Payment, PaymentOpts } from './index' +import { Payment, PaymentOpts } from './index' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS const ecc = require('tiny-secp256k1') const bech32 = require('bech32') @@ -59,7 +59,7 @@ export function p2wpkh (a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(2, 22) if (a.address) return _address().data - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey) + if (a.pubkey || o.pubkey) return bcrypto.hash160( a.pubkey || o.pubkey) // eslint-disable-line }) lazy.prop(o, 'output', function () { if (!o.hash) return diff --git a/src/payments/p2wsh.ts b/src/payments/p2wsh.ts index 1a8e86e..7e2f237 100644 --- a/src/payments/p2wsh.ts +++ b/src/payments/p2wsh.ts @@ -1,11 +1,10 @@ -import { Payment, PaymentOpts } from './index' -import { Network } from '../networks' +import { Payment, PaymentOpts } from './index' // eslint-disable-line +import { Network, bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' const typef = require('typeforce') -import { OPS } from '../script' +const OPS = bscript.OPS const bech32 = require('bech32') diff --git a/src/templates/nulldata.ts b/src/templates/nulldata.ts index 8889fb9..0833eac 100644 --- a/src/templates/nulldata.ts +++ b/src/templates/nulldata.ts @@ -1,6 +1,6 @@ // OP_RETURN {data} import * as bscript from '../script' -import { OPS } from '../script' +const OPS = bscript.OPS export function check (script: Buffer | Array): boolean { const buffer = bscript.compile(script) From f8427274cc7f77f5901ea732f79dd4d641adb956 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 23:00:32 +0900 Subject: [PATCH 088/183] Add a few type aliases to TransactionBuilder --- src/transaction_builder.ts | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index 8977364..b3c6ee0 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -16,31 +16,36 @@ const typeforce = require('typeforce') const SCRIPT_TYPES = classify.types +type TxbSignatures = Array | Array +type TxbPubkeys = Array +type TxbWitness = Array +type TxbScriptType = string +type TxbScript = Buffer interface TxbInput { value?: number hasWitness?: boolean - signScript?: Buffer - signType?: string - prevOutScript?: Buffer - redeemScript?: Buffer - redeemScriptType?: string - prevOutType?: string - pubkeys?: Array - signatures?: Array | Array - witness?: Array - witnessScript?: Buffer - witnessScriptType?: string - script?: Buffer + signScript?: TxbScript + signType?: TxbScriptType + prevOutScript?: TxbScript + redeemScript?: TxbScript + redeemScriptType?: TxbScriptType + prevOutType?: TxbScriptType + pubkeys?: TxbPubkeys + signatures?: TxbSignatures + witness?: TxbWitness + witnessScript?: TxbScript + witnessScriptType?: TxbScriptType + script?: TxbScript sequence?: number - scriptSig?: Buffer + scriptSig?: TxbScript maxSignatures?: number } interface TxbOutput { type: string - pubkeys?: Array - signatures?: Array | Array + pubkeys?: TxbPubkeys + signatures?: TxbSignatures maxSignatures?: number } From 35adaa84717d42b7f69217e88b31d00bc703ddfc Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 29 Dec 2018 23:27:57 +0900 Subject: [PATCH 089/183] Add test from bugfix, also remove unnecessary arg --- src/transaction_builder.ts | 4 ++-- test/fixtures/p2ms.json | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/transaction_builder.ts b/src/transaction_builder.ts index b3c6ee0..59fc102 100644 --- a/src/transaction_builder.ts +++ b/src/transaction_builder.ts @@ -279,7 +279,7 @@ export class TransactionBuilder { } if (!canSign(input)) { - const prepared = prepareInput(input, ourPubKey, redeemScript, witnessValue, witnessScript) + const prepared = prepareInput(input, ourPubKey, redeemScript, witnessScript) // updates inline Object.assign(input, prepared) @@ -589,7 +589,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { return { type } } -function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, witnessValue: number, witnessScript: Buffer): TxbInput { +function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, witnessScript: Buffer): TxbInput { if (redeemScript && witnessScript) { const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) const p2wshAlt = payments.p2wsh({ output: redeemScript }) diff --git a/test/fixtures/p2ms.json b/test/fixtures/p2ms.json index 8ea033e..2f41270 100644 --- a/test/fixtures/p2ms.json +++ b/test/fixtures/p2ms.json @@ -310,6 +310,20 @@ ] } }, + { + "exception": "Signature mismatch", + "arguments": { + "m": 1, + "pubkeys": [ + "030000000000000000000000000000000000000000000000000000000000000001", + "030000000000000000000000000000000000000000000000000000000000000001" + ], + "signatures": [ + "300602010002010001" + ], + "input": "OP_0 300602010002010101" + } + }, { "exception": "Too many signatures provided", "arguments": { From b8c2e9e339a64ea79f78c81864b25e8b69f0efcc Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 30 Dec 2018 11:23:28 +0900 Subject: [PATCH 090/183] Change ECPair to be compatible with payment({pubkey:ecpair.publicKey}) --- src/ecpair.ts | 16 ++++++++-------- test/ecpair.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ecpair.ts b/src/ecpair.ts index 321a5ed..ad28adf 100644 --- a/src/ecpair.ts +++ b/src/ecpair.ts @@ -20,8 +20,8 @@ interface ECPairOptions { export interface ECPairInterface { compressed: boolean network: Network - privateKey: Buffer | null - publicKey: Buffer | null + privateKey?: Buffer + publicKey?: Buffer toWIF(): string sign(hash: Buffer): Buffer verify(hash: Buffer, signature: Buffer): Buffer @@ -31,25 +31,25 @@ export interface ECPairInterface { class ECPair implements ECPairInterface { compressed: boolean network: Network - private __d: Buffer | null - private __Q: Buffer | null + private __d?: Buffer + private __Q?: Buffer constructor (d?: Buffer, Q?: Buffer, options?: ECPairOptions) { if (options === undefined) options = {} this.compressed = options.compressed === undefined ? true : options.compressed this.network = options.network || NETWORKS.bitcoin - this.__d = null - this.__Q = null + this.__d = undefined + this.__Q = undefined if (d !== undefined) this.__d = d if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed) } - get privateKey (): Buffer | null { + get privateKey (): Buffer | undefined { return this.__d } - get publicKey (): Buffer | null { + get publicKey (): Buffer | undefined { if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed) return this.__Q } diff --git a/test/ecpair.js b/test/ecpair.js index 75a2e81..f590e18 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -30,7 +30,7 @@ describe('ECPair', function () { }) it('calls pointFromScalar lazily', hoodwink(function () { - assert.strictEqual(keyPair.__Q, null) + assert.strictEqual(keyPair.__Q, undefined) // .publicKey forces the memoization assert.strictEqual(keyPair.publicKey.toString('hex'), '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798') From 63d51d1da7b04f5108c1ca86ef103e0175c151d2 Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 30 Dec 2018 13:34:40 +0900 Subject: [PATCH 091/183] Export some types and interfaces --- src/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/index.ts b/src/index.ts index 31ef042..1db2052 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,3 +24,8 @@ export { payments, script, } + +export { Payment, PaymentOpts } from './payments' +export { Input as TxInput, Output as TxOutput } from './transaction' +export { Network } from './networks' +export { OpCode } from './script' From e7ac2b9a4ec703aca840fa0517406a5bbf1d5c38 Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 30 Dec 2018 15:08:29 +0900 Subject: [PATCH 092/183] pull in bip32 typescript --- package.json | 2 +- src/index.ts | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 2d89027..81761a9 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dependencies": { "@types/node": "^10.12.18", "bech32": "^1.1.2", - "bip32": "^1.0.0", + "bip32": "git+https://github.com/junderw/bip32.git#typeScript", "bip66": "^1.1.0", "bitcoin-ops": "^1.4.0", "bs58check": "^2.0.0", diff --git a/src/index.ts b/src/index.ts index 1db2052..7574048 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,31 +1,28 @@ -const bip32 = require('bip32') - -import { Block } from './block' +import * as bip32 from 'bip32' import * as ECPair from './ecpair' -import { Transaction } from './transaction' -import { TransactionBuilder } from './transaction_builder' import * as address from './address' import * as crypto from './crypto' import * as networks from './networks' import * as payments from './payments' import * as script from './script' -import { OPS as opcodes } from './script' export { - Block, ECPair, - Transaction, - TransactionBuilder, address, bip32, crypto, networks, - opcodes, payments, script, } +export { Block } from './block' +export { Transaction } from './transaction' +export { TransactionBuilder } from './transaction_builder' +export { OPS as opcodes } from './script' + export { Payment, PaymentOpts } from './payments' export { Input as TxInput, Output as TxOutput } from './transaction' export { Network } from './networks' export { OpCode } from './script' +export { BIP32Interface } from 'bip32' From 53b8f966e768e9ee69337412d23ba9d5f038bd2b Mon Sep 17 00:00:00 2001 From: "Sam (Sangho Kim)" Date: Mon, 31 Dec 2018 12:24:27 +0900 Subject: [PATCH 093/183] Update transactions.js I think this is typo. --- test/integration/transactions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/transactions.js b/test/integration/transactions.js index 0d88d78..f725241 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -64,7 +64,7 @@ describe('bitcoinjs-lib (transactions)', function () { txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend" txb.addOutput(aliceCpkh.address, 1e4) // Alice's change - // (in)(4e4 + 2e4) - (out)(1e4 + 3e4) = (fee)2e4 = 20000, this is the miner fee + // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee // Alice signs each input with the respective private keys txb.sign(0, alice1) From f8490b6c0d89ab44f3408a6cdbd44c6da2c718ef Mon Sep 17 00:00:00 2001 From: Jonathan Underwood Date: Mon, 31 Dec 2018 15:17:00 +0900 Subject: [PATCH 094/183] Update rng function In case someone copy pastes, instead of getting a dangerous key, they will get a random key, and a console error. --- test/integration/addresses.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 9ad7502..501e7ac 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -15,7 +15,14 @@ const LITECOIN = { } // deterministic RNG for testing only -function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } +function rng (c) { + if (describe === undefined || it === undefined) { + console.error('DO NOT USE THIS rng FUNCTION OUTSIDE OF AUTOMATED TESTING!') + const randomBytes = require('randombytes') + return randomBytes(c) + } + return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') +} describe('bitcoinjs-lib (addresses)', function () { it('can generate a random address', function () { From 7d8dd860d1208ed715579a1ec4364d9f9d7aa4b2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 1 Jan 2019 11:30:20 +1100 Subject: [PATCH 095/183] testing: use NODE_ENV instead of mocha constants --- package.json | 2 +- test/integration/addresses.js | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 755be28..c9ab813 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha", - "integration": "mocha --timeout 50000 test/integration/", + "integration": "NODE_ENV=TESTING-BITCOINJS mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run standard && npm run coverage", "unit": "mocha" diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 76c0330..9a70172 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -14,20 +14,17 @@ const LITECOIN = { wif: 0xb0 } -// deterministic RNG for testing only -function rng (c) { - if (describe === undefined || it === undefined) { - console.error('DO NOT USE THIS rng FUNCTION OUTSIDE OF AUTOMATED TESTING!') - const randomBytes = require('randombytes') - return randomBytes(c) - } +// deterministic random number generator for TESTING ONLY +// WARNING: DO NOT USE THIS - IT IS NOT RANDOM - it produces the same private key every time for the purposes of testing. +function unsafeDeterministicRng (c) { + if (process.env.NODE_ENV !== 'TESTING-BITCOINJS') throw new Error('DO NOT USE THIS FUNCTION - IT IS NOT RANDOM - IT IS FOR TESTING ONLY - IT PRODUCES THE SAME PRIVATE KEY EVERY TIME') return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } describe('bitcoinjs-lib (addresses)', function () { it('can generate a random address', function () { - // in production: const keyPair = bitcoin.ECPair.makeRandom({}) - const keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) + // const keyPair = bitcoin.ECPair.makeRandom() + const keyPair = bitcoin.ECPair.makeRandom({ rng: unsafeDeterministicRng }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') @@ -118,8 +115,8 @@ describe('bitcoinjs-lib (addresses)', function () { // other networks it('can generate a Testnet address', function () { const testnet = bitcoin.networks.testnet - // in production: const keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) - const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: rng }) + // const keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) + const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: unsafeDeterministicRng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: testnet }) @@ -128,8 +125,8 @@ describe('bitcoinjs-lib (addresses)', function () { }) it('can generate a Litecoin address', function () { - // in production: const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) - const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: rng }) + // const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) + const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: unsafeDeterministicRng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN }) From e5781d97b9f3a8631fdfadadd75b3fe78b244bf4 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 1 Jan 2019 11:41:00 +1100 Subject: [PATCH 096/183] testing: extra warnings --- test/integration/addresses.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 9a70172..661d5b6 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -3,6 +3,17 @@ const assert = require('assert') const bitcoin = require('../../') const dhttp = require('dhttp/200') +// WARNING: DO NOT USE THIS - IT IS NOT RANDOM +// WARNING: It produces the same 'number' every time for the purposes of testing. +function unsafeDeterministicRng (c) { + if (process.env.NODE_ENV !== 'TESTING-BITCOINJS') { + throw new Error('DO NOT USE THIS FUNCTION - IT IS NOT RANDOM - IT IS FOR TESTING ONLY - IT PRODUCES THE SAME NUMBER EVERY TIME') + } + + // deterministic result for TESTING ONLY + return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') +} + const LITECOIN = { messagePrefix: '\x19Litecoin Signed Message:\n', bip32: { @@ -14,16 +25,11 @@ const LITECOIN = { wif: 0xb0 } -// deterministic random number generator for TESTING ONLY -// WARNING: DO NOT USE THIS - IT IS NOT RANDOM - it produces the same private key every time for the purposes of testing. -function unsafeDeterministicRng (c) { - if (process.env.NODE_ENV !== 'TESTING-BITCOINJS') throw new Error('DO NOT USE THIS FUNCTION - IT IS NOT RANDOM - IT IS FOR TESTING ONLY - IT PRODUCES THE SAME PRIVATE KEY EVERY TIME') - return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') -} - describe('bitcoinjs-lib (addresses)', function () { it('can generate a random address', function () { // const keyPair = bitcoin.ECPair.makeRandom() + + // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file const keyPair = bitcoin.ECPair.makeRandom({ rng: unsafeDeterministicRng }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) @@ -116,6 +122,8 @@ describe('bitcoinjs-lib (addresses)', function () { it('can generate a Testnet address', function () { const testnet = bitcoin.networks.testnet // const keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) + + // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: unsafeDeterministicRng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: testnet }) @@ -126,6 +134,8 @@ describe('bitcoinjs-lib (addresses)', function () { it('can generate a Litecoin address', function () { // const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) + + // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: unsafeDeterministicRng }) const wif = keyPair.toWIF() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN }) From 88951d34dbe5834a1330282a5b7b97d6157cdc28 Mon Sep 17 00:00:00 2001 From: Jonathan Underwood Date: Tue, 1 Jan 2019 14:26:34 +0900 Subject: [PATCH 097/183] Update LICENSE Happy new year! --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index fadd21b..064b885 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2011-2018 bitcoinjs-lib contributors +Copyright (c) 2011-2019 bitcoinjs-lib contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 49be171583d40eb0d4d638caf9d16df78ac3d178 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 1 Jan 2019 23:24:26 +1100 Subject: [PATCH 098/183] rm usage of unsafeDeterministicRng --- README.md | 62 ++++++++++----------- test/integration/addresses.js | 100 +++++++++++++--------------------- 2 files changed, 68 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index 9342696..b8f70f2 100644 --- a/README.md +++ b/README.md @@ -108,37 +108,37 @@ The below examples are implemented as integration tests, they should be very eas Otherwise, pull requests are appreciated. Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). -- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L22) -- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L40) -- [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L47) -- [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L60) -- [Generate a SegWit P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L67) -- [Generate a SegWit 3-of-4 multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L76) -- [Generate a SegWit 2-of-2 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L90) -- [Support the retrieval of transactions for an address (3rd party blockchain)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L104) -- [Generate a Testnet address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L123) -- [Generate a Litecoin address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L133) -- [Create a 1-to-1 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L13) -- [Create a 2-to-2 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L28) -- [Create (and broadcast via 3PBP) a typical Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L47) -- [Create (and broadcast via 3PBP) a Transaction with an OP\_RETURN output](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L83) -- [Create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L105) -- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L143) -- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2WPKH input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L174) -- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2PK input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L218) -- [Create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L263) -- [Verify a Transaction signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L304) -- [Import a BIP32 testnet xpriv and export to WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L12) -- [Export a BIP32 xpriv, then import it](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L20) -- [Export a BIP32 xpub](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L31) -- [Create a BIP32, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L40) -- [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L55) -- [Create a BIP49, bitcoin testnet, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L71) -- [Use BIP39 to generate BIP32 addresses](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L86) -- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L43) -- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L88) -- [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L144) -- [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L190) +- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a SegWit P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a SegWit 3-of-4 multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a SegWit 2-of-2 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Support the retrieval of transactions for an address (3rd party blockchain)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a Testnet address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Generate a Litecoin address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) +- [Create a 1-to-1 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create a 2-to-2 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a typical Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with an OP\_RETURN output](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2WPKH input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2PK input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Verify a Transaction signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) +- [Import a BIP32 testnet xpriv and export to WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Export a BIP32 xpriv, then import it](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Export a BIP32 xpub](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Create a BIP32, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Create a BIP49, bitcoin testnet, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Use BIP39 to generate BIP32 addresses](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) +- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) +- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) +- [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) +- [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)! diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 661d5b6..51d2264 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -2,38 +2,28 @@ const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const dhttp = require('dhttp/200') - -// WARNING: DO NOT USE THIS - IT IS NOT RANDOM -// WARNING: It produces the same 'number' every time for the purposes of testing. -function unsafeDeterministicRng (c) { - if (process.env.NODE_ENV !== 'TESTING-BITCOINJS') { - throw new Error('DO NOT USE THIS FUNCTION - IT IS NOT RANDOM - IT IS FOR TESTING ONLY - IT PRODUCES THE SAME NUMBER EVERY TIME') - } - - // deterministic result for TESTING ONLY - return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') -} - -const LITECOIN = { - messagePrefix: '\x19Litecoin Signed Message:\n', - bip32: { - public: 0x019da462, - private: 0x019d9cfe - }, - pubKeyHash: 0x30, - scriptHash: 0x32, - wif: 0xb0 -} +const TESTNET = bitcoin.networks.testnet describe('bitcoinjs-lib (addresses)', function () { - it('can generate a random address', function () { - // const keyPair = bitcoin.ECPair.makeRandom() - - // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file - const keyPair = bitcoin.ECPair.makeRandom({ rng: unsafeDeterministicRng }) + it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', function (done) { + const keyPair = bitcoin.ECPair.makeRandom() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') + // bitcoin P2PKH addresses start with a '1' + assert.strictEqual(address.startsWith('1'), true) + + dhttp({ + method: 'GET', + url: 'https://blockchain.info/rawaddr/' + address + }, function (err, result) { + if (err) return done(err) + + // random private keys [probably!] have no transactions + assert.strictEqual(result.n_tx, 0) + assert.strictEqual(result.total_received, 0) + assert.strictEqual(result.total_sent, 0) + done() + }) }) it('can import an address via WIF', function () { @@ -100,47 +90,31 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, '3P4mrxQfmExfhxqjLnR2Ah4WES5EB1KBrN') }) - it('can support the retrieval of transactions for an address (via 3PBP)', function (done) { - const keyPair = bitcoin.ECPair.makeRandom() - const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - - dhttp({ - method: 'GET', - url: 'https://blockchain.info/rawaddr/' + address - }, function (err, result) { - if (err) return done(err) - - // random private keys [probably!] have no transactions - assert.strictEqual(result.n_tx, 0) - assert.strictEqual(result.total_received, 0) - assert.strictEqual(result.total_sent, 0) - done() - }) - }) - - // other networks + // examples using other network information it('can generate a Testnet address', function () { - const testnet = bitcoin.networks.testnet - // const keyPair = bitcoin.ECPair.makeRandom({ network: testnet }) + const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET }) + const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET }) - // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file - const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: unsafeDeterministicRng }) - const wif = keyPair.toWIF() - const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: testnet }) - - assert.strictEqual(address, 'mubSzQNtZfDj1YdNP6pNDuZy6zs6GDn61L') - assert.strictEqual(wif, 'cRgnQe9MUu1JznntrLaoQpB476M8PURvXVQB5R2eqms5tXnzNsrr') + // bitcoin testnet P2PKH addresses start with a 'm' + assert.strictEqual(address.startsWith('m'), true) }) it('can generate a Litecoin address', function () { - // const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) - - // WARNING: uses unsafeDeterministicRng function for testing, see warning at top of file - const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: unsafeDeterministicRng }) - const wif = keyPair.toWIF() + // WARNING: although possible, bitcoinjs is NOT necessarily compatible with Litecoin + const LITECOIN = { + messagePrefix: '\x19Litecoin Signed Message:\n', + bip32: { + public: 0x019da462, + private: 0x019d9cfe + }, + pubKeyHash: 0x30, + scriptHash: 0x32, + wif: 0xb0 + } + + const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN }) - assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') - assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') + assert.strictEqual(address.startsWith('L'), true) }) }) From c68dfc058fa984d1fb5431cc4ce4ef23a8b0cbc5 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 1 Jan 2019 23:30:10 +1100 Subject: [PATCH 099/183] testing: rm NODE_ENV --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c9ab813..755be28 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "coverage-report": "nyc report --reporter=lcov", "coverage-html": "nyc report --reporter=html", "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha", - "integration": "NODE_ENV=TESTING-BITCOINJS mocha --timeout 50000 test/integration/", + "integration": "mocha --timeout 50000 test/integration/", "standard": "standard", "test": "npm run standard && npm run coverage", "unit": "mocha" From f3d918a2cbc6653247e939c367f5aafd5c48f73c Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 1 Jan 2019 23:49:57 +1100 Subject: [PATCH 100/183] tests: use privateKey 0x000...0001 for examples --- test/integration/addresses.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 51d2264..5afc5e8 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -27,10 +27,10 @@ describe('bitcoinjs-lib (addresses)', function () { }) it('can import an address via WIF', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') + assert.strictEqual(address, '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH') }) it('can generate a P2SH, pay-to-multisig (2-of-3) address', function () { @@ -47,19 +47,19 @@ describe('bitcoinjs-lib (addresses)', function () { }) it('can generate a SegWit address', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, 'bc1qt97wqg464zrhnx23upykca5annqvwkwujjglky') + assert.strictEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4') }) it('can generate a SegWit address (via P2SH)', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) }) - assert.strictEqual(address, '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53') + assert.strictEqual(address, '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN') }) it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', function () { From bc28949056f4cd4841c3391c06085695d2a12c8a Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 4 Jan 2019 18:33:02 +0900 Subject: [PATCH 101/183] Commit js, ts, and definitions in separate folders --- .gitignore | 1 - package.json | 8 +- src/address.js | 99 +++ src/block.js | 190 +++++ src/bufferutils.js | 42 ++ src/classify.js | 75 ++ src/crypto.js | 23 + src/ecpair.js | 97 +++ src/index.js | 24 + src/networks.js | 35 + src/payments/embed.js | 52 ++ src/payments/index.js | 18 + src/payments/lazy.js | 32 + src/payments/p2ms.js | 144 ++++ src/payments/p2pk.js | 80 ++ src/payments/p2pkh.js | 144 ++++ src/payments/p2sh.js | 191 +++++ src/payments/p2wpkh.js | 145 ++++ src/payments/p2wsh.js | 178 +++++ src/script.js | 188 +++++ src/script_number.js | 60 ++ src/script_signature.js | 58 ++ src/templates/multisig/index.js | 6 + src/templates/multisig/input.js | 21 + src/templates/multisig/output.js | 34 + src/templates/nulldata.js | 14 + src/templates/pubkey/index.js | 6 + src/templates/pubkey/input.js | 11 + src/templates/pubkey/output.js | 13 + src/templates/pubkeyhash/index.js | 6 + src/templates/pubkeyhash/input.js | 12 + src/templates/pubkeyhash/output.js | 16 + src/templates/scripthash/index.js | 6 + src/templates/scripthash/input.js | 43 ++ src/templates/scripthash/output.js | 14 + src/templates/witnesscommitment/index.js | 4 + src/templates/witnesscommitment/output.js | 30 + src/templates/witnesspubkeyhash/index.js | 6 + src/templates/witnesspubkeyhash/input.js | 15 + src/templates/witnesspubkeyhash/output.js | 13 + src/templates/witnessscripthash/index.js | 6 + src/templates/witnessscripthash/input.js | 34 + src/templates/witnessscripthash/output.js | 13 + src/transaction.js | 448 +++++++++++ src/transaction_builder.js | 699 ++++++++++++++++++ src/types.js | 48 ++ test/address.js | 6 +- test/bufferutils.js | 2 +- test/classify.js | 20 +- test/crypto.js | 2 +- test/ecpair.js | 6 +- test/payments.js | 2 +- test/payments.utils.js | 4 +- test/script.js | 2 +- test/script_number.js | 2 +- test/script_signature.js | 2 +- test/transaction.js | 2 +- test/transaction_builder.js | 10 +- test/types.js | 2 +- {src => ts_src}/address.ts | 0 {src => ts_src}/block.ts | 0 {src => ts_src}/bufferutils.ts | 0 {src => ts_src}/classify.ts | 0 {src => ts_src}/crypto.ts | 0 {src => ts_src}/ecpair.ts | 0 {src => ts_src}/index.ts | 0 {src => ts_src}/networks.ts | 0 {src => ts_src}/payments/embed.ts | 0 {src => ts_src}/payments/index.ts | 0 {src => ts_src}/payments/lazy.ts | 0 {src => ts_src}/payments/p2ms.ts | 0 {src => ts_src}/payments/p2pk.ts | 0 {src => ts_src}/payments/p2pkh.ts | 0 {src => ts_src}/payments/p2sh.ts | 0 {src => ts_src}/payments/p2wpkh.ts | 0 {src => ts_src}/payments/p2wsh.ts | 0 {src => ts_src}/script.ts | 0 {src => ts_src}/script_number.ts | 0 {src => ts_src}/script_signature.ts | 0 {src => ts_src}/templates/multisig/index.ts | 0 {src => ts_src}/templates/multisig/input.ts | 0 {src => ts_src}/templates/multisig/output.ts | 0 {src => ts_src}/templates/nulldata.ts | 0 {src => ts_src}/templates/pubkey/index.ts | 0 {src => ts_src}/templates/pubkey/input.ts | 0 {src => ts_src}/templates/pubkey/output.ts | 0 {src => ts_src}/templates/pubkeyhash/index.ts | 0 {src => ts_src}/templates/pubkeyhash/input.ts | 0 .../templates/pubkeyhash/output.ts | 0 {src => ts_src}/templates/scripthash/index.ts | 0 {src => ts_src}/templates/scripthash/input.ts | 0 .../templates/scripthash/output.ts | 0 .../templates/witnesscommitment/index.ts | 0 .../templates/witnesscommitment/output.ts | 0 .../templates/witnesspubkeyhash/index.ts | 0 .../templates/witnesspubkeyhash/input.ts | 0 .../templates/witnesspubkeyhash/output.ts | 0 .../templates/witnessscripthash/index.ts | 0 .../templates/witnessscripthash/input.ts | 0 .../templates/witnessscripthash/output.ts | 0 {src => ts_src}/transaction.ts | 0 {src => ts_src}/transaction_builder.ts | 0 {src => ts_src}/types.ts | 0 tsconfig.json | 7 +- types/address.d.ts | 17 + types/block.d.ts | 27 + types/bufferutils.d.ts | 4 + types/classify.d.ts | 16 + types/crypto.d.ts | 6 + types/ecpair.d.ts | 34 + types/index.d.ts | 17 + types/networks.d.ts | 16 + types/payments/embed.d.ts | 2 + types/payments/index.d.ts | 30 + types/payments/lazy.d.ts | 2 + types/payments/p2ms.d.ts | 2 + types/payments/p2pk.d.ts | 2 + types/payments/p2pkh.d.ts | 2 + types/payments/p2sh.d.ts | 2 + types/payments/p2wpkh.d.ts | 2 + types/payments/p2wsh.d.ts | 2 + types/script.d.ts | 18 + types/script_number.d.ts | 3 + types/script_signature.d.ts | 8 + types/templates/multisig/index.d.ts | 3 + types/templates/multisig/input.d.ts | 5 + types/templates/multisig/output.d.ts | 5 + types/templates/nulldata.d.ts | 9 + types/templates/pubkey/index.d.ts | 3 + types/templates/pubkey/input.d.ts | 5 + types/templates/pubkey/output.d.ts | 5 + types/templates/pubkeyhash/index.d.ts | 3 + types/templates/pubkeyhash/input.d.ts | 5 + types/templates/pubkeyhash/output.d.ts | 5 + types/templates/scripthash/index.d.ts | 3 + types/templates/scripthash/input.d.ts | 5 + types/templates/scripthash/output.d.ts | 5 + types/templates/witnesscommitment/index.d.ts | 2 + types/templates/witnesscommitment/output.d.ts | 7 + types/templates/witnesspubkeyhash/index.d.ts | 3 + types/templates/witnesspubkeyhash/input.d.ts | 5 + types/templates/witnesspubkeyhash/output.d.ts | 5 + types/templates/witnessscripthash/index.d.ts | 3 + types/templates/witnessscripthash/input.d.ts | 5 + types/templates/witnessscripthash/output.d.ts | 5 + types/transaction.d.ts | 59 ++ types/transaction_builder.d.ts | 26 + types/types.d.ts | 25 + 148 files changed, 3850 insertions(+), 39 deletions(-) create mode 100644 src/address.js create mode 100644 src/block.js create mode 100644 src/bufferutils.js create mode 100644 src/classify.js create mode 100644 src/crypto.js create mode 100644 src/ecpair.js create mode 100644 src/index.js create mode 100644 src/networks.js create mode 100644 src/payments/embed.js create mode 100644 src/payments/index.js create mode 100644 src/payments/lazy.js create mode 100644 src/payments/p2ms.js create mode 100644 src/payments/p2pk.js create mode 100644 src/payments/p2pkh.js create mode 100644 src/payments/p2sh.js create mode 100644 src/payments/p2wpkh.js create mode 100644 src/payments/p2wsh.js create mode 100644 src/script.js create mode 100644 src/script_number.js create mode 100644 src/script_signature.js create mode 100644 src/templates/multisig/index.js create mode 100644 src/templates/multisig/input.js create mode 100644 src/templates/multisig/output.js create mode 100644 src/templates/nulldata.js create mode 100644 src/templates/pubkey/index.js create mode 100644 src/templates/pubkey/input.js create mode 100644 src/templates/pubkey/output.js create mode 100644 src/templates/pubkeyhash/index.js create mode 100644 src/templates/pubkeyhash/input.js create mode 100644 src/templates/pubkeyhash/output.js create mode 100644 src/templates/scripthash/index.js create mode 100644 src/templates/scripthash/input.js create mode 100644 src/templates/scripthash/output.js create mode 100644 src/templates/witnesscommitment/index.js create mode 100644 src/templates/witnesscommitment/output.js create mode 100644 src/templates/witnesspubkeyhash/index.js create mode 100644 src/templates/witnesspubkeyhash/input.js create mode 100644 src/templates/witnesspubkeyhash/output.js create mode 100644 src/templates/witnessscripthash/index.js create mode 100644 src/templates/witnessscripthash/input.js create mode 100644 src/templates/witnessscripthash/output.js create mode 100644 src/transaction.js create mode 100644 src/transaction_builder.js create mode 100644 src/types.js rename {src => ts_src}/address.ts (100%) rename {src => ts_src}/block.ts (100%) rename {src => ts_src}/bufferutils.ts (100%) rename {src => ts_src}/classify.ts (100%) rename {src => ts_src}/crypto.ts (100%) rename {src => ts_src}/ecpair.ts (100%) rename {src => ts_src}/index.ts (100%) rename {src => ts_src}/networks.ts (100%) rename {src => ts_src}/payments/embed.ts (100%) rename {src => ts_src}/payments/index.ts (100%) rename {src => ts_src}/payments/lazy.ts (100%) rename {src => ts_src}/payments/p2ms.ts (100%) rename {src => ts_src}/payments/p2pk.ts (100%) rename {src => ts_src}/payments/p2pkh.ts (100%) rename {src => ts_src}/payments/p2sh.ts (100%) rename {src => ts_src}/payments/p2wpkh.ts (100%) rename {src => ts_src}/payments/p2wsh.ts (100%) rename {src => ts_src}/script.ts (100%) rename {src => ts_src}/script_number.ts (100%) rename {src => ts_src}/script_signature.ts (100%) rename {src => ts_src}/templates/multisig/index.ts (100%) rename {src => ts_src}/templates/multisig/input.ts (100%) rename {src => ts_src}/templates/multisig/output.ts (100%) rename {src => ts_src}/templates/nulldata.ts (100%) rename {src => ts_src}/templates/pubkey/index.ts (100%) rename {src => ts_src}/templates/pubkey/input.ts (100%) rename {src => ts_src}/templates/pubkey/output.ts (100%) rename {src => ts_src}/templates/pubkeyhash/index.ts (100%) rename {src => ts_src}/templates/pubkeyhash/input.ts (100%) rename {src => ts_src}/templates/pubkeyhash/output.ts (100%) rename {src => ts_src}/templates/scripthash/index.ts (100%) rename {src => ts_src}/templates/scripthash/input.ts (100%) rename {src => ts_src}/templates/scripthash/output.ts (100%) rename {src => ts_src}/templates/witnesscommitment/index.ts (100%) rename {src => ts_src}/templates/witnesscommitment/output.ts (100%) rename {src => ts_src}/templates/witnesspubkeyhash/index.ts (100%) rename {src => ts_src}/templates/witnesspubkeyhash/input.ts (100%) rename {src => ts_src}/templates/witnesspubkeyhash/output.ts (100%) rename {src => ts_src}/templates/witnessscripthash/index.ts (100%) rename {src => ts_src}/templates/witnessscripthash/input.ts (100%) rename {src => ts_src}/templates/witnessscripthash/output.ts (100%) rename {src => ts_src}/transaction.ts (100%) rename {src => ts_src}/transaction_builder.ts (100%) rename {src => ts_src}/types.ts (100%) create mode 100644 types/address.d.ts create mode 100644 types/block.d.ts create mode 100644 types/bufferutils.d.ts create mode 100644 types/classify.d.ts create mode 100644 types/crypto.d.ts create mode 100644 types/ecpair.d.ts create mode 100644 types/index.d.ts create mode 100644 types/networks.d.ts create mode 100644 types/payments/embed.d.ts create mode 100644 types/payments/index.d.ts create mode 100644 types/payments/lazy.d.ts create mode 100644 types/payments/p2ms.d.ts create mode 100644 types/payments/p2pk.d.ts create mode 100644 types/payments/p2pkh.d.ts create mode 100644 types/payments/p2sh.d.ts create mode 100644 types/payments/p2wpkh.d.ts create mode 100644 types/payments/p2wsh.d.ts create mode 100644 types/script.d.ts create mode 100644 types/script_number.d.ts create mode 100644 types/script_signature.d.ts create mode 100644 types/templates/multisig/index.d.ts create mode 100644 types/templates/multisig/input.d.ts create mode 100644 types/templates/multisig/output.d.ts create mode 100644 types/templates/nulldata.d.ts create mode 100644 types/templates/pubkey/index.d.ts create mode 100644 types/templates/pubkey/input.d.ts create mode 100644 types/templates/pubkey/output.d.ts create mode 100644 types/templates/pubkeyhash/index.d.ts create mode 100644 types/templates/pubkeyhash/input.d.ts create mode 100644 types/templates/pubkeyhash/output.d.ts create mode 100644 types/templates/scripthash/index.d.ts create mode 100644 types/templates/scripthash/input.d.ts create mode 100644 types/templates/scripthash/output.d.ts create mode 100644 types/templates/witnesscommitment/index.d.ts create mode 100644 types/templates/witnesscommitment/output.d.ts create mode 100644 types/templates/witnesspubkeyhash/index.d.ts create mode 100644 types/templates/witnesspubkeyhash/input.d.ts create mode 100644 types/templates/witnesspubkeyhash/output.d.ts create mode 100644 types/templates/witnessscripthash/index.d.ts create mode 100644 types/templates/witnessscripthash/input.d.ts create mode 100644 types/templates/witnessscripthash/output.d.ts create mode 100644 types/transaction.d.ts create mode 100644 types/transaction_builder.d.ts create mode 100644 types/types.d.ts diff --git a/.gitignore b/.gitignore index 3d940fb..a6c0ab8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ coverage -dist node_modules .nyc_output npm-debug.log diff --git a/package.json b/package.json index 81761a9..c00414a 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "bitcoinjs-lib", "version": "4.0.2", "description": "Client-side Bitcoin JavaScript library", - "main": "./dist/src/index.js", - "types": "./dist/src/index.d.ts", + "main": "./src/index.js", + "types": "./types/index.d.ts", "engines": { "node": ">=8.0.0" }, @@ -24,7 +24,7 @@ "nobuild:coverage-html": "nyc report --reporter=html", "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", "nobuild:integration": "mocha --timeout 50000 test/integration/", - "nobuild:standard": "standard src/**/*.ts", + "nobuild:standard": "standard ts_src/**/*.ts", "nobuild:unit": "mocha", "prepare": "npm run build", "standard": "npm run build && npm run nobuild:standard", @@ -36,7 +36,7 @@ "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git" }, "files": [ - "dist/src" + "src" ], "dependencies": { "@types/node": "^10.12.18", diff --git a/src/address.js b/src/address.js new file mode 100644 index 0000000..ed11e5c --- /dev/null +++ b/src/address.js @@ -0,0 +1,99 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const types = require("./types"); +const bscript = require("./script"); +const networks = require("./networks"); +const payments = require("./payments"); +const bech32 = require('bech32'); +const bs58check = require('bs58check'); +const typeforce = require('typeforce'); +function fromBase58Check(address) { + const payload = bs58check.decode(address); + // TODO: 4.0.0, move to "toOutputScript" + if (payload.length < 21) + throw new TypeError(address + ' is too short'); + if (payload.length > 21) + throw new TypeError(address + ' is too long'); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version: version, hash: hash }; +} +exports.fromBase58Check = fromBase58Check; +function fromBech32(address) { + const result = bech32.decode(address); + const data = bech32.fromWords(result.words.slice(1)); + return { + version: result.words[0], + prefix: result.prefix, + data: Buffer.from(data) + }; +} +exports.fromBech32 = fromBech32; +function toBase58Check(hash, version) { + typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(version, 0); + hash.copy(payload, 1); + return bs58check.encode(payload); +} +exports.toBase58Check = toBase58Check; +function toBech32(data, version, prefix) { + const words = bech32.toWords(data); + words.unshift(version); + return bech32.encode(prefix, words); +} +exports.toBech32 = toBech32; +function fromOutputScript(output, network) { + network = network || networks.bitcoin; + try { + return payments.p2pkh({ output, network }).address; + } + catch (e) { } + try { + return payments.p2sh({ output, network }).address; + } + catch (e) { } + try { + return payments.p2wpkh({ output, network }).address; + } + catch (e) { } + try { + return payments.p2wsh({ output, network }).address; + } + catch (e) { } + throw new Error(bscript.toASM(output) + ' has no matching Address'); +} +exports.fromOutputScript = fromOutputScript; +function toOutputScript(address, network) { + network = network || networks.bitcoin; + let decodeBase58 = undefined; + let decodeBech32 = undefined; + try { + decodeBase58 = fromBase58Check(address); + } + catch (e) { } + if (decodeBase58) { + if (decodeBase58.version === network.pubKeyHash) + return payments.p2pkh({ hash: decodeBase58.hash }).output; + if (decodeBase58.version === network.scriptHash) + return payments.p2sh({ hash: decodeBase58.hash }).output; + } + else { + try { + decodeBech32 = fromBech32(address); + } + catch (e) { } + if (decodeBech32) { + if (decodeBech32.prefix !== network.bech32) + throw new Error(address + ' has an invalid prefix'); + if (decodeBech32.version === 0) { + if (decodeBech32.data.length === 20) + return payments.p2wpkh({ hash: decodeBech32.data }).output; + if (decodeBech32.data.length === 32) + return payments.p2wsh({ hash: decodeBech32.data }).output; + } + } + } + throw new Error(address + ' has no matching Script'); +} +exports.toOutputScript = toOutputScript; diff --git a/src/block.js b/src/block.js new file mode 100644 index 0000000..5b4776f --- /dev/null +++ b/src/block.js @@ -0,0 +1,190 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const transaction_1 = require("./transaction"); +const types = require("./types"); +const bcrypto = require("./crypto"); +const bufferutils_1 = require("./bufferutils"); +const fastMerkleRoot = require('merkle-lib/fastRoot'); +const typeforce = require('typeforce'); +const varuint = require('varuint-bitcoin'); +const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); +const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); +const errorBufferTooSmall = new Error('Buffer too small (< 80 bytes)'); +function txesHaveWitness(transactions) { + return transactions !== undefined && + transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0; +} +class Block { + constructor() { + this.version = 1; + this.timestamp = 0; + this.bits = 0; + this.nonce = 0; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.witnessCommit = undefined; + this.transactions = undefined; + } + static fromBuffer(buffer) { + if (buffer.length < 80) + throw errorBufferTooSmall; + let offset = 0; + const readSlice = (n) => { + offset += n; + return buffer.slice(offset - n, offset); + }; + const readUInt32 = () => { + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; + }; + const readInt32 = () => { + const i = buffer.readInt32LE(offset); + offset += 4; + return i; + }; + const block = new Block(); + block.version = readInt32(); + block.prevHash = readSlice(32); + block.merkleRoot = readSlice(32); + block.timestamp = readUInt32(); + block.bits = readUInt32(); + block.nonce = readUInt32(); + if (buffer.length === 80) + return block; + const readVarInt = () => { + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; + }; + const readTransaction = () => { + const tx = transaction_1.Transaction.fromBuffer(buffer.slice(offset), true); + offset += tx.byteLength(); + return tx; + }; + const nTransactions = readVarInt(); + block.transactions = []; + for (var i = 0; i < nTransactions; ++i) { + const tx = readTransaction(); + block.transactions.push(tx); + } + // This Block contains a witness commit + if (block.hasWitnessCommit()) { + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + let witnessCommits = block.transactions[0].outs + .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) + .map(out => out.script.slice(6, 38)); + // Use the commit with the highest output (should only be one though) + block.witnessCommit = witnessCommits[witnessCommits.length - 1]; + } + return block; + } + static fromHex(hex) { + return Block.fromBuffer(Buffer.from(hex, 'hex')); + } + static calculateTarget(bits) { + const exponent = ((bits & 0xff000000) >> 24) - 3; + const mantissa = bits & 0x007fffff; + const target = Buffer.alloc(32, 0); + target.writeUIntBE(mantissa, 29 - exponent, 3); + return target; + } + static calculateMerkleRoot(transactions, forWitness) { + typeforce([{ getHash: types.Function }], transactions); + if (transactions.length === 0) + throw errorMerkleNoTxes; + if (forWitness && !txesHaveWitness(transactions)) + throw errorWitnessNotSegwit; + const hashes = transactions.map(transaction => transaction.getHash(forWitness)); + const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); + return forWitness + ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) + : rootHash; + } + hasWitnessCommit() { + return txesHaveWitness(this.transactions); + } + byteLength(headersOnly) { + if (headersOnly || !this.transactions) + return 80; + return 80 + varuint.encodingLength(this.transactions.length) + + this.transactions.reduce((a, x) => a + x.byteLength(), 0); + } + getHash() { + return bcrypto.hash256(this.toBuffer(true)); + } + getId() { + return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); + } + getUTCDate() { + const date = new Date(0); // epoch + date.setUTCSeconds(this.timestamp); + return date; + } + // TODO: buffer, offset compatibility + toBuffer(headersOnly) { + const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); + let offset = 0; + const writeSlice = (slice) => { + slice.copy(buffer, offset); + offset += slice.length; + }; + const writeInt32 = (i) => { + buffer.writeInt32LE(i, offset); + offset += 4; + }; + const writeUInt32 = (i) => { + buffer.writeUInt32LE(i, offset); + offset += 4; + }; + writeInt32(this.version); + writeSlice(this.prevHash); + writeSlice(this.merkleRoot); + writeUInt32(this.timestamp); + writeUInt32(this.bits); + writeUInt32(this.nonce); + if (headersOnly || !this.transactions) + return buffer; + varuint.encode(this.transactions.length, buffer, offset); + offset += varuint.encode.bytes; + this.transactions.forEach(tx => { + const txSize = tx.byteLength(); // TODO: extract from toBuffer? + tx.toBuffer(buffer, offset); + offset += txSize; + }); + return buffer; + } + toHex(headersOnly) { + return this.toBuffer(headersOnly).toString('hex'); + } + checkMerkleRoot() { + if (!this.transactions) + throw errorMerkleNoTxes; + const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); + return this.merkleRoot.compare(actualMerkleRoot) === 0; + } + checkWitnessCommit() { + if (!this.transactions) + throw errorMerkleNoTxes; + if (!this.hasWitnessCommit()) + throw errorWitnessNotSegwit; + const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true); + return this.witnessCommit.compare(actualWitnessCommit) === 0; + } + checkProofOfWork() { + const hash = bufferutils_1.reverseBuffer(this.getHash()); + const target = Block.calculateTarget(this.bits); + return hash.compare(target) <= 0; + } +} +exports.Block = Block; diff --git a/src/bufferutils.js b/src/bufferutils.js new file mode 100644 index 0000000..f768250 --- /dev/null +++ b/src/bufferutils.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// https://github.com/feross/buffer/blob/master/index.js#L1127 +function verifuint(value, max) { + if (typeof value !== 'number') + throw new Error('cannot write a non-number as a number'); + if (value < 0) + throw new Error('specified a negative value for writing an unsigned value'); + if (value > max) + throw new Error('RangeError: value out of range'); + if (Math.floor(value) !== value) + throw new Error('value has a fractional component'); +} +function readUInt64LE(buffer, offset) { + const a = buffer.readUInt32LE(offset); + let b = buffer.readUInt32LE(offset + 4); + b *= 0x100000000; + verifuint(b + a, 0x001fffffffffffff); + return b + a; +} +exports.readUInt64LE = readUInt64LE; +function writeUInt64LE(buffer, value, offset) { + verifuint(value, 0x001fffffffffffff); + buffer.writeInt32LE(value & -1, offset); + buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); + return offset + 8; +} +exports.writeUInt64LE = writeUInt64LE; +function reverseBuffer(buffer) { + if (buffer.length < 1) + return buffer; + let j = buffer.length - 1; + let tmp = 0; + for (let i = 0; i < buffer.length / 2; i++) { + tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + j--; + } + return buffer; +} +exports.reverseBuffer = reverseBuffer; diff --git a/src/classify.js b/src/classify.js new file mode 100644 index 0000000..a2109c2 --- /dev/null +++ b/src/classify.js @@ -0,0 +1,75 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const script_1 = require("./script"); +const multisig = require("./templates/multisig"); +const nullData = require("./templates/nulldata"); +const pubKey = require("./templates/pubkey"); +const pubKeyHash = require("./templates/pubkeyhash"); +const scriptHash = require("./templates/scripthash"); +const witnessPubKeyHash = require("./templates/witnesspubkeyhash"); +const witnessScriptHash = require("./templates/witnessscripthash"); +const witnessCommitment = require("./templates/witnesscommitment"); +const types = { + P2MS: 'multisig', + NONSTANDARD: 'nonstandard', + NULLDATA: 'nulldata', + P2PK: 'pubkey', + P2PKH: 'pubkeyhash', + P2SH: 'scripthash', + P2WPKH: 'witnesspubkeyhash', + P2WSH: 'witnessscripthash', + WITNESS_COMMITMENT: 'witnesscommitment' +}; +exports.types = types; +function classifyOutput(script) { + if (witnessPubKeyHash.output.check(script)) + return types.P2WPKH; + if (witnessScriptHash.output.check(script)) + return types.P2WSH; + if (pubKeyHash.output.check(script)) + return types.P2PKH; + if (scriptHash.output.check(script)) + return types.P2SH; + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) + throw new TypeError('Invalid script'); + if (multisig.output.check(chunks)) + return types.P2MS; + if (pubKey.output.check(chunks)) + return types.P2PK; + if (witnessCommitment.output.check(chunks)) + return types.WITNESS_COMMITMENT; + if (nullData.output.check(chunks)) + return types.NULLDATA; + return types.NONSTANDARD; +} +exports.output = classifyOutput; +function classifyInput(script, allowIncomplete) { + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) + throw new TypeError('Invalid script'); + if (pubKeyHash.input.check(chunks)) + return types.P2PKH; + if (scriptHash.input.check(chunks, allowIncomplete)) + return types.P2SH; + if (multisig.input.check(chunks, allowIncomplete)) + return types.P2MS; + if (pubKey.input.check(chunks)) + return types.P2PK; + return types.NONSTANDARD; +} +exports.input = classifyInput; +function classifyWitness(script, allowIncomplete) { + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) + throw new TypeError('Invalid script'); + if (witnessPubKeyHash.input.check(chunks)) + return types.P2WPKH; + if (witnessScriptHash.input.check(chunks, allowIncomplete)) + return types.P2WSH; + return types.NONSTANDARD; +} +exports.witness = classifyWitness; diff --git a/src/crypto.js b/src/crypto.js new file mode 100644 index 0000000..4165d30 --- /dev/null +++ b/src/crypto.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const createHash = require('create-hash'); +function ripemd160(buffer) { + return createHash('rmd160').update(buffer).digest(); +} +exports.ripemd160 = ripemd160; +function sha1(buffer) { + return createHash('sha1').update(buffer).digest(); +} +exports.sha1 = sha1; +function sha256(buffer) { + return createHash('sha256').update(buffer).digest(); +} +exports.sha256 = sha256; +function hash160(buffer) { + return ripemd160(sha256(buffer)); +} +exports.hash160 = hash160; +function hash256(buffer) { + return sha256(sha256(buffer)); +} +exports.hash256 = hash256; diff --git a/src/ecpair.js b/src/ecpair.js new file mode 100644 index 0000000..d4dc94f --- /dev/null +++ b/src/ecpair.js @@ -0,0 +1,97 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const NETWORKS = require("./networks"); +const types = require("./types"); +const ecc = require('tiny-secp256k1'); +const randomBytes = require('randombytes'); +const typeforce = require('typeforce'); +const wif = require('wif'); +const isOptions = typeforce.maybe(typeforce.compile({ + compressed: types.maybe(types.Boolean), + network: types.maybe(types.Network) +})); +class ECPair { + constructor(d, Q, options) { + if (options === undefined) + options = {}; + this.compressed = options.compressed === undefined ? true : options.compressed; + this.network = options.network || NETWORKS.bitcoin; + this.__d = undefined; + this.__Q = undefined; + if (d !== undefined) + this.__d = d; + if (Q !== undefined) + this.__Q = ecc.pointCompress(Q, this.compressed); + } + get privateKey() { + return this.__d; + } + get publicKey() { + if (!this.__Q) + this.__Q = ecc.pointFromScalar(this.__d, this.compressed); + return this.__Q; + } + toWIF() { + if (!this.__d) + throw new Error('Missing private key'); + return wif.encode(this.network.wif, this.__d, this.compressed); + } + sign(hash) { + if (!this.__d) + throw new Error('Missing private key'); + return ecc.sign(hash, this.__d); + } + verify(hash, signature) { + return ecc.verify(hash, this.publicKey, signature); + } +} +function fromPrivateKey(buffer, options) { + typeforce(types.Buffer256bit, buffer); + if (!ecc.isPrivate(buffer)) + throw new TypeError('Private key not in range [1, n)'); + typeforce(isOptions, options); + return new ECPair(buffer, undefined, options); +} +exports.fromPrivateKey = fromPrivateKey; +function fromPublicKey(buffer, options) { + typeforce(ecc.isPoint, buffer); + typeforce(isOptions, options); + return new ECPair(undefined, buffer, options); +} +exports.fromPublicKey = fromPublicKey; +function fromWIF(string, network) { + const decoded = wif.decode(string); + const version = decoded.version; + // list of networks? + if (types.Array(network)) { + network = network.filter(function (x) { + return version === x.wif; + }).pop(); + if (!network) + throw new Error('Unknown network version'); + // otherwise, assume a network object (or default to bitcoin) + } + else { + network = network || NETWORKS.bitcoin; + if (version !== network.wif) + throw new Error('Invalid network version'); + } + return fromPrivateKey(decoded.privateKey, { + compressed: decoded.compressed, + network: network + }); +} +exports.fromWIF = fromWIF; +function makeRandom(options) { + typeforce(isOptions, options); + if (options === undefined) + options = {}; + const rng = options.rng || randomBytes; + let d; + do { + d = rng(32); + typeforce(types.Buffer256bit, d); + } while (!ecc.isPrivate(d)); + return fromPrivateKey(d, options); +} +exports.makeRandom = makeRandom; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..7455d4a --- /dev/null +++ b/src/index.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bip32 = require("bip32"); +exports.bip32 = bip32; +const ECPair = require("./ecpair"); +exports.ECPair = ECPair; +const address = require("./address"); +exports.address = address; +const crypto = require("./crypto"); +exports.crypto = crypto; +const networks = require("./networks"); +exports.networks = networks; +const payments = require("./payments"); +exports.payments = payments; +const script = require("./script"); +exports.script = script; +var block_1 = require("./block"); +exports.Block = block_1.Block; +var transaction_1 = require("./transaction"); +exports.Transaction = transaction_1.Transaction; +var transaction_builder_1 = require("./transaction_builder"); +exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; +var script_1 = require("./script"); +exports.opcodes = script_1.OPS; diff --git a/src/networks.js b/src/networks.js new file mode 100644 index 0000000..821cd96 --- /dev/null +++ b/src/networks.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bitcoin = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80 +}; +exports.regtest = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef +}; +exports.testnet = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef +}; diff --git a/src/payments/embed.js b/src/payments/embed.js new file mode 100644 index 0000000..7d341ab --- /dev/null +++ b/src/payments/embed.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../script"); +const lazy = require("./lazy"); +const networks_1 = require("../networks"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +function stacksEqual(a, b) { + if (a.length !== b.length) + return false; + return a.every(function (x, i) { + return x.equals(b[i]); + }); +} +// output: OP_RETURN ... +function p2data(a, opts) { + if (!a.data && + !a.output) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + data: typef.maybe(typef.arrayOf(typef.Buffer)) + }, a); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'output', function () { + if (!a.data) + return; + return bscript.compile([OPS.OP_RETURN].concat(a.data)); + }); + lazy.prop(o, 'data', function () { + if (!a.output) + return; + return bscript.decompile(a.output).slice(1); + }); + // extended validation + if (opts.validate) { + if (a.output) { + const chunks = bscript.decompile(a.output); + if (chunks[0] !== OPS.OP_RETURN) + throw new TypeError('Output is invalid'); + if (!chunks.slice(1).every(typef.Buffer)) + throw new TypeError('Output is invalid'); + if (a.data && !stacksEqual(a.data, o.data)) + throw new TypeError('Data mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2data = p2data; diff --git a/src/payments/index.js b/src/payments/index.js new file mode 100644 index 0000000..f21762d --- /dev/null +++ b/src/payments/index.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const embed_1 = require("./embed"); +exports.embed = embed_1.p2data; +const p2ms_1 = require("./p2ms"); +exports.p2ms = p2ms_1.p2ms; +const p2pk_1 = require("./p2pk"); +exports.p2pk = p2pk_1.p2pk; +const p2pkh_1 = require("./p2pkh"); +exports.p2pkh = p2pkh_1.p2pkh; +const p2sh_1 = require("./p2sh"); +exports.p2sh = p2sh_1.p2sh; +const p2wpkh_1 = require("./p2wpkh"); +exports.p2wpkh = p2wpkh_1.p2wpkh; +const p2wsh_1 = require("./p2wsh"); +exports.p2wsh = p2wsh_1.p2wsh; +// TODO +// witness commitment diff --git a/src/payments/lazy.js b/src/payments/lazy.js new file mode 100644 index 0000000..2c848e1 --- /dev/null +++ b/src/payments/lazy.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function prop(object, name, f) { + Object.defineProperty(object, name, { + configurable: true, + enumerable: true, + get: function () { + let value = f.call(this); + this[name] = value; + return value; + }, + set: function (value) { + Object.defineProperty(this, name, { + configurable: true, + enumerable: true, + value: value, + writable: true + }); + } + }); +} +exports.prop = prop; +function value(f) { + let value; + return function () { + if (value !== undefined) + return value; + value = f(); + return value; + }; +} +exports.value = value; diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js new file mode 100644 index 0000000..a45bd48 --- /dev/null +++ b/src/payments/p2ms.js @@ -0,0 +1,144 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../script"); +const lazy = require("./lazy"); +const networks_1 = require("../networks"); +const OPS = bscript.OPS; +const typef = require('typeforce'); +const ecc = require('tiny-secp256k1'); +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 +function stacksEqual(a, b) { + if (a.length !== b.length) + return false; + return a.every(function (x, i) { + return x.equals(b[i]); + }); +} +// input: OP_0 [signatures ...] +// output: m [pubKeys ...] n OP_CHECKMULTISIG +function p2ms(a, opts) { + if (!a.input && + !a.output && + !(a.pubkeys && a.m !== undefined) && + !a.signatures) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + function isAcceptableSignature(x) { + return bscript.isCanonicalScriptSignature(x) || + (opts.allowIncomplete && + (x === OPS.OP_0)) !== undefined; // eslint-disable-line + } + typef({ + network: typef.maybe(typef.Object), + m: typef.maybe(typef.Number), + n: typef.maybe(typef.Number), + output: typef.maybe(typef.Buffer), + pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), + signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + input: typef.maybe(typef.Buffer) + }, a); + const network = a.network || networks_1.bitcoin; + const o = { network }; + let chunks = []; + let decoded = false; + function decode(output) { + if (decoded) + return; + decoded = true; + chunks = bscript.decompile(output); + o.m = chunks[0] - OP_INT_BASE; // eslint-disable-line + o.n = chunks[chunks.length - 2] - OP_INT_BASE; // eslint-disable-line + o.pubkeys = chunks.slice(1, -2); + } + lazy.prop(o, 'output', function () { + if (!a.m) + return; + if (!o.n) + return; + if (!a.pubkeys) + return; + return bscript.compile([].concat(OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, OPS.OP_CHECKMULTISIG)); + }); + lazy.prop(o, 'm', function () { + if (!o.output) + return; + decode(o.output); + return o.m; + }); + lazy.prop(o, 'n', function () { + if (!o.pubkeys) + return; + return o.pubkeys.length; + }); + lazy.prop(o, 'pubkeys', function () { + if (!a.output) + return; + decode(a.output); + return o.pubkeys; + }); + lazy.prop(o, 'signatures', function () { + if (!a.input) + return; + return bscript.decompile(a.input).slice(1); + }); + lazy.prop(o, 'input', function () { + if (!a.signatures) + return; + return bscript.compile([OPS.OP_0].concat(a.signatures)); + }); + lazy.prop(o, 'witness', function () { + if (!o.input) + return; + return []; + }); + // extended validation + if (opts.validate) { + if (a.output) { + decode(a.output); + if (!typef.Number(chunks[0])) + throw new TypeError('Output is invalid'); + if (!typef.Number(chunks[chunks.length - 2])) + throw new TypeError('Output is invalid'); + if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) + throw new TypeError('Output is invalid'); + if (o.m <= 0 || // eslint-disable-line + o.n > 16 || // eslint-disable-line + o.m > o.n || // eslint-disable-line + o.n !== chunks.length - 3) + throw new TypeError('Output is invalid'); + if (!o.pubkeys.every(x => ecc.isPoint(x))) + throw new TypeError('Output is invalid'); + if (a.m !== undefined && a.m !== o.m) + throw new TypeError('m mismatch'); + if (a.n !== undefined && a.n !== o.n) + throw new TypeError('n mismatch'); + if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) + throw new TypeError('Pubkeys mismatch'); + } + if (a.pubkeys) { + if (a.n !== undefined && a.n !== a.pubkeys.length) + throw new TypeError('Pubkey count mismatch'); + o.n = a.pubkeys.length; + if (o.n < o.m) + throw new TypeError('Pubkey count cannot be less than m'); + } + if (a.signatures) { + if (a.signatures.length < o.m) + throw new TypeError('Not enough signatures provided'); + if (a.signatures.length > o.m) + throw new TypeError('Too many signatures provided'); + } + if (a.input) { + if (a.input[0] !== OPS.OP_0) + throw new TypeError('Input is invalid'); + if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) + throw new TypeError('Input has invalid signature(s)'); + if (a.signatures && !stacksEqual(a.signatures, o.signatures)) + throw new TypeError('Signature mismatch'); + if (a.m !== undefined && a.m !== a.signatures.length) + throw new TypeError('Signature count mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2ms = p2ms; diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js new file mode 100644 index 0000000..ab8654d --- /dev/null +++ b/src/payments/p2pk.js @@ -0,0 +1,80 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../script"); +const lazy = require("./lazy"); +const networks_1 = require("../networks"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); +// input: {signature} +// output: {pubKey} OP_CHECKSIG +function p2pk(a, opts) { + if (!a.input && + !a.output && + !a.pubkey && + !a.input && + !a.signature) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer) + }, a); + const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'output', function () { + if (!a.pubkey) + return; + return bscript.compile([ + a.pubkey, + OPS.OP_CHECKSIG + ]); + }); + lazy.prop(o, 'pubkey', function () { + if (!a.output) + return; + return a.output.slice(1, -1); + }); + lazy.prop(o, 'signature', function () { + if (!a.input) + return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', function () { + if (!a.signature) + return; + return bscript.compile([a.signature]); + }); + lazy.prop(o, 'witness', function () { + if (!o.input) + return; + return []; + }); + // extended validation + if (opts.validate) { + if (a.output) { + if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) + throw new TypeError('Output is invalid'); + if (!ecc.isPoint(o.pubkey)) + throw new TypeError('Output pubkey is invalid'); + if (a.pubkey && !a.pubkey.equals(o.pubkey)) + throw new TypeError('Pubkey mismatch'); + } + if (a.signature) { + if (a.input && !a.input.equals(o.input)) + throw new TypeError('Signature mismatch'); + } + if (a.input) { + if (_chunks().length !== 1) + throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(o.signature)) + throw new TypeError('Input has invalid signature'); + } + } + return Object.assign(o, a); +} +exports.p2pk = p2pk; diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js new file mode 100644 index 0000000..443464a --- /dev/null +++ b/src/payments/p2pkh.js @@ -0,0 +1,144 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../script"); +const bcrypto = require("../crypto"); +const lazy = require("./lazy"); +const networks_1 = require("../networks"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); +const bs58check = require('bs58check'); +// input: {signature} {pubkey} +// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG +function p2pkh(a, opts) { + if (!a.address && + !a.hash && + !a.output && + !a.pubkey && + !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(25)), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer) + }, a); + const _address = lazy.value(function () { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'address', function () { + if (!o.hash) + return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(network.pubKeyHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', function () { + if (a.output) + return a.output.slice(3, 23); + if (a.address) + return _address().hash; + if (a.pubkey || o.pubkey) + return bcrypto.hash160(a.pubkey || o.pubkey); // eslint-disable-line + }); + lazy.prop(o, 'output', function () { + if (!o.hash) + return; + return bscript.compile([ + OPS.OP_DUP, + OPS.OP_HASH160, + o.hash, + OPS.OP_EQUALVERIFY, + OPS.OP_CHECKSIG + ]); + }); + lazy.prop(o, 'pubkey', function () { + if (!a.input) + return; + return _chunks()[1]; + }); + lazy.prop(o, 'signature', function () { + if (!a.input) + return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', function () { + if (!a.pubkey) + return; + if (!a.signature) + return; + return bscript.compile([a.signature, a.pubkey]); + }); + lazy.prop(o, 'witness', function () { + if (!o.input) + return; + return []; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.pubKeyHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) + throw new TypeError('Invalid address'); + hash = _address().hash; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else + hash = a.hash; + } + if (a.output) { + if (a.output.length !== 25 || + a.output[0] !== OPS.OP_DUP || + a.output[1] !== OPS.OP_HASH160 || + a.output[2] !== 0x14 || + a.output[23] !== OPS.OP_EQUALVERIFY || + a.output[24] !== OPS.OP_CHECKSIG) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(3, 23); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else + hash = hash2; + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else + hash = pkh; + } + if (a.input) { + const chunks = _chunks(); + if (chunks.length !== 2) + throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(chunks[0])) + throw new TypeError('Input has invalid signature'); + if (!ecc.isPoint(chunks[1])) + throw new TypeError('Input has invalid pubkey'); + if (a.signature && !a.signature.equals(chunks[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(chunks[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(chunks[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2pkh = p2pkh; diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js new file mode 100644 index 0000000..8ec9910 --- /dev/null +++ b/src/payments/p2sh.js @@ -0,0 +1,191 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const networks_1 = require("../networks"); // eslint-disable-line +const bscript = require("../script"); +const bcrypto = require("../crypto"); +const lazy = require("./lazy"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +const bs58check = require('bs58check'); +function stacksEqual(a, b) { + if (a.length !== b.length) + return false; + return a.every(function (x, i) { + return x.equals(b[i]); + }); +} +// input: [redeemScriptSig ...] {redeemScript} +// witness: +// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL +function p2sh(a, opts) { + if (!a.address && + !a.hash && + !a.output && + !a.redeem && + !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(23)), + redeem: typef.maybe({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)) + }), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)) + }, a); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + } + const o = { network }; + const _address = lazy.value(function () { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const _redeem = lazy.value(function () { + const chunks = _chunks(); + return { + network, + output: chunks[chunks.length - 1], + input: bscript.compile(chunks.slice(0, -1)), + witness: a.witness || [] + }; + }); + // output dependents + lazy.prop(o, 'address', function () { + if (!o.hash) + return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(o.network.scriptHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', function () { + // in order of least effort + if (a.output) + return a.output.slice(2, 22); + if (a.address) + return _address().hash; + if (o.redeem && o.redeem.output) + return bcrypto.hash160(o.redeem.output); + }); + lazy.prop(o, 'output', function () { + if (!o.hash) + return; + return bscript.compile([ + OPS.OP_HASH160, + o.hash, + OPS.OP_EQUAL + ]); + }); + // input dependents + lazy.prop(o, 'redeem', function () { + if (!a.input) + return; + return _redeem(); + }); + lazy.prop(o, 'input', function () { + if (!a.redeem || !a.redeem.input || !a.redeem.output) + return; + return bscript.compile([].concat(bscript.decompile(a.redeem.input), a.redeem.output)); + }); + lazy.prop(o, 'witness', function () { + if (o.redeem && o.redeem.witness) + return o.redeem.witness; + if (o.input) + return []; + }); + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.scriptHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) + throw new TypeError('Invalid address'); + hash = _address().hash; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else + hash = a.hash; + } + if (a.output) { + if (a.output.length !== 23 || + a.output[0] !== OPS.OP_HASH160 || + a.output[1] !== 0x14 || + a.output[22] !== OPS.OP_EQUAL) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2, 22); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else + hash = hash2; + } + // inlined to prevent 'no-inner-declarations' failing + const checkRedeem = function (redeem) { + // is the redeem output empty/invalid? + if (redeem.output) { + const decompile = bscript.decompile(redeem.output); + if (!decompile || decompile.length < 1) + throw new TypeError('Redeem.output too short'); + // match hash against other sources + const hash2 = bcrypto.hash160(redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else + hash = hash2; + } + if (redeem.input) { + const hasInput = redeem.input.length > 0; + const hasWitness = redeem.witness && redeem.witness.length > 0; + if (!hasInput && !hasWitness) + throw new TypeError('Empty input'); + if (hasInput && hasWitness) + throw new TypeError('Input and witness provided'); + if (hasInput) { + const richunks = bscript.decompile(redeem.input); + if (!bscript.isPushOnly(richunks)) + throw new TypeError('Non push-only scriptSig'); + } + } + }; + if (a.input) { + const chunks = _chunks(); + if (!chunks || chunks.length < 1) + throw new TypeError('Input too short'); + if (!Buffer.isBuffer(_redeem().output)) + throw new TypeError('Input is invalid'); + checkRedeem(_redeem()); + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + if (a.input) { + const redeem = _redeem(); + if (a.redeem.output && !a.redeem.output.equals(redeem.output)) + throw new TypeError('Redeem.output mismatch'); + if (a.redeem.input && !a.redeem.input.equals(redeem.input)) + throw new TypeError('Redeem.input mismatch'); + } + checkRedeem(a.redeem); + } + if (a.witness) { + if (a.redeem && + a.redeem.witness && + !stacksEqual(a.redeem.witness, a.witness)) + throw new TypeError('Witness and redeem.witness mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2sh = p2sh; diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js new file mode 100644 index 0000000..98951c6 --- /dev/null +++ b/src/payments/p2wpkh.js @@ -0,0 +1,145 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../script"); +const bcrypto = require("../crypto"); +const lazy = require("./lazy"); +const networks_1 = require("../networks"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); +const bech32 = require('bech32'); +const EMPTY_BUFFER = Buffer.alloc(0); +// witness: {signature} {pubKey} +// input: <> +// output: OP_0 {pubKeyHash} +function p2wpkh(a, opts) { + if (!a.address && + !a.hash && + !a.output && + !a.pubkey && + !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + input: typef.maybe(typef.BufferN(0)), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.BufferN(22)), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + witness: typef.maybe(typef.arrayOf(typef.Buffer)) + }, a); + const _address = lazy.value(function () { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data) + }; + }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'address', function () { + if (!o.hash) + return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', function () { + if (a.output) + return a.output.slice(2, 22); + if (a.address) + return _address().data; + if (a.pubkey || o.pubkey) + return bcrypto.hash160(a.pubkey || o.pubkey); // eslint-disable-line + }); + lazy.prop(o, 'output', function () { + if (!o.hash) + return; + return bscript.compile([ + OPS.OP_0, + o.hash + ]); + }); + lazy.prop(o, 'pubkey', function () { + if (a.pubkey) + return a.pubkey; + if (!a.witness) + return; + return a.witness[1]; + }); + lazy.prop(o, 'signature', function () { + if (!a.witness) + return; + return a.witness[0]; + }); + lazy.prop(o, 'input', function () { + if (!o.witness) + return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', function () { + if (!a.pubkey) + return; + if (!a.signature) + return; + return [a.signature, a.pubkey]; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 20) + throw new TypeError('Invalid address data'); + hash = _address().data; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else + hash = a.hash; + } + if (a.output) { + if (a.output.length !== 22 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x14) + throw new TypeError('Output is invalid'); + if (hash.length > 0 && !hash.equals(a.output.slice(2))) + throw new TypeError('Hash mismatch'); + else + hash = a.output.slice(2); + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else + hash = pkh; + } + if (a.witness) { + if (a.witness.length !== 2) + throw new TypeError('Witness is invalid'); + if (!bscript.isCanonicalScriptSignature(a.witness[0])) + throw new TypeError('Witness has invalid signature'); + if (!ecc.isPoint(a.witness[1])) + throw new TypeError('Witness has invalid pubkey'); + if (a.signature && !a.signature.equals(a.witness[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(a.witness[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(a.witness[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2wpkh = p2wpkh; diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js new file mode 100644 index 0000000..a7e9f8b --- /dev/null +++ b/src/payments/p2wsh.js @@ -0,0 +1,178 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const networks_1 = require("../networks"); // eslint-disable-line +const bscript = require("../script"); +const bcrypto = require("../crypto"); +const lazy = require("./lazy"); +const typef = require('typeforce'); +const OPS = bscript.OPS; +const bech32 = require('bech32'); +const EMPTY_BUFFER = Buffer.alloc(0); +function stacksEqual(a, b) { + if (a.length !== b.length) + return false; + return a.every(function (x, i) { + return x.equals(b[i]); + }); +} +// input: <> +// witness: [redeemScriptSig ...] {redeemScript} +// output: OP_0 {sha256(redeemScript)} +function p2wsh(a, opts) { + if (!a.address && + !a.hash && + !a.output && + !a.redeem && + !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef({ + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(32)), + output: typef.maybe(typef.BufferN(34)), + redeem: typef.maybe({ + input: typef.maybe(typef.Buffer), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)) + }), + input: typef.maybe(typef.BufferN(0)), + witness: typef.maybe(typef.arrayOf(typef.Buffer)) + }, a); + const _address = lazy.value(function () { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data) + }; + }); + const _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input); }); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + } + const o = { network }; + lazy.prop(o, 'address', function () { + if (!o.hash) + return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', function () { + if (a.output) + return a.output.slice(2); + if (a.address) + return _address().data; + if (o.redeem && o.redeem.output) + return bcrypto.sha256(o.redeem.output); + }); + lazy.prop(o, 'output', function () { + if (!o.hash) + return; + return bscript.compile([ + OPS.OP_0, + o.hash + ]); + }); + lazy.prop(o, 'redeem', function () { + if (!a.witness) + return; + return { + output: a.witness[a.witness.length - 1], + input: EMPTY_BUFFER, + witness: a.witness.slice(0, -1) + }; + }); + lazy.prop(o, 'input', function () { + if (!o.witness) + return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', function () { + // transform redeem input to witness stack? + if (a.redeem && + a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.output && + a.redeem.output.length > 0) { + const stack = bscript.toStack(_rchunks()); + // assign, and blank the existing input + o.redeem = Object.assign({ witness: stack }, a.redeem); + o.redeem.input = EMPTY_BUFFER; + return [].concat(stack, a.redeem.output); + } + if (!a.redeem) + return; + if (!a.redeem.output) + return; + if (!a.redeem.witness) + return; + return [].concat(a.redeem.witness, a.redeem.output); + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().prefix !== network.bech32) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + hash = _address().data; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else + hash = a.hash; + } + if (a.output) { + if (a.output.length !== 34 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x20) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else + hash = hash2; + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + // is there two redeem sources? + if (a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.witness && + a.redeem.witness.length > 0) + throw new TypeError('Ambiguous witness source'); + // is the redeem output non-empty? + if (a.redeem.output) { + if (bscript.decompile(a.redeem.output).length === 0) + throw new TypeError('Redeem.output is invalid'); + // match hash against other sources + const hash2 = bcrypto.sha256(a.redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else + hash = hash2; + } + if (a.redeem.input && !bscript.isPushOnly(_rchunks())) + throw new TypeError('Non push-only scriptSig'); + if (a.witness && a.redeem.witness && !stacksEqual(a.witness, a.redeem.witness)) + throw new TypeError('Witness and redeem.witness mismatch'); + } + if (a.witness) { + if (a.redeem && a.redeem.output && !a.redeem.output.equals(a.witness[a.witness.length - 1])) + throw new TypeError('Witness and redeem.output mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2wsh = p2wsh; diff --git a/src/script.js b/src/script.js new file mode 100644 index 0000000..3d115cb --- /dev/null +++ b/src/script.js @@ -0,0 +1,188 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const types = require("./types"); +const scriptNumber = require("./script_number"); +const scriptSignature = require("./script_signature"); +const bip66 = require('bip66'); +const ecc = require('tiny-secp256k1'); +const pushdata = require('pushdata-bitcoin'); +const typeforce = require('typeforce'); +exports.OPS = require('bitcoin-ops'); +const REVERSE_OPS = require('bitcoin-ops/map'); +const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1 +function isOPInt(value) { + return types.Number(value) && + ((value === exports.OPS.OP_0) || + (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || + (value === exports.OPS.OP_1NEGATE)); +} +function isPushOnlyChunk(value) { + return types.Buffer(value) || isOPInt(value); +} +function isPushOnly(value) { + return types.Array(value) && value.every(isPushOnlyChunk); +} +exports.isPushOnly = isPushOnly; +function asMinimalOP(buffer) { + if (buffer.length === 0) + return exports.OPS.OP_0; + if (buffer.length !== 1) + return; + if (buffer[0] >= 1 && buffer[0] <= 16) + return OP_INT_BASE + buffer[0]; + if (buffer[0] === 0x81) + return exports.OPS.OP_1NEGATE; +} +function chunksIsBuffer(buf) { + return Buffer.isBuffer(buf); +} +function chunksIsArray(buf) { + return types.Array(buf); +} +function singleChunkIsBuffer(buf) { + return Buffer.isBuffer(buf); +} +function compile(chunks) { + // TODO: remove me + if (chunksIsBuffer(chunks)) + return chunks; + typeforce(types.Array, chunks); + const bufferSize = chunks.reduce(function (accum, chunk) { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { + return accum + 1; + } + return accum + pushdata.encodingLength(chunk.length) + chunk.length; + } + // opcode + return accum + 1; + }, 0.0); + const buffer = Buffer.allocUnsafe(bufferSize); + let offset = 0; + chunks.forEach(function (chunk) { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + const opcode = asMinimalOP(chunk); + if (opcode !== undefined) { + buffer.writeUInt8(opcode, offset); + offset += 1; + return; + } + offset += pushdata.encode(buffer, chunk.length, offset); + chunk.copy(buffer, offset); + offset += chunk.length; + // opcode + } + else { + buffer.writeUInt8(chunk, offset); + offset += 1; + } + }); + if (offset !== buffer.length) + throw new Error('Could not decode chunks'); + return buffer; +} +exports.compile = compile; +function decompile(buffer) { + // TODO: remove me + if (chunksIsArray(buffer)) + return buffer; + typeforce(types.Buffer, buffer); + const chunks = []; + let i = 0; + while (i < buffer.length) { + const opcode = buffer[i]; + // data chunk + if ((opcode > exports.OPS.OP_0) && (opcode <= exports.OPS.OP_PUSHDATA4)) { + const d = pushdata.decode(buffer, i); + // did reading a pushDataInt fail? + if (d === null) + return null; + i += d.size; + // attempt to read too much data? + if (i + d.number > buffer.length) + return null; + const data = buffer.slice(i, i + d.number); + i += d.number; + // decompile minimally + const op = asMinimalOP(data); + if (op !== undefined) { + chunks.push(op); + } + else { + chunks.push(data); + } + // opcode + } + else { + chunks.push(opcode); + i += 1; + } + } + return chunks; +} +exports.decompile = decompile; +function toASM(chunks) { + if (chunksIsBuffer(chunks)) { + chunks = decompile(chunks); + } + return chunks.map(function (chunk) { + // data? + if (singleChunkIsBuffer(chunk)) { + const op = asMinimalOP(chunk); + if (op === undefined) + return chunk.toString('hex'); + chunk = op; + } + // opcode! + return REVERSE_OPS[chunk]; + }).join(' '); +} +exports.toASM = toASM; +function fromASM(asm) { + typeforce(types.String, asm); + return compile(asm.split(' ').map(function (chunkStr) { + // opcode? + if (exports.OPS[chunkStr] !== undefined) + return exports.OPS[chunkStr]; + typeforce(types.Hex, chunkStr); + // data! + return Buffer.from(chunkStr, 'hex'); + })); +} +exports.fromASM = fromASM; +function toStack(chunks) { + chunks = decompile(chunks); + typeforce(isPushOnly, chunks); + return chunks.map(function (op) { + if (singleChunkIsBuffer(op)) + return op; + if (op === exports.OPS.OP_0) + return Buffer.allocUnsafe(0); + return scriptNumber.encode(op - OP_INT_BASE); + }); +} +exports.toStack = toStack; +function isCanonicalPubKey(buffer) { + return ecc.isPoint(buffer); +} +exports.isCanonicalPubKey = isCanonicalPubKey; +function isDefinedHashType(hashType) { + const hashTypeMod = hashType & ~0x80; + // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE + return hashTypeMod > 0x00 && hashTypeMod < 0x04; +} +exports.isDefinedHashType = isDefinedHashType; +function isCanonicalScriptSignature(buffer) { + if (!Buffer.isBuffer(buffer)) + return false; + if (!isDefinedHashType(buffer[buffer.length - 1])) + return false; + return bip66.check(buffer.slice(0, -1)); +} +exports.isCanonicalScriptSignature = isCanonicalScriptSignature; +exports.number = scriptNumber; +exports.signature = scriptSignature; diff --git a/src/script_number.js b/src/script_number.js new file mode 100644 index 0000000..da12de6 --- /dev/null +++ b/src/script_number.js @@ -0,0 +1,60 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function decode(buffer, maxLength, minimal) { + maxLength = maxLength || 4; + minimal = minimal === undefined ? true : minimal; + const length = buffer.length; + if (length === 0) + return 0; + if (length > maxLength) + throw new TypeError('Script number overflow'); + if (minimal) { + if ((buffer[length - 1] & 0x7f) === 0) { + if (length <= 1 || (buffer[length - 2] & 0x80) === 0) + throw new Error('Non-minimally encoded script number'); + } + } + // 40-bit + if (length === 5) { + const a = buffer.readUInt32LE(0); + const b = buffer.readUInt8(4); + if (b & 0x80) + return -(((b & ~0x80) * 0x100000000) + a); + return (b * 0x100000000) + a; + } + // 32-bit / 24-bit / 16-bit / 8-bit + let result = 0; + for (var i = 0; i < length; ++i) { + result |= buffer[i] << (8 * i); + } + if (buffer[length - 1] & 0x80) + return -(result & ~(0x80 << (8 * (length - 1)))); + return result; +} +exports.decode = decode; +function scriptNumSize(i) { + return i > 0x7fffffff ? 5 + : i > 0x7fffff ? 4 + : i > 0x7fff ? 3 + : i > 0x7f ? 2 + : i > 0x00 ? 1 + : 0; +} +function encode(number) { + let value = Math.abs(number); + const size = scriptNumSize(value); + const buffer = Buffer.allocUnsafe(size); + const negative = number < 0; + for (var i = 0; i < size; ++i) { + buffer.writeUInt8(value & 0xff, i); + value >>= 8; + } + if (buffer[size - 1] & 0x80) { + buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + } + else if (negative) { + buffer[size - 1] |= 0x80; + } + return buffer; +} +exports.encode = encode; diff --git a/src/script_signature.js b/src/script_signature.js new file mode 100644 index 0000000..c3372cd --- /dev/null +++ b/src/script_signature.js @@ -0,0 +1,58 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const types = require("./types"); +const bip66 = require('bip66'); +const typeforce = require('typeforce'); +const ZERO = Buffer.alloc(1, 0); +function toDER(x) { + let i = 0; + while (x[i] === 0) + ++i; + if (i === x.length) + return ZERO; + x = x.slice(i); + if (x[0] & 0x80) + return Buffer.concat([ZERO, x], 1 + x.length); + return x; +} +function fromDER(x) { + if (x[0] === 0x00) + x = x.slice(1); + const buffer = Buffer.alloc(32, 0); + const bstart = Math.max(0, 32 - x.length); + x.copy(buffer, bstart); + return buffer; +} +// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) +function decode(buffer) { + const hashType = buffer.readUInt8(buffer.length - 1); + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); + const decode = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decode.r); + const s = fromDER(decode.s); + return { + signature: Buffer.concat([r, s], 64), + hashType: hashType + }; +} +exports.decode = decode; +function encode(signature, hashType) { + typeforce({ + signature: types.BufferN(64), + hashType: types.UInt8 + }, { signature, hashType }); + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); + const hashTypeBuffer = Buffer.allocUnsafe(1); + hashTypeBuffer.writeUInt8(hashType, 0); + const r = toDER(signature.slice(0, 32)); + const s = toDER(signature.slice(32, 64)); + return Buffer.concat([ + bip66.encode(r, s), + hashTypeBuffer + ]); +} +exports.encode = encode; diff --git a/src/templates/multisig/index.js b/src/templates/multisig/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/multisig/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.js new file mode 100644 index 0000000..f8dd3d3 --- /dev/null +++ b/src/templates/multisig/input.js @@ -0,0 +1,21 @@ +"use strict"; +// OP_0 [signatures ...] +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function partialSignature(value) { + return value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value); +} +function check(script, allowIncomplete) { + const chunks = bscript.decompile(script); + if (chunks.length < 2) + return false; + if (chunks[0] !== script_1.OPS.OP_0) + return false; + if (allowIncomplete) { + return chunks.slice(1).every(partialSignature); + } + return chunks.slice(1).every(bscript.isCanonicalScriptSignature); +} +exports.check = check; +check.toJSON = function () { return 'multisig input'; }; diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.js new file mode 100644 index 0000000..811ed12 --- /dev/null +++ b/src/templates/multisig/output.js @@ -0,0 +1,34 @@ +"use strict"; +// m [pubKeys ...] n OP_CHECKMULTISIG +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const types = require("../../types"); +const script_1 = require("../../script"); +const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1 +function check(script, allowIncomplete) { + const chunks = bscript.decompile(script); + if (chunks.length < 4) + return false; + if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) + return false; + if (!types.Number(chunks[0])) + return false; + if (!types.Number(chunks[chunks.length - 2])) + return false; + const m = chunks[0] - OP_INT_BASE; + const n = chunks[chunks.length - 2] - OP_INT_BASE; + if (m <= 0) + return false; + if (n > 16) + return false; + if (m > n) + return false; + if (n !== chunks.length - 3) + return false; + if (allowIncomplete) + return true; + const keys = chunks.slice(1, -2); + return keys.every(bscript.isCanonicalPubKey); +} +exports.check = check; +check.toJSON = function () { return 'multi-sig output'; }; diff --git a/src/templates/nulldata.js b/src/templates/nulldata.js new file mode 100644 index 0000000..fd5320d --- /dev/null +++ b/src/templates/nulldata.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// OP_RETURN {data} +const bscript = require("../script"); +const OPS = bscript.OPS; +function check(script) { + const buffer = bscript.compile(script); + return buffer.length > 1 && + buffer[0] === OPS.OP_RETURN; +} +exports.check = check; +check.toJSON = function () { return 'null data output'; }; +const output = { check }; +exports.output = output; diff --git a/src/templates/pubkey/index.js b/src/templates/pubkey/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/pubkey/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.js new file mode 100644 index 0000000..bc5e566 --- /dev/null +++ b/src/templates/pubkey/input.js @@ -0,0 +1,11 @@ +"use strict"; +// {signature} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +function check(script) { + const chunks = bscript.decompile(script); + return chunks.length === 1 && + bscript.isCanonicalScriptSignature(chunks[0]); +} +exports.check = check; +check.toJSON = function () { return 'pubKey input'; }; diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.js new file mode 100644 index 0000000..043150e --- /dev/null +++ b/src/templates/pubkey/output.js @@ -0,0 +1,13 @@ +"use strict"; +// {pubKey} OP_CHECKSIG +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function check(script) { + const chunks = bscript.decompile(script); + return chunks.length === 2 && + bscript.isCanonicalPubKey(chunks[0]) && + chunks[1] === script_1.OPS.OP_CHECKSIG; +} +exports.check = check; +check.toJSON = function () { return 'pubKey output'; }; diff --git a/src/templates/pubkeyhash/index.js b/src/templates/pubkeyhash/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/pubkeyhash/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.js new file mode 100644 index 0000000..29a684e --- /dev/null +++ b/src/templates/pubkeyhash/input.js @@ -0,0 +1,12 @@ +"use strict"; +// {signature} {pubKey} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +function check(script) { + const chunks = bscript.decompile(script); + return chunks.length === 2 && + bscript.isCanonicalScriptSignature(chunks[0]) && + bscript.isCanonicalPubKey(chunks[1]); +} +exports.check = check; +check.toJSON = function () { return 'pubKeyHash input'; }; diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.js new file mode 100644 index 0000000..9016c6a --- /dev/null +++ b/src/templates/pubkeyhash/output.js @@ -0,0 +1,16 @@ +"use strict"; +// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function check(script) { + const buffer = bscript.compile(script); + return buffer.length === 25 && + buffer[0] === script_1.OPS.OP_DUP && + buffer[1] === script_1.OPS.OP_HASH160 && + buffer[2] === 0x14 && + buffer[23] === script_1.OPS.OP_EQUALVERIFY && + buffer[24] === script_1.OPS.OP_CHECKSIG; +} +exports.check = check; +check.toJSON = function () { return 'pubKeyHash output'; }; diff --git a/src/templates/scripthash/index.js b/src/templates/scripthash/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/scripthash/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.js new file mode 100644 index 0000000..c40bc26 --- /dev/null +++ b/src/templates/scripthash/input.js @@ -0,0 +1,43 @@ +"use strict"; +// {serialized scriptPubKey script} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const p2ms = require("../multisig"); +const p2pk = require("../pubkey"); +const p2pkh = require("../pubkeyhash"); +const p2wpkho = require("../witnesspubkeyhash/output"); +const p2wsho = require("../witnessscripthash/output"); +function check(script, allowIncomplete) { + const chunks = bscript.decompile(script); + if (chunks.length < 1) + return false; + const lastChunk = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(lastChunk)) + return false; + const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))); + const redeemScriptChunks = bscript.decompile(lastChunk); + // is redeemScript a valid script? + if (!redeemScriptChunks) + return false; + // is redeemScriptSig push only? + if (!bscript.isPushOnly(scriptSigChunks)) + return false; + // is witness? + if (chunks.length === 1) { + return p2wsho.check(redeemScriptChunks) || + p2wpkho.check(redeemScriptChunks); + } + // match types + if (p2pkh.input.check(scriptSigChunks) && + p2pkh.output.check(redeemScriptChunks)) + return true; + if (p2ms.input.check(scriptSigChunks, allowIncomplete) && + p2ms.output.check(redeemScriptChunks)) + return true; + if (p2pk.input.check(scriptSigChunks) && + p2pk.output.check(redeemScriptChunks)) + return true; + return false; +} +exports.check = check; +check.toJSON = function () { return 'scriptHash input'; }; diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.js new file mode 100644 index 0000000..bd38d5a --- /dev/null +++ b/src/templates/scripthash/output.js @@ -0,0 +1,14 @@ +"use strict"; +// OP_HASH160 {scriptHash} OP_EQUAL +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function check(script) { + const buffer = bscript.compile(script); + return buffer.length === 23 && + buffer[0] === script_1.OPS.OP_HASH160 && + buffer[1] === 0x14 && + buffer[22] === script_1.OPS.OP_EQUAL; +} +exports.check = check; +check.toJSON = function () { return 'scriptHash output'; }; diff --git a/src/templates/witnesscommitment/index.js b/src/templates/witnesscommitment/index.js new file mode 100644 index 0000000..aff0618 --- /dev/null +++ b/src/templates/witnesscommitment/index.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const output = require("./output"); +exports.output = output; diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.js new file mode 100644 index 0000000..95a8bc1 --- /dev/null +++ b/src/templates/witnesscommitment/output.js @@ -0,0 +1,30 @@ +"use strict"; +// OP_RETURN {aa21a9ed} {commitment} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const types = require("../../types"); +const typeforce = require('typeforce'); +const script_1 = require("../../script"); +const HEADER = Buffer.from('aa21a9ed', 'hex'); +function check(script) { + const buffer = bscript.compile(script); + return buffer.length > 37 && + buffer[0] === script_1.OPS.OP_RETURN && + buffer[1] === 0x24 && + buffer.slice(2, 6).equals(HEADER); +} +exports.check = check; +check.toJSON = function () { return 'Witness commitment output'; }; +function encode(commitment) { + typeforce(types.Hash256bit, commitment); + const buffer = Buffer.allocUnsafe(36); + HEADER.copy(buffer, 0); + commitment.copy(buffer, 4); + return bscript.compile([script_1.OPS.OP_RETURN, buffer]); +} +exports.encode = encode; +function decode(buffer) { + typeforce(check, buffer); + return bscript.decompile(buffer)[1].slice(4, 36); +} +exports.decode = decode; diff --git a/src/templates/witnesspubkeyhash/index.js b/src/templates/witnesspubkeyhash/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/witnesspubkeyhash/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.js new file mode 100644 index 0000000..131a49e --- /dev/null +++ b/src/templates/witnesspubkeyhash/input.js @@ -0,0 +1,15 @@ +"use strict"; +// {signature} {pubKey} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +function isCompressedCanonicalPubKey(pubKey) { + return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; +} +function check(script) { + const chunks = bscript.decompile(script); + return chunks.length === 2 && + bscript.isCanonicalScriptSignature(chunks[0]) && + isCompressedCanonicalPubKey(chunks[1]); +} +exports.check = check; +check.toJSON = function () { return 'witnessPubKeyHash input'; }; diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.js new file mode 100644 index 0000000..2fb6e15 --- /dev/null +++ b/src/templates/witnesspubkeyhash/output.js @@ -0,0 +1,13 @@ +"use strict"; +// OP_0 {pubKeyHash} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function check(script) { + const buffer = bscript.compile(script); + return buffer.length === 22 && + buffer[0] === script_1.OPS.OP_0 && + buffer[1] === 0x14; +} +exports.check = check; +check.toJSON = function () { return 'Witness pubKeyHash output'; }; diff --git a/src/templates/witnessscripthash/index.js b/src/templates/witnessscripthash/index.js new file mode 100644 index 0000000..85a15b9 --- /dev/null +++ b/src/templates/witnessscripthash/index.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const input = require("./input"); +exports.input = input; +const output = require("./output"); +exports.output = output; diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.js new file mode 100644 index 0000000..255ea86 --- /dev/null +++ b/src/templates/witnessscripthash/input.js @@ -0,0 +1,34 @@ +"use strict"; +// {serialized scriptPubKey script} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const typeforce = require('typeforce'); +const p2ms = require("../multisig"); +const p2pk = require("../pubkey"); +const p2pkh = require("../pubkeyhash"); +function check(chunks, allowIncomplete) { + typeforce(typeforce.Array, chunks); + if (chunks.length < 1) + return false; + const witnessScript = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(witnessScript)) + return false; + const witnessScriptChunks = bscript.decompile(witnessScript); + // is witnessScript a valid script? + if (!witnessScriptChunks || witnessScriptChunks.length === 0) + return false; + const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); + // match types + if (p2pkh.input.check(witnessRawScriptSig) && + p2pkh.output.check(witnessScriptChunks)) + return true; + if (p2ms.input.check(witnessRawScriptSig, allowIncomplete) && + p2ms.output.check(witnessScriptChunks)) + return true; + if (p2pk.input.check(witnessRawScriptSig) && + p2pk.output.check(witnessScriptChunks)) + return true; + return false; +} +exports.check = check; +check.toJSON = function () { return 'witnessScriptHash input'; }; diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.js new file mode 100644 index 0000000..994a75a --- /dev/null +++ b/src/templates/witnessscripthash/output.js @@ -0,0 +1,13 @@ +"use strict"; +// OP_0 {scriptHash} +Object.defineProperty(exports, "__esModule", { value: true }); +const bscript = require("../../script"); +const script_1 = require("../../script"); +function check(script) { + const buffer = bscript.compile(script); + return buffer.length === 34 && + buffer[0] === script_1.OPS.OP_0 && + buffer[1] === 0x20; +} +exports.check = check; +check.toJSON = function () { return 'Witness scriptHash output'; }; diff --git a/src/transaction.js b/src/transaction.js new file mode 100644 index 0000000..6619b79 --- /dev/null +++ b/src/transaction.js @@ -0,0 +1,448 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bcrypto = require("./crypto"); +const bscript = require("./script"); +const types = require("./types"); +const bufferutils = require("./bufferutils"); +const bufferutils_1 = require("./bufferutils"); +const script_1 = require("./script"); +const typeforce = require('typeforce'); +const varuint = require('varuint-bitcoin'); +function varSliceSize(someScript) { + const length = someScript.length; + return varuint.encodingLength(length) + length; +} +function vectorSize(someVector) { + const length = someVector.length; + return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0); +} +const EMPTY_SCRIPT = Buffer.allocUnsafe(0); +const EMPTY_WITNESS = []; +const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); +const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); +const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); +const BLANK_OUTPUT = { + script: EMPTY_SCRIPT, + valueBuffer: VALUE_UINT64_MAX +}; +function isOutput(out) { + return out.value !== undefined; +} +class Transaction { + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; + } + static fromBuffer(buffer, __noStrict) { + let offset = 0; + function readSlice(n) { + offset += n; + return buffer.slice(offset - n, offset); + } + function readUInt32() { + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; + } + function readInt32() { + const i = buffer.readInt32LE(offset); + offset += 4; + return i; + } + function readUInt64() { + const i = bufferutils.readUInt64LE(buffer, offset); + offset += 8; + return i; + } + function readVarInt() { + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; + } + function readVarSlice() { + return readSlice(readVarInt()); + } + function readVector() { + const count = readVarInt(); + const vector = []; + for (var i = 0; i < count; i++) + vector.push(readVarSlice()); + return vector; + } + const tx = new Transaction(); + tx.version = readInt32(); + const marker = buffer.readUInt8(offset); + const flag = buffer.readUInt8(offset + 1); + let hasWitnesses = false; + if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG) { + offset += 2; + hasWitnesses = true; + } + const vinLen = readVarInt(); + for (var i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readVarSlice(), + sequence: readUInt32(), + witness: EMPTY_WITNESS + }); + } + const voutLen = readVarInt(); + for (i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readVarSlice() + }); + } + if (hasWitnesses) { + for (i = 0; i < vinLen; ++i) { + tx.ins[i].witness = readVector(); + } + // was this pointless? + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); + } + tx.locktime = readUInt32(); + if (__noStrict) + return tx; + if (offset !== buffer.length) + throw new Error('Transaction has unexpected data'); + return tx; + } + static fromHex(hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + } + static isCoinbaseHash(buffer) { + typeforce(types.Hash256bit, buffer); + for (var i = 0; i < 32; ++i) { + if (buffer[i] !== 0) + return false; + } + return true; + } + isCoinbase() { + return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash); + } + addInput(hash, index, sequence, scriptSig) { + typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE; + } + // Add the input and return the input's index + return (this.ins.push({ + hash: hash, + index: index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS + }) - 1); + } + addOutput(scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value: value + }) - 1); + } + hasWitnesses() { + return this.ins.some((x) => { + return x.witness.length !== 0; + }); + } + weight() { + const base = this.__byteLength(false); + const total = this.__byteLength(true); + return base * 3 + total; + } + virtualSize() { + return Math.ceil(this.weight() / 4); + } + byteLength() { + return this.__byteLength(true); + } + __byteLength(__allowWitness) { + const hasWitnesses = __allowWitness && this.hasWitnesses(); + return ((hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) : 0)); + } + clone() { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; + newTx.ins = this.ins.map((txIn) => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness + }; + }); + newTx.outs = this.outs.map((txOut) => { + return { + script: txOut.script, + value: txOut.value + }; + }); + return newTx; + } + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex, prevOutScript, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments); + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) + return ONE; + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { + return x !== script_1.OPS.OP_CODESEPARATOR; + })); + const txTmp = this.clone(); + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = []; + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) + return; + input.sequence = 0; + }); + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } + else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) + return ONE; + // truncate outputs after + txTmp.outs.length = inIndex + 1; + // "blank" outputs before + for (var i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT; + } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) + return; + input.sequence = 0; + }); + } + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; + // SIGHASH_ALL: only ignore input scripts + } + else { + // "blank" others input scripts + txTmp.ins.forEach((input) => { + input.script = EMPTY_SCRIPT; + }); + txTmp.ins[inIndex].script = ourScript; + } + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); + return bcrypto.hash256(buffer); + } + hashForWitnessV0(inIndex, prevOutScript, value, hashType) { + typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments); + let tbuffer = Buffer.from([]); + let toffset = 0; + function writeSlice(slice) { + toffset += slice.copy(tbuffer, toffset); + } + function writeUInt32(i) { + toffset = tbuffer.writeUInt32LE(i, toffset); + } + function writeUInt64(i) { + toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset); + } + function writeVarInt(i) { + varuint.encode(i, tbuffer, toffset); + toffset += varuint.encode.bytes; + } + function writeVarSlice(slice) { + writeVarInt(slice.length); + writeSlice(slice); + } + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + toffset = 0; + this.ins.forEach((txIn) => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.hash256(tbuffer); + } + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + toffset = 0; + this.ins.forEach((txIn) => { + writeUInt32(txIn.sequence); + }); + hashSequence = bcrypto.hash256(tbuffer); + } + if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0); + tbuffer = Buffer.allocUnsafe(txOutsSize); + toffset = 0; + this.outs.forEach((out) => { + writeUInt64(out.value); + writeVarSlice(out.script); + }); + hashOutputs = bcrypto.hash256(tbuffer); + } + else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { + const output = this.outs[inIndex]; + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + toffset = 0; + writeUInt64(output.value); + writeVarSlice(output.script); + hashOutputs = bcrypto.hash256(tbuffer); + } + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + toffset = 0; + const input = this.ins[inIndex]; + writeUInt32(this.version); + writeSlice(hashPrevouts); + writeSlice(hashSequence); + writeSlice(input.hash); + writeUInt32(input.index); + writeVarSlice(prevOutScript); + writeUInt64(value); + writeUInt32(input.sequence); + writeSlice(hashOutputs); + writeUInt32(this.locktime); + writeUInt32(hashType); + return bcrypto.hash256(tbuffer); + } + getHash(forWitness) { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) + return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); + } + getId() { + // transaction hash's are displayed in reverse order + return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex'); + } + toBuffer(buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true); + } + __toBuffer(buffer, initialOffset, __allowWitness) { + if (!buffer) + buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)); + let offset = initialOffset || 0; + function writeSlice(slice) { + offset += slice.copy(buffer, offset); + } + function writeUInt8(i) { + offset = buffer.writeUInt8(i, offset); + } + function writeUInt32(i) { + offset = buffer.writeUInt32LE(i, offset); + } + function writeInt32(i) { + offset = buffer.writeInt32LE(i, offset); + } + function writeUInt64(i) { + offset = bufferutils.writeUInt64LE(buffer, i, offset); + } + function writeVarInt(i) { + varuint.encode(i, buffer, offset); + offset += varuint.encode.bytes; + } + function writeVarSlice(slice) { + writeVarInt(slice.length); + writeSlice(slice); + } + function writeVector(vector) { + writeVarInt(vector.length); + vector.forEach(writeVarSlice); + } + writeInt32(this.version); + const hasWitnesses = __allowWitness && this.hasWitnesses(); + if (hasWitnesses) { + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); + } + writeVarInt(this.ins.length); + this.ins.forEach((txIn) => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + writeVarSlice(txIn.script); + writeUInt32(txIn.sequence); + }); + writeVarInt(this.outs.length); + this.outs.forEach((txOut) => { + if (isOutput(txOut)) { + writeUInt64(txOut.value); + } + else { + writeSlice(txOut.valueBuffer); + } + writeVarSlice(txOut.script); + }); + if (hasWitnesses) { + this.ins.forEach((input) => { + writeVector(input.witness); + }); + } + writeUInt32(this.locktime); + // avoid slicing unless necessary + if (initialOffset !== undefined) + return buffer.slice(initialOffset, offset); + return buffer; + } + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } +} +Transaction.DEFAULT_SEQUENCE = 0xffffffff; +Transaction.SIGHASH_ALL = 0x01; +Transaction.SIGHASH_NONE = 0x02; +Transaction.SIGHASH_SINGLE = 0x03; +Transaction.SIGHASH_ANYONECANPAY = 0x80; +Transaction.ADVANCED_TRANSACTION_MARKER = 0x00; +Transaction.ADVANCED_TRANSACTION_FLAG = 0x01; +exports.Transaction = Transaction; diff --git a/src/transaction_builder.js b/src/transaction_builder.js new file mode 100644 index 0000000..2121156 --- /dev/null +++ b/src/transaction_builder.js @@ -0,0 +1,699 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const networks = require("./networks"); +const bufferutils_1 = require("./bufferutils"); +const transaction_1 = require("./transaction"); +const ECPair = require("./ecpair"); +const types = require("./types"); +const baddress = require("./address"); +const bcrypto = require("./crypto"); +const bscript = require("./script"); +const payments = require("./payments"); +const classify = require("./classify"); +const script_1 = require("./script"); +const typeforce = require('typeforce'); +const SCRIPT_TYPES = classify.types; +function txIsString(tx) { + return typeof tx === 'string' || tx instanceof String; +} +function txIsTransaction(tx) { + return tx instanceof transaction_1.Transaction; +} +class TransactionBuilder { + constructor(network, maximumFeeRate) { + this.__prevTxSet = {}; + this.network = network || networks.bitcoin; + // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) + this.maximumFeeRate = maximumFeeRate || 2500; + this.__inputs = []; + this.__tx = new transaction_1.Transaction(); + this.__tx.version = 2; + } + static fromTransaction(transaction, network) { + const txb = new TransactionBuilder(network); + // Copy transaction fields + txb.setVersion(transaction.version); + txb.setLockTime(transaction.locktime); + // Copy outputs (done first to avoid signature invalidation) + transaction.outs.forEach(txOut => { + txb.addOutput(txOut.script, txOut.value); + }); + // Copy inputs + transaction.ins.forEach(txIn => { + txb.__addInputUnsafe(txIn.hash, txIn.index, { + sequence: txIn.sequence, + script: txIn.script, + witness: txIn.witness + }); + }); + // fix some things not possible through the public API + txb.__inputs.forEach((input, i) => { + fixMultisigOrder(input, transaction, i); + }); + return txb; + } + setLockTime(locktime) { + typeforce(types.UInt32, locktime); + // if any signatures exist, throw + if (this.__inputs.some(input => { + if (!input.signatures) + return false; + return input.signatures.some(s => s !== undefined); + })) { + throw new Error('No, this would invalidate signatures'); + } + this.__tx.locktime = locktime; + } + setVersion(version) { + typeforce(types.UInt32, version); + // XXX: this might eventually become more complex depending on what the versions represent + this.__tx.version = version; + } + addInput(txHash, vout, sequence, prevOutScript) { + if (!this.__canModifyInputs()) { + throw new Error('No, this would invalidate signatures'); + } + let value = undefined; + // is it a hex string? + if (txIsString(txHash)) { + // transaction hashs's are displayed in reverse order, un-reverse it + txHash = bufferutils_1.reverseBuffer(Buffer.from(txHash, 'hex')); + // is it a Transaction object? + } + else if (txIsTransaction(txHash)) { + const txOut = txHash.outs[vout]; + prevOutScript = txOut.script; + value = txOut.value; + txHash = txHash.getHash(false); + } + return this.__addInputUnsafe(txHash, vout, { + sequence: sequence, + prevOutScript: prevOutScript, + value: value + }); + } + __addInputUnsafe(txHash, vout, options) { + if (transaction_1.Transaction.isCoinbaseHash(txHash)) { + throw new Error('coinbase inputs not supported'); + } + const prevTxOut = txHash.toString('hex') + ':' + vout; + if (this.__prevTxSet[prevTxOut] !== undefined) + throw new Error('Duplicate TxOut: ' + prevTxOut); + let input = {}; + // derive what we can from the scriptSig + if (options.script !== undefined) { + input = expandInput(options.script, options.witness || []); + } + // if an input value was given, retain it + if (options.value !== undefined) { + input.value = options.value; + } + // derive what we can from the previous transactions output script + if (!input.prevOutScript && options.prevOutScript) { + let prevOutType; + if (!input.pubkeys && !input.signatures) { + const expanded = expandOutput(options.prevOutScript); + if (expanded.pubkeys) { + input.pubkeys = expanded.pubkeys; + input.signatures = expanded.signatures; + } + prevOutType = expanded.type; + } + input.prevOutScript = options.prevOutScript; + input.prevOutType = prevOutType || classify.output(options.prevOutScript); + } + const vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig); + this.__inputs[vin] = input; + this.__prevTxSet[prevTxOut] = true; + return vin; + } + addOutput(scriptPubKey, value) { + if (!this.__canModifyOutputs()) { + throw new Error('No, this would invalidate signatures'); + } + // Attempt to get a script if it's a base58 or bech32 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); + } + return this.__tx.addOutput(scriptPubKey, value); + } + build() { + return this.__build(false); + } + buildIncomplete() { + return this.__build(true); + } + __build(allowIncomplete) { + if (!allowIncomplete) { + if (!this.__tx.ins.length) + throw new Error('Transaction has no inputs'); + if (!this.__tx.outs.length) + throw new Error('Transaction has no outputs'); + } + const tx = this.__tx.clone(); + // create script signatures from inputs + this.__inputs.forEach((input, i) => { + if (!input.prevOutType && !allowIncomplete) + throw new Error('Transaction is not complete'); + const result = build(input.prevOutType, input, allowIncomplete); + if (!result) { + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) + throw new Error('Unknown input type'); + if (!allowIncomplete) + throw new Error('Not enough information'); + return; + } + tx.setInputScript(i, result.input); + tx.setWitness(i, result.witness); + }); + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__overMaximumFees(tx.virtualSize())) { + throw new Error('Transaction has absurd fees'); + } + } + return tx; + } + sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { + // TODO: remove keyPair.network matching in 4.0.0 + if (keyPair.network && keyPair.network !== this.network) + throw new TypeError('Inconsistent network'); + if (!this.__inputs[vin]) + throw new Error('No input at index: ' + vin); + hashType = hashType || transaction_1.Transaction.SIGHASH_ALL; + if (this.__needsOutputs(hashType)) + throw new Error('Transaction needs outputs'); + const input = this.__inputs[vin]; + // if redeemScript was previously provided, enforce consistency + if (input.redeemScript !== undefined && + redeemScript && + !input.redeemScript.equals(redeemScript)) { + throw new Error('Inconsistent redeemScript'); + } + const ourPubKey = keyPair.publicKey || keyPair.getPublicKey(); + if (!canSign(input)) { + if (witnessValue !== undefined) { + if (input.value !== undefined && input.value !== witnessValue) + throw new Error('Input didn\'t match witnessValue'); + typeforce(types.Satoshi, witnessValue); + input.value = witnessValue; + } + if (!canSign(input)) { + const prepared = prepareInput(input, ourPubKey, redeemScript, witnessScript); + // updates inline + Object.assign(input, prepared); + } + if (!canSign(input)) + throw Error(input.prevOutType + ' not supported'); + } + // ready to sign + let signatureHash; + if (input.hasWitness) { + signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType); + } + else { + signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType); + } + // enforce in order signing of public keys + const signed = input.pubkeys.some((pubKey, i) => { + if (!ourPubKey.equals(pubKey)) + return false; + if (input.signatures[i]) + throw new Error('Signature already exists'); + // TODO: add tests + if (ourPubKey.length !== 33 && input.hasWitness) { + throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH'); + } + const signature = keyPair.sign(signatureHash); + input.signatures[i] = bscript.signature.encode(signature, hashType); + return true; + }); + if (!signed) + throw new Error('Key pair cannot sign for this input'); + } + __canModifyInputs() { + return this.__inputs.every(input => { + if (!input.signatures) + return true; + return input.signatures.every(signature => { + if (!signature) + return true; + const hashType = signatureHashType(signature); + // if SIGHASH_ANYONECANPAY is set, signatures would not + // be invalidated by more inputs + return (hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) !== 0; + }); + }); + } + __needsOutputs(signingHashType) { + if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) { + return this.__tx.outs.length === 0; + } + // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs + // .build() will fail, but .buildIncomplete() is OK + return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { + if (!input.signatures) + return false; + return input.signatures.some((signature) => { + if (!signature) + return false; // no signature, no issue + const hashType = signatureHashType(signature); + if (hashType & transaction_1.Transaction.SIGHASH_NONE) + return false; // SIGHASH_NONE doesn't care about outputs + return true; // SIGHASH_* does care + }); + }); + } + __canModifyOutputs() { + const nInputs = this.__tx.ins.length; + const nOutputs = this.__tx.outs.length; + return this.__inputs.every(input => { + if (input.signatures === undefined) + return true; + return input.signatures.every((signature => { + if (!signature) + return true; + const hashType = signatureHashType(signature); + const hashTypeMod = hashType & 0x1f; + if (hashTypeMod === transaction_1.Transaction.SIGHASH_NONE) + return true; + if (hashTypeMod === transaction_1.Transaction.SIGHASH_SINGLE) { + // if SIGHASH_SINGLE is set, and nInputs > nOutputs + // some signatures would be invalidated by the addition + // of more outputs + return nInputs <= nOutputs; + } + })); + }); + } + __overMaximumFees(bytes) { + // not all inputs will have .value defined + const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0); + // but all outputs do, and if we have any input value + // we can immediately determine if the outputs are too small + const outgoing = this.__tx.outs.reduce((a, x) => a + x.value, 0); + const fee = incoming - outgoing; + const feeRate = fee / bytes; + return feeRate > this.maximumFeeRate; + } +} +exports.TransactionBuilder = TransactionBuilder; +function expandInput(scriptSig, witnessStack, type, scriptPubKey) { + if (scriptSig.length === 0 && witnessStack.length === 0) + return {}; + if (!type) { + let ssType = classify.input(scriptSig, true); + let wsType = classify.witness(witnessStack, true); + if (ssType === SCRIPT_TYPES.NONSTANDARD) + ssType = undefined; + if (wsType === SCRIPT_TYPES.NONSTANDARD) + wsType = undefined; + type = ssType || wsType; + } + switch (type) { + case SCRIPT_TYPES.P2WPKH: { + const { output, pubkey, signature } = payments.p2wpkh({ witness: witnessStack }); + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2WPKH, + pubkeys: [pubkey], + signatures: [signature] + }; + } + case SCRIPT_TYPES.P2PKH: { + const { output, pubkey, signature } = payments.p2pkh({ input: scriptSig }); + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2PKH, + pubkeys: [pubkey], + signatures: [signature] + }; + } + case SCRIPT_TYPES.P2PK: { + const { signature } = payments.p2pk({ input: scriptSig }); + return { + prevOutType: SCRIPT_TYPES.P2PK, + pubkeys: [undefined], + signatures: [signature] + }; + } + case SCRIPT_TYPES.P2MS: { + const { m, pubkeys, signatures } = payments.p2ms({ + input: scriptSig, + output: scriptPubKey + }, { allowIncomplete: true }); + return { + prevOutType: SCRIPT_TYPES.P2MS, + pubkeys: pubkeys, + signatures: signatures, + maxSignatures: m + }; + } + } + if (type === SCRIPT_TYPES.P2SH) { + const { output, redeem } = payments.p2sh({ + input: scriptSig, + witness: witnessStack + }); + const outputType = classify.output(redeem.output); + const expanded = expandInput(redeem.input, redeem.witness, outputType, redeem.output); + if (!expanded.prevOutType) + return {}; + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2SH, + redeemScript: redeem.output, + redeemScriptType: expanded.prevOutType, + witnessScript: expanded.witnessScript, + witnessScriptType: expanded.witnessScriptType, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures + }; + } + if (type === SCRIPT_TYPES.P2WSH) { + const { output, redeem } = payments.p2wsh({ + input: scriptSig, + witness: witnessStack + }); + const outputType = classify.output(redeem.output); + let expanded; + if (outputType === SCRIPT_TYPES.P2WPKH) { + expanded = expandInput(redeem.input, redeem.witness, outputType); + } + else { + expanded = expandInput(bscript.compile(redeem.witness), [], outputType, redeem.output); + } + if (!expanded.prevOutType) + return {}; + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2WSH, + witnessScript: redeem.output, + witnessScriptType: expanded.prevOutType, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures + }; + } + return { + prevOutType: SCRIPT_TYPES.NONSTANDARD, + prevOutScript: scriptSig + }; +} +// could be done in expandInput, but requires the original Transaction for hashForSignature +function fixMultisigOrder(input, transaction, vin) { + if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) + return; + if (input.pubkeys.length === input.signatures.length) + return; + const unmatched = input.signatures.concat(); + input.signatures = input.pubkeys.map(pubKey => { + const keyPair = ECPair.fromPublicKey(pubKey); + let match; + // check for a signature + unmatched.some((signature, i) => { + // skip if undefined || OP_0 + if (!signature) + return false; + // TODO: avoid O(n) hashForSignature + const parsed = bscript.signature.decode(signature); + const hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType); + // skip if signature does not match pubKey + if (!keyPair.verify(hash, parsed.signature)) + return false; + // remove matched signature from unmatched + unmatched[i] = undefined; + match = signature; + return true; + }); + return match; + }); +} +function expandOutput(script, ourPubKey) { + typeforce(types.Buffer, script); + const type = classify.output(script); + switch (type) { + case SCRIPT_TYPES.P2PKH: { + if (!ourPubKey) + return { type }; + // does our hash160(pubKey) match the output scripts? + const pkh1 = payments.p2pkh({ output: script }).hash; + const pkh2 = bcrypto.hash160(ourPubKey); + if (!pkh1.equals(pkh2)) + return { type }; + return { + type, + pubkeys: [ourPubKey], + signatures: [undefined] + }; + } + case SCRIPT_TYPES.P2WPKH: { + if (!ourPubKey) + return { type }; + // does our hash160(pubKey) match the output scripts? + const wpkh1 = payments.p2wpkh({ output: script }).hash; + const wpkh2 = bcrypto.hash160(ourPubKey); + if (!wpkh1.equals(wpkh2)) + return { type }; + return { + type, + pubkeys: [ourPubKey], + signatures: [undefined] + }; + } + case SCRIPT_TYPES.P2PK: { + const p2pk = payments.p2pk({ output: script }); + return { + type, + pubkeys: [p2pk.pubkey], + signatures: [undefined] + }; + } + case SCRIPT_TYPES.P2MS: { + const p2ms = payments.p2ms({ output: script }); + return { + type, + pubkeys: p2ms.pubkeys, + signatures: p2ms.pubkeys.map(() => undefined), + maxSignatures: p2ms.m + }; + } + } + return { type }; +} +function prepareInput(input, ourPubKey, redeemScript, witnessScript) { + if (redeemScript && witnessScript) { + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); + const p2wshAlt = payments.p2wsh({ output: redeemScript }); + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + const p2shAlt = payments.p2sh({ redeem: p2wsh }); + // enforces P2SH(P2WSH(...)) + if (!p2wsh.hash.equals(p2wshAlt.hash)) + throw new Error('Witness script inconsistent with prevOutScript'); + if (!p2sh.hash.equals(p2shAlt.hash)) + throw new Error('Redeem script inconsistent with prevOutScript'); + const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')'); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); + return { + redeemScript, + redeemScriptType: SCRIPT_TYPES.P2WSH, + witnessScript, + witnessScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2SH, + prevOutScript: p2sh.output, + hasWitness: true, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures + }; + } + if (redeemScript) { + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + if (input.prevOutScript) { + let p2shAlt; + try { + p2shAlt = payments.p2sh({ output: input.prevOutScript }); + } + catch (e) { + throw new Error('PrevOutScript must be P2SH'); + } + if (!p2sh.hash.equals(p2shAlt.hash)) + throw new Error('Redeem script inconsistent with prevOutScript'); + } + const expanded = expandOutput(p2sh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')'); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = redeemScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) { + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; + } + return { + redeemScript, + redeemScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2SH, + prevOutScript: p2sh.output, + hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures + }; + } + if (witnessScript) { + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); + if (input.prevOutScript) { + const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }); + if (!p2wsh.hash.equals(p2wshAlt.hash)) + throw new Error('Witness script inconsistent with prevOutScript'); + } + const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')'); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2WSH(P2WPKH) is a consensus failure'); + return { + witnessScript, + witnessScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2WSH, + prevOutScript: p2wsh.output, + hasWitness: true, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures + }; + } + if (input.prevOutType && input.prevOutScript) { + // embedded scripts are not possible without extra information + if (input.prevOutType === SCRIPT_TYPES.P2SH) + throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript'); + if (input.prevOutType === SCRIPT_TYPES.P2WSH) + throw new Error('PrevOutScript is ' + input.prevOutType + ', requires witnessScript'); + if (!input.prevOutScript) + throw new Error('PrevOutScript is missing'); + const expanded = expandOutput(input.prevOutScript, ourPubKey); + if (!expanded.pubkeys) + throw new Error(expanded.type + ' not supported (' + bscript.toASM(input.prevOutScript) + ')'); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = input.prevOutScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) { + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; + } + return { + prevOutType: expanded.type, + prevOutScript: input.prevOutScript, + hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures + }; + } + const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; + return { + prevOutType: SCRIPT_TYPES.P2PKH, + prevOutScript: prevOutScript, + hasWitness: false, + signScript: prevOutScript, + signType: SCRIPT_TYPES.P2PKH, + pubkeys: [ourPubKey], + signatures: [undefined] + }; +} +function build(type, input, allowIncomplete) { + const pubkeys = (input.pubkeys || []); + let signatures = (input.signatures || []); + switch (type) { + case SCRIPT_TYPES.P2PKH: { + if (pubkeys.length === 0) + break; + if (signatures.length === 0) + break; + return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }); + } + case SCRIPT_TYPES.P2WPKH: { + if (pubkeys.length === 0) + break; + if (signatures.length === 0) + break; + return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }); + } + case SCRIPT_TYPES.P2PK: { + if (pubkeys.length === 0) + break; + if (signatures.length === 0) + break; + return payments.p2pk({ signature: signatures[0] }); + } + case SCRIPT_TYPES.P2MS: { + const m = input.maxSignatures; + if (allowIncomplete) { + signatures = signatures.map(x => x || script_1.OPS.OP_0); + } + else { + signatures = signatures.filter(x => x); + } + // if the transaction is not not complete (complete), or if signatures.length === m, validate + // otherwise, the number of OP_0's may be >= m, so don't validate (boo) + const validate = !allowIncomplete || (m === signatures.length); + return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }); + } + case SCRIPT_TYPES.P2SH: { + const redeem = build(input.redeemScriptType, input, allowIncomplete); + if (!redeem) + return; + return payments.p2sh({ + redeem: { + output: redeem.output || input.redeemScript, + input: redeem.input, + witness: redeem.witness + } + }); + } + case SCRIPT_TYPES.P2WSH: { + const redeem = build(input.witnessScriptType, input, allowIncomplete); + if (!redeem) + return; + return payments.p2wsh({ + redeem: { + output: input.witnessScript, + input: redeem.input, + witness: redeem.witness + } + }); + } + } +} +function canSign(input) { + return input.signScript !== undefined && + input.signType !== undefined && + input.pubkeys !== undefined && + input.signatures !== undefined && + input.signatures.length === input.pubkeys.length && + input.pubkeys.length > 0 && + (input.hasWitness === false || + input.value !== undefined); +} +function signatureHashType(buffer) { + return buffer.readUInt8(buffer.length - 1); +} diff --git a/src/types.js b/src/types.js new file mode 100644 index 0000000..13d1bc8 --- /dev/null +++ b/src/types.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const typeforce = require('typeforce'); +const UINT31_MAX = Math.pow(2, 31) - 1; +function UInt31(value) { + return typeforce.UInt32(value) && value <= UINT31_MAX; +} +exports.UInt31 = UInt31; +function BIP32Path(value) { + return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); +} +exports.BIP32Path = BIP32Path; +BIP32Path.toJSON = function () { return 'BIP32 derivation path'; }; +const SATOSHI_MAX = 21 * 1e14; +function Satoshi(value) { + return typeforce.UInt53(value) && value <= SATOSHI_MAX; +} +exports.Satoshi = Satoshi; +// external dependent types +exports.ECPoint = typeforce.quacksLike('Point'); +// exposed, external API +exports.Network = typeforce.compile({ + messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), + bip32: { + public: typeforce.UInt32, + private: typeforce.UInt32 + }, + pubKeyHash: typeforce.UInt8, + scriptHash: typeforce.UInt8, + wif: typeforce.UInt8 +}); +exports.Buffer256bit = typeforce.BufferN(32); +exports.Hash160bit = typeforce.BufferN(20); +exports.Hash256bit = typeforce.BufferN(32); +exports.Number = typeforce.Number; +exports.Array = typeforce.Array; +exports.Boolean = typeforce.Boolean; +exports.String = typeforce.String; +exports.Buffer = typeforce.Buffer; +exports.Hex = typeforce.Hex; +exports.maybe = typeforce.maybe; +exports.tuple = typeforce.tuple; +exports.UInt8 = typeforce.UInt8; +exports.UInt32 = typeforce.UInt32; +exports.Function = typeforce.Function; +exports.BufferN = typeforce.BufferN; +exports.Null = typeforce.Null; +exports.oneOf = typeforce.oneOf; diff --git a/test/address.js b/test/address.js index 19093b6..a0f4df0 100644 --- a/test/address.js +++ b/test/address.js @@ -1,7 +1,7 @@ const { describe, it } = require('mocha') const assert = require('assert') -const baddress = require('../dist/src/address') -const bscript = require('../dist/src/script') +const baddress = require('../src/address') +const bscript = require('../src/script') const fixtures = require('./fixtures/address.json') const NETWORKS = Object.assign({ litecoin: { @@ -14,7 +14,7 @@ const NETWORKS = Object.assign({ scriptHash: 0x32, wif: 0xb0 } -}, require('../dist/src/networks')) +}, require('../src/networks')) describe('address', function () { describe('fromBase58Check', function () { diff --git a/test/bufferutils.js b/test/bufferutils.js index ceb649a..5f2c39e 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bufferutils = require('../dist/src/bufferutils') +const bufferutils = require('../src/bufferutils') const fixtures = require('./fixtures/bufferutils.json') diff --git a/test/classify.js b/test/classify.js index 33225b5..3efcc74 100644 --- a/test/classify.js +++ b/test/classify.js @@ -1,18 +1,18 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscript = require('../dist/src/script') -const classify = require('../dist/src/classify') +const bscript = require('../src/script') +const classify = require('../src/classify') const fixtures = require('./fixtures/templates.json') -const multisig = require('../dist/src/templates/multisig') -const nullData = require('../dist/src/templates/nulldata') -const pubKey = require('../dist/src/templates/pubkey') -const pubKeyHash = require('../dist/src/templates/pubkeyhash') -const scriptHash = require('../dist/src/templates/scripthash') -const witnessPubKeyHash = require('../dist/src/templates/witnesspubkeyhash') -const witnessScriptHash = require('../dist/src/templates/witnessscripthash') -const witnessCommitment = require('../dist/src/templates/witnesscommitment') +const multisig = require('../src/templates/multisig') +const nullData = require('../src/templates/nulldata') +const pubKey = require('../src/templates/pubkey') +const pubKeyHash = require('../src/templates/pubkeyhash') +const scriptHash = require('../src/templates/scripthash') +const witnessPubKeyHash = require('../src/templates/witnesspubkeyhash') +const witnessScriptHash = require('../src/templates/witnessscripthash') +const witnessCommitment = require('../src/templates/witnesscommitment') const tmap = { pubKey, diff --git a/test/crypto.js b/test/crypto.js index 0a01c98..3f7802a 100644 --- a/test/crypto.js +++ b/test/crypto.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bcrypto = require('../dist/src/crypto') +const bcrypto = require('../src/crypto') const fixtures = require('./fixtures/crypto') diff --git a/test/ecpair.js b/test/ecpair.js index f590e18..4299470 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -5,12 +5,12 @@ const assert = require('assert') const proxyquire = require('proxyquire') const hoodwink = require('hoodwink') -const ECPair = require('../dist/src/ecpair') +const ECPair = require('../src/ecpair') const tinysecp = require('tiny-secp256k1') const fixtures = require('./fixtures/ecpair.json') -const NETWORKS = require('../dist/src/networks') +const NETWORKS = require('../src/networks') const NETWORKS_LIST = [] // Object.values(NETWORKS) for (let networkName in NETWORKS) { NETWORKS_LIST.push(NETWORKS[networkName]) @@ -144,7 +144,7 @@ describe('ECPair', function () { describe('uses randombytes RNG', function () { it('generates a ECPair', function () { const stub = { randombytes: function () { return d } } - const ProxiedECPair = proxyquire('../dist/src/ecpair', stub) + const ProxiedECPair = proxyquire('../src/ecpair', stub) const keyPair = ProxiedECPair.makeRandom() assert.strictEqual(keyPair.toWIF(), exWIF) diff --git a/test/payments.js b/test/payments.js index 6617047..a4f07bb 100644 --- a/test/payments.js +++ b/test/payments.js @@ -5,7 +5,7 @@ const u = require('./payments.utils') ;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) { describe(p, function () { let fn - let payment = require('../dist/src/payments/' + p) + let payment = require('../src/payments/' + p) if (p === 'embed') { fn = payment.p2data } else { diff --git a/test/payments.utils.js b/test/payments.utils.js index 086561d..485bf03 100644 --- a/test/payments.utils.js +++ b/test/payments.utils.js @@ -1,6 +1,6 @@ const t = require('assert') -const bscript = require('../dist/src/script') -const BNETWORKS = require('../dist/src/networks') +const bscript = require('../src/script') +const BNETWORKS = require('../src/networks') function tryHex (x) { if (Buffer.isBuffer(x)) return x.toString('hex') diff --git a/test/script.js b/test/script.js index 013d50a..c2a60ad 100644 --- a/test/script.js +++ b/test/script.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscript = require('../dist/src/script') +const bscript = require('../src/script') const minimalData = require('minimaldata') const fixtures = require('./fixtures/script.json') diff --git a/test/script_number.js b/test/script_number.js index 1d38e48..bc8f395 100644 --- a/test/script_number.js +++ b/test/script_number.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const scriptNumber = require('../dist/src/script_number') +const scriptNumber = require('../src/script_number') const fixtures = require('./fixtures/script_number.json') describe('script-number', function () { diff --git a/test/script_signature.js b/test/script_signature.js index e56ff68..cee69bd 100644 --- a/test/script_signature.js +++ b/test/script_signature.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const bscriptSig = require('../dist/src/script').signature +const bscriptSig = require('../src/script').signature const Buffer = require('safe-buffer').Buffer const fixtures = require('./fixtures/signature.json') diff --git a/test/transaction.js b/test/transaction.js index 74afc8f..d923ce2 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -1,6 +1,6 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const bscript = require('../dist/src/script') +const bscript = require('../src/script') const fixtures = require('./fixtures/transaction') const Transaction = require('..').Transaction diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 34d9270..574b669 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -1,13 +1,13 @@ const { describe, it, beforeEach } = require('mocha') const assert = require('assert') -const baddress = require('../dist/src/address') -const bscript = require('../dist/src/script') -const payments = require('../dist/src/payments') +const baddress = require('../src/address') +const bscript = require('../src/script') +const payments = require('../src/payments') -const ECPair = require('../dist/src/ecpair') +const ECPair = require('../src/ecpair') const Transaction = require('..').Transaction const TransactionBuilder = require('..').TransactionBuilder -const NETWORKS = require('../dist/src/networks') +const NETWORKS = require('../src/networks') const fixtures = require('./fixtures/transaction_builder') diff --git a/test/types.js b/test/types.js index 831d415..d245d53 100644 --- a/test/types.js +++ b/test/types.js @@ -1,6 +1,6 @@ const { describe, it } = require('mocha') const assert = require('assert') -const types = require('../dist/src/types') +const types = require('../src/types') const typeforce = require('typeforce') describe('types', function () { diff --git a/src/address.ts b/ts_src/address.ts similarity index 100% rename from src/address.ts rename to ts_src/address.ts diff --git a/src/block.ts b/ts_src/block.ts similarity index 100% rename from src/block.ts rename to ts_src/block.ts diff --git a/src/bufferutils.ts b/ts_src/bufferutils.ts similarity index 100% rename from src/bufferutils.ts rename to ts_src/bufferutils.ts diff --git a/src/classify.ts b/ts_src/classify.ts similarity index 100% rename from src/classify.ts rename to ts_src/classify.ts diff --git a/src/crypto.ts b/ts_src/crypto.ts similarity index 100% rename from src/crypto.ts rename to ts_src/crypto.ts diff --git a/src/ecpair.ts b/ts_src/ecpair.ts similarity index 100% rename from src/ecpair.ts rename to ts_src/ecpair.ts diff --git a/src/index.ts b/ts_src/index.ts similarity index 100% rename from src/index.ts rename to ts_src/index.ts diff --git a/src/networks.ts b/ts_src/networks.ts similarity index 100% rename from src/networks.ts rename to ts_src/networks.ts diff --git a/src/payments/embed.ts b/ts_src/payments/embed.ts similarity index 100% rename from src/payments/embed.ts rename to ts_src/payments/embed.ts diff --git a/src/payments/index.ts b/ts_src/payments/index.ts similarity index 100% rename from src/payments/index.ts rename to ts_src/payments/index.ts diff --git a/src/payments/lazy.ts b/ts_src/payments/lazy.ts similarity index 100% rename from src/payments/lazy.ts rename to ts_src/payments/lazy.ts diff --git a/src/payments/p2ms.ts b/ts_src/payments/p2ms.ts similarity index 100% rename from src/payments/p2ms.ts rename to ts_src/payments/p2ms.ts diff --git a/src/payments/p2pk.ts b/ts_src/payments/p2pk.ts similarity index 100% rename from src/payments/p2pk.ts rename to ts_src/payments/p2pk.ts diff --git a/src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts similarity index 100% rename from src/payments/p2pkh.ts rename to ts_src/payments/p2pkh.ts diff --git a/src/payments/p2sh.ts b/ts_src/payments/p2sh.ts similarity index 100% rename from src/payments/p2sh.ts rename to ts_src/payments/p2sh.ts diff --git a/src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts similarity index 100% rename from src/payments/p2wpkh.ts rename to ts_src/payments/p2wpkh.ts diff --git a/src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts similarity index 100% rename from src/payments/p2wsh.ts rename to ts_src/payments/p2wsh.ts diff --git a/src/script.ts b/ts_src/script.ts similarity index 100% rename from src/script.ts rename to ts_src/script.ts diff --git a/src/script_number.ts b/ts_src/script_number.ts similarity index 100% rename from src/script_number.ts rename to ts_src/script_number.ts diff --git a/src/script_signature.ts b/ts_src/script_signature.ts similarity index 100% rename from src/script_signature.ts rename to ts_src/script_signature.ts diff --git a/src/templates/multisig/index.ts b/ts_src/templates/multisig/index.ts similarity index 100% rename from src/templates/multisig/index.ts rename to ts_src/templates/multisig/index.ts diff --git a/src/templates/multisig/input.ts b/ts_src/templates/multisig/input.ts similarity index 100% rename from src/templates/multisig/input.ts rename to ts_src/templates/multisig/input.ts diff --git a/src/templates/multisig/output.ts b/ts_src/templates/multisig/output.ts similarity index 100% rename from src/templates/multisig/output.ts rename to ts_src/templates/multisig/output.ts diff --git a/src/templates/nulldata.ts b/ts_src/templates/nulldata.ts similarity index 100% rename from src/templates/nulldata.ts rename to ts_src/templates/nulldata.ts diff --git a/src/templates/pubkey/index.ts b/ts_src/templates/pubkey/index.ts similarity index 100% rename from src/templates/pubkey/index.ts rename to ts_src/templates/pubkey/index.ts diff --git a/src/templates/pubkey/input.ts b/ts_src/templates/pubkey/input.ts similarity index 100% rename from src/templates/pubkey/input.ts rename to ts_src/templates/pubkey/input.ts diff --git a/src/templates/pubkey/output.ts b/ts_src/templates/pubkey/output.ts similarity index 100% rename from src/templates/pubkey/output.ts rename to ts_src/templates/pubkey/output.ts diff --git a/src/templates/pubkeyhash/index.ts b/ts_src/templates/pubkeyhash/index.ts similarity index 100% rename from src/templates/pubkeyhash/index.ts rename to ts_src/templates/pubkeyhash/index.ts diff --git a/src/templates/pubkeyhash/input.ts b/ts_src/templates/pubkeyhash/input.ts similarity index 100% rename from src/templates/pubkeyhash/input.ts rename to ts_src/templates/pubkeyhash/input.ts diff --git a/src/templates/pubkeyhash/output.ts b/ts_src/templates/pubkeyhash/output.ts similarity index 100% rename from src/templates/pubkeyhash/output.ts rename to ts_src/templates/pubkeyhash/output.ts diff --git a/src/templates/scripthash/index.ts b/ts_src/templates/scripthash/index.ts similarity index 100% rename from src/templates/scripthash/index.ts rename to ts_src/templates/scripthash/index.ts diff --git a/src/templates/scripthash/input.ts b/ts_src/templates/scripthash/input.ts similarity index 100% rename from src/templates/scripthash/input.ts rename to ts_src/templates/scripthash/input.ts diff --git a/src/templates/scripthash/output.ts b/ts_src/templates/scripthash/output.ts similarity index 100% rename from src/templates/scripthash/output.ts rename to ts_src/templates/scripthash/output.ts diff --git a/src/templates/witnesscommitment/index.ts b/ts_src/templates/witnesscommitment/index.ts similarity index 100% rename from src/templates/witnesscommitment/index.ts rename to ts_src/templates/witnesscommitment/index.ts diff --git a/src/templates/witnesscommitment/output.ts b/ts_src/templates/witnesscommitment/output.ts similarity index 100% rename from src/templates/witnesscommitment/output.ts rename to ts_src/templates/witnesscommitment/output.ts diff --git a/src/templates/witnesspubkeyhash/index.ts b/ts_src/templates/witnesspubkeyhash/index.ts similarity index 100% rename from src/templates/witnesspubkeyhash/index.ts rename to ts_src/templates/witnesspubkeyhash/index.ts diff --git a/src/templates/witnesspubkeyhash/input.ts b/ts_src/templates/witnesspubkeyhash/input.ts similarity index 100% rename from src/templates/witnesspubkeyhash/input.ts rename to ts_src/templates/witnesspubkeyhash/input.ts diff --git a/src/templates/witnesspubkeyhash/output.ts b/ts_src/templates/witnesspubkeyhash/output.ts similarity index 100% rename from src/templates/witnesspubkeyhash/output.ts rename to ts_src/templates/witnesspubkeyhash/output.ts diff --git a/src/templates/witnessscripthash/index.ts b/ts_src/templates/witnessscripthash/index.ts similarity index 100% rename from src/templates/witnessscripthash/index.ts rename to ts_src/templates/witnessscripthash/index.ts diff --git a/src/templates/witnessscripthash/input.ts b/ts_src/templates/witnessscripthash/input.ts similarity index 100% rename from src/templates/witnessscripthash/input.ts rename to ts_src/templates/witnessscripthash/input.ts diff --git a/src/templates/witnessscripthash/output.ts b/ts_src/templates/witnessscripthash/output.ts similarity index 100% rename from src/templates/witnessscripthash/output.ts rename to ts_src/templates/witnessscripthash/output.ts diff --git a/src/transaction.ts b/ts_src/transaction.ts similarity index 100% rename from src/transaction.ts rename to ts_src/transaction.ts diff --git a/src/transaction_builder.ts b/ts_src/transaction_builder.ts similarity index 100% rename from src/transaction_builder.ts rename to ts_src/transaction_builder.ts diff --git a/src/types.ts b/ts_src/types.ts similarity index 100% rename from src/types.ts rename to ts_src/types.ts diff --git a/tsconfig.json b/tsconfig.json index 1d68be9..787769d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,8 +2,9 @@ "compilerOptions": { "target": "ES2015", "module": "commonjs", - "outDir": "./dist", - "rootDir": "./", + "outDir": "./src", + "declarationDir": "./types", + "rootDir": "./ts_src", "types": [ "node" ], @@ -19,7 +20,7 @@ "esModuleInterop": false }, "include": [ - "src/**/*" + "ts_src/**/*.ts" ], "exclude": [ "**/*.spec.ts", diff --git a/types/address.d.ts b/types/address.d.ts new file mode 100644 index 0000000..68fbedd --- /dev/null +++ b/types/address.d.ts @@ -0,0 +1,17 @@ +/// +import { Network } from './networks'; +export declare type Base58CheckResult = { + hash: Buffer; + version: number; +}; +export declare type Bech32Result = { + version: number; + prefix: string; + data: Buffer; +}; +export declare function fromBase58Check(address: string): Base58CheckResult; +export declare function fromBech32(address: string): Bech32Result; +export declare function toBase58Check(hash: Buffer, version: number): string; +export declare function toBech32(data: Buffer, version: number, prefix: string): string; +export declare function fromOutputScript(output: Buffer, network: Network): string; +export declare function toOutputScript(address: string, network: Network): Buffer; diff --git a/types/block.d.ts b/types/block.d.ts new file mode 100644 index 0000000..ff98de2 --- /dev/null +++ b/types/block.d.ts @@ -0,0 +1,27 @@ +/// +import { Transaction } from './transaction'; +export declare class Block { + version: number; + prevHash?: Buffer; + merkleRoot?: Buffer; + timestamp: number; + witnessCommit?: Buffer; + bits: number; + nonce: number; + transactions?: Array; + constructor(); + static fromBuffer(buffer: Buffer): Block; + static fromHex(hex: string): Block; + static calculateTarget(bits: number): Buffer; + static calculateMerkleRoot(transactions: Array, forWitness?: boolean): Buffer; + hasWitnessCommit(): boolean; + byteLength(headersOnly: boolean): number; + getHash(): Buffer; + getId(): string; + getUTCDate(): Date; + toBuffer(headersOnly: boolean): Buffer; + toHex(headersOnly: boolean): string; + checkMerkleRoot(): boolean; + checkWitnessCommit(): boolean; + checkProofOfWork(): boolean; +} diff --git a/types/bufferutils.d.ts b/types/bufferutils.d.ts new file mode 100644 index 0000000..2686e4e --- /dev/null +++ b/types/bufferutils.d.ts @@ -0,0 +1,4 @@ +/// +export declare function readUInt64LE(buffer: Buffer, offset: number): number; +export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number; +export declare function reverseBuffer(buffer: Buffer): Buffer; diff --git a/types/classify.d.ts b/types/classify.d.ts new file mode 100644 index 0000000..b394c71 --- /dev/null +++ b/types/classify.d.ts @@ -0,0 +1,16 @@ +/// +declare const types: { + P2MS: string; + NONSTANDARD: string; + NULLDATA: string; + P2PK: string; + P2PKH: string; + P2SH: string; + P2WPKH: string; + P2WSH: string; + WITNESS_COMMITMENT: string; +}; +declare function classifyOutput(script: Buffer): string; +declare function classifyInput(script: Buffer, allowIncomplete: boolean): string; +declare function classifyWitness(script: Array, allowIncomplete: boolean): string; +export { classifyInput as input, classifyOutput as output, classifyWitness as witness, types, }; diff --git a/types/crypto.d.ts b/types/crypto.d.ts new file mode 100644 index 0000000..1743681 --- /dev/null +++ b/types/crypto.d.ts @@ -0,0 +1,6 @@ +/// +export declare function ripemd160(buffer: Buffer): Buffer; +export declare function sha1(buffer: Buffer): Buffer; +export declare function sha256(buffer: Buffer): Buffer; +export declare function hash160(buffer: Buffer): Buffer; +export declare function hash256(buffer: Buffer): Buffer; diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts new file mode 100644 index 0000000..58ea4be --- /dev/null +++ b/types/ecpair.d.ts @@ -0,0 +1,34 @@ +/// +import { Network } from './networks'; +interface ECPairOptions { + compressed?: boolean; + network?: Network; + rng?(arg0: Buffer): Buffer; +} +export interface ECPairInterface { + compressed: boolean; + network: Network; + privateKey?: Buffer; + publicKey?: Buffer; + toWIF(): string; + sign(hash: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): Buffer; + getPublicKey?(): Buffer; +} +declare class ECPair implements ECPairInterface { + compressed: boolean; + network: Network; + private __d?; + private __Q?; + constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions); + readonly privateKey: Buffer | undefined; + readonly publicKey: Buffer | undefined; + toWIF(): string; + sign(hash: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): Buffer; +} +declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair; +declare function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair; +declare function fromWIF(string: string, network?: Network | Array): ECPair; +declare function makeRandom(options?: ECPairOptions): ECPair; +export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF }; diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..9682271 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,17 @@ +import * as bip32 from 'bip32'; +import * as ECPair from './ecpair'; +import * as address from './address'; +import * as crypto from './crypto'; +import * as networks from './networks'; +import * as payments from './payments'; +import * as script from './script'; +export { ECPair, address, bip32, crypto, networks, payments, script, }; +export { Block } from './block'; +export { Transaction } from './transaction'; +export { TransactionBuilder } from './transaction_builder'; +export { OPS as opcodes } from './script'; +export { Payment, PaymentOpts } from './payments'; +export { Input as TxInput, Output as TxOutput } from './transaction'; +export { Network } from './networks'; +export { OpCode } from './script'; +export { BIP32Interface } from 'bip32'; diff --git a/types/networks.d.ts b/types/networks.d.ts new file mode 100644 index 0000000..e402873 --- /dev/null +++ b/types/networks.d.ts @@ -0,0 +1,16 @@ +export declare type Network = { + messagePrefix: string; + bech32: string; + bip32: bip32; + pubKeyHash: number; + scriptHash: number; + wif: number; +}; +declare type bip32 = { + public: number; + private: number; +}; +export declare const bitcoin: Network; +export declare const regtest: Network; +export declare const testnet: Network; +export {}; diff --git a/types/payments/embed.d.ts b/types/payments/embed.d.ts new file mode 100644 index 0000000..76a9ed2 --- /dev/null +++ b/types/payments/embed.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2data(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/index.d.ts b/types/payments/index.d.ts new file mode 100644 index 0000000..5afc847 --- /dev/null +++ b/types/payments/index.d.ts @@ -0,0 +1,30 @@ +/// +import { Network } from '../networks'; +import { p2data as embed } from './embed'; +import { p2ms } from './p2ms'; +import { p2pk } from './p2pk'; +import { p2pkh } from './p2pkh'; +import { p2sh } from './p2sh'; +import { p2wpkh } from './p2wpkh'; +import { p2wsh } from './p2wsh'; +export interface Payment { + network?: Network; + output?: Buffer; + data?: Array; + m?: number; + n?: number; + pubkeys?: Array; + input?: Buffer; + signatures?: Array; + pubkey?: Buffer; + signature?: Buffer; + address?: string; + hash?: Buffer; + redeem?: Payment; + witness?: Array; +} +export interface PaymentOpts { + validate?: boolean; + allowIncomplete?: boolean; +} +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; diff --git a/types/payments/lazy.d.ts b/types/payments/lazy.d.ts new file mode 100644 index 0000000..705f530 --- /dev/null +++ b/types/payments/lazy.d.ts @@ -0,0 +1,2 @@ +export declare function prop(object: Object, name: string, f: () => any): void; +export declare function value(f: () => T): () => T; diff --git a/types/payments/p2ms.d.ts b/types/payments/p2ms.d.ts new file mode 100644 index 0000000..199e029 --- /dev/null +++ b/types/payments/p2ms.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2ms(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/p2pk.d.ts b/types/payments/p2pk.d.ts new file mode 100644 index 0000000..d7e824d --- /dev/null +++ b/types/payments/p2pk.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2pk(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/p2pkh.d.ts b/types/payments/p2pkh.d.ts new file mode 100644 index 0000000..a33eeb0 --- /dev/null +++ b/types/payments/p2pkh.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2pkh(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/p2sh.d.ts b/types/payments/p2sh.d.ts new file mode 100644 index 0000000..bb76772 --- /dev/null +++ b/types/payments/p2sh.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2sh(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/p2wpkh.d.ts b/types/payments/p2wpkh.d.ts new file mode 100644 index 0000000..3609391 --- /dev/null +++ b/types/payments/p2wpkh.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2wpkh(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/payments/p2wsh.d.ts b/types/payments/p2wsh.d.ts new file mode 100644 index 0000000..d9ae925 --- /dev/null +++ b/types/payments/p2wsh.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2wsh(a: Payment, opts?: PaymentOpts): Payment; diff --git a/types/script.d.ts b/types/script.d.ts new file mode 100644 index 0000000..702e76b --- /dev/null +++ b/types/script.d.ts @@ -0,0 +1,18 @@ +/// +import * as scriptNumber from './script_number'; +import * as scriptSignature from './script_signature'; +export declare type OpCode = number; +export declare const OPS: { + [index: string]: number; +}; +export declare function isPushOnly(value: Array): boolean; +export declare function compile(chunks: Buffer | Array): Buffer; +export declare function decompile(buffer: Buffer | Array): Array | null; +export declare function toASM(chunks: Buffer | Array): string; +export declare function fromASM(asm: string): Buffer; +export declare function toStack(chunks: Buffer | Array): Array; +export declare function isCanonicalPubKey(buffer: Buffer): boolean; +export declare function isDefinedHashType(hashType: number): boolean; +export declare function isCanonicalScriptSignature(buffer: Buffer): boolean; +export declare const number: typeof scriptNumber; +export declare const signature: typeof scriptSignature; diff --git a/types/script_number.d.ts b/types/script_number.d.ts new file mode 100644 index 0000000..d0b87b1 --- /dev/null +++ b/types/script_number.d.ts @@ -0,0 +1,3 @@ +/// +export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number; +export declare function encode(number: number): Buffer; diff --git a/types/script_signature.d.ts b/types/script_signature.d.ts new file mode 100644 index 0000000..2057dd9 --- /dev/null +++ b/types/script_signature.d.ts @@ -0,0 +1,8 @@ +/// +interface ScriptSignature { + signature: Buffer; + hashType: number; +} +export declare function decode(buffer: Buffer): ScriptSignature; +export declare function encode(signature: Buffer, hashType: number): Buffer; +export {}; diff --git a/types/templates/multisig/index.d.ts b/types/templates/multisig/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/multisig/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/multisig/input.d.ts b/types/templates/multisig/input.d.ts new file mode 100644 index 0000000..a04d03c --- /dev/null +++ b/types/templates/multisig/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/multisig/output.d.ts b/types/templates/multisig/output.d.ts new file mode 100644 index 0000000..a04d03c --- /dev/null +++ b/types/templates/multisig/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/nulldata.d.ts b/types/templates/nulldata.d.ts new file mode 100644 index 0000000..aff3cd0 --- /dev/null +++ b/types/templates/nulldata.d.ts @@ -0,0 +1,9 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} +declare const output: { + check: typeof check; +}; +export { output }; diff --git a/types/templates/pubkey/index.d.ts b/types/templates/pubkey/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/pubkey/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/pubkey/input.d.ts b/types/templates/pubkey/input.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/pubkey/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/pubkey/output.d.ts b/types/templates/pubkey/output.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/pubkey/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/pubkeyhash/index.d.ts b/types/templates/pubkeyhash/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/pubkeyhash/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/pubkeyhash/input.d.ts b/types/templates/pubkeyhash/input.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/pubkeyhash/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/pubkeyhash/output.d.ts b/types/templates/pubkeyhash/output.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/pubkeyhash/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/scripthash/index.d.ts b/types/templates/scripthash/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/scripthash/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/scripthash/input.d.ts b/types/templates/scripthash/input.d.ts new file mode 100644 index 0000000..a04d03c --- /dev/null +++ b/types/templates/scripthash/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/scripthash/output.d.ts b/types/templates/scripthash/output.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/scripthash/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/witnesscommitment/index.d.ts b/types/templates/witnesscommitment/index.d.ts new file mode 100644 index 0000000..a072ea9 --- /dev/null +++ b/types/templates/witnesscommitment/index.d.ts @@ -0,0 +1,2 @@ +import * as output from './output'; +export { output, }; diff --git a/types/templates/witnesscommitment/output.d.ts b/types/templates/witnesscommitment/output.d.ts new file mode 100644 index 0000000..778c9a1 --- /dev/null +++ b/types/templates/witnesscommitment/output.d.ts @@ -0,0 +1,7 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} +export declare function encode(commitment: Buffer): Buffer; +export declare function decode(buffer: Buffer): Buffer; diff --git a/types/templates/witnesspubkeyhash/index.d.ts b/types/templates/witnesspubkeyhash/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/witnesspubkeyhash/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/witnesspubkeyhash/input.d.ts b/types/templates/witnesspubkeyhash/input.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/witnesspubkeyhash/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/witnesspubkeyhash/output.d.ts b/types/templates/witnesspubkeyhash/output.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/witnesspubkeyhash/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/witnessscripthash/index.d.ts b/types/templates/witnessscripthash/index.d.ts new file mode 100644 index 0000000..cff90ee --- /dev/null +++ b/types/templates/witnessscripthash/index.d.ts @@ -0,0 +1,3 @@ +import * as input from './input'; +import * as output from './output'; +export { input, output, }; diff --git a/types/templates/witnessscripthash/input.d.ts b/types/templates/witnessscripthash/input.d.ts new file mode 100644 index 0000000..7786731 --- /dev/null +++ b/types/templates/witnessscripthash/input.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(chunks: Array, allowIncomplete?: boolean): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/templates/witnessscripthash/output.d.ts b/types/templates/witnessscripthash/output.d.ts new file mode 100644 index 0000000..091758f --- /dev/null +++ b/types/templates/witnessscripthash/output.d.ts @@ -0,0 +1,5 @@ +/// +export declare function check(script: Buffer | Array): boolean; +export declare namespace check { + var toJSON: () => string; +} diff --git a/types/transaction.d.ts b/types/transaction.d.ts new file mode 100644 index 0000000..60bbf45 --- /dev/null +++ b/types/transaction.d.ts @@ -0,0 +1,59 @@ +/// +export declare type BlankOutput = { + script: Buffer; + valueBuffer: Buffer; +}; +export declare type Output = { + script: Buffer; + value: number; +}; +export declare type Input = { + hash: Buffer; + index: number; + script: Buffer; + sequence: number; + witness: Array; +}; +export declare class Transaction { + version: number; + locktime: number; + ins: Array; + outs: Array; + static readonly DEFAULT_SEQUENCE = 4294967295; + static readonly SIGHASH_ALL = 1; + static readonly SIGHASH_NONE = 2; + static readonly SIGHASH_SINGLE = 3; + static readonly SIGHASH_ANYONECANPAY = 128; + static readonly ADVANCED_TRANSACTION_MARKER = 0; + static readonly ADVANCED_TRANSACTION_FLAG = 1; + constructor(); + static fromBuffer(buffer: Buffer, __noStrict?: boolean): Transaction; + static fromHex(hex: string): Transaction; + static isCoinbaseHash(buffer: Buffer): boolean; + isCoinbase(): boolean; + addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; + addOutput(scriptPubKey: Buffer, value: number): number; + hasWitnesses(): boolean; + weight(): number; + virtualSize(): number; + byteLength(): number; + private __byteLength; + clone(): Transaction; + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex: number, prevOutScript: Buffer, hashType: number): Buffer; + hashForWitnessV0(inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer; + getHash(forWitness?: boolean): Buffer; + getId(): string; + toBuffer(buffer?: Buffer, initialOffset?: number): Buffer; + private __toBuffer; + toHex(): string; + setInputScript(index: number, scriptSig: Buffer): void; + setWitness(index: number, witness: Array): void; +} diff --git a/types/transaction_builder.d.ts b/types/transaction_builder.d.ts new file mode 100644 index 0000000..4be5968 --- /dev/null +++ b/types/transaction_builder.d.ts @@ -0,0 +1,26 @@ +/// +import { Network } from './networks'; +import { Transaction } from './transaction'; +import { ECPairInterface } from './ecpair'; +export declare class TransactionBuilder { + network: Network; + maximumFeeRate: number; + private __prevTxSet; + private __inputs; + private __tx; + constructor(network?: Network, maximumFeeRate?: number); + static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; + setLockTime(locktime: number): void; + setVersion(version: number): void; + addInput(txHash: Buffer | string | Transaction, vout: number, sequence: number, prevOutScript: Buffer): number; + private __addInputUnsafe; + addOutput(scriptPubKey: string | Buffer, value: number): number; + build(): Transaction; + buildIncomplete(): Transaction; + private __build; + sign(vin: number, keyPair: ECPairInterface, redeemScript: Buffer, hashType: number, witnessValue: number, witnessScript: Buffer): void; + private __canModifyInputs; + private __needsOutputs; + private __canModifyOutputs; + private __overMaximumFees; +} diff --git a/types/types.d.ts b/types/types.d.ts new file mode 100644 index 0000000..242bab8 --- /dev/null +++ b/types/types.d.ts @@ -0,0 +1,25 @@ +export declare function UInt31(value: number): boolean; +export declare function BIP32Path(value: string): boolean; +export declare namespace BIP32Path { + var toJSON: () => string; +} +export declare function Satoshi(value: number): boolean; +export declare const ECPoint: any; +export declare const Network: any; +export declare const Buffer256bit: any; +export declare const Hash160bit: any; +export declare const Hash256bit: any; +export declare const Number: any; +export declare const Array: any; +export declare const Boolean: any; +export declare const String: any; +export declare const Buffer: any; +export declare const Hex: any; +export declare const maybe: any; +export declare const tuple: any; +export declare const UInt8: any; +export declare const UInt32: any; +export declare const Function: any; +export declare const BufferN: any; +export declare const Null: any; +export declare const oneOf: any; From 1ed037025c69cf65c50db0b1bef16022cff91cf1 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 7 Jan 2019 16:33:57 +0900 Subject: [PATCH 102/183] Fix testnet address test --- test/integration/addresses.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 5afc5e8..7cf2612 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -95,8 +95,8 @@ describe('bitcoinjs-lib (addresses)', function () { const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET }) - // bitcoin testnet P2PKH addresses start with a 'm' - assert.strictEqual(address.startsWith('m'), true) + // bitcoin testnet P2PKH addresses start with a 'm' or 'n' + assert.strictEqual(address.startsWith('m') || address.startsWith('n'), true) }) it('can generate a Litecoin address', function () { From 1732bafbc14d6926fd6074e02566954eed79e1f1 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 15 Jan 2019 17:47:30 +0900 Subject: [PATCH 103/183] Update TypeScript to use ! instead of casting --- src/payments/p2pkh.js | 2 +- src/payments/p2wpkh.js | 2 +- src/transaction.js | 6 +- src/transaction_builder.js | 5 +- ts_src/block.ts | 12 +-- ts_src/payments/embed.ts | 6 +- ts_src/payments/p2ms.ts | 26 +++---- ts_src/payments/p2pk.ts | 8 +- ts_src/payments/p2pkh.ts | 4 +- ts_src/payments/p2sh.ts | 8 +- ts_src/payments/p2wpkh.ts | 2 +- ts_src/payments/p2wsh.ts | 6 +- ts_src/script.ts | 2 +- ts_src/templates/scripthash/input.ts | 6 +- ts_src/templates/witnesscommitment/output.ts | 2 +- ts_src/transaction.ts | 18 ++--- ts_src/transaction_builder.ts | 81 ++++++++++---------- 17 files changed, 99 insertions(+), 97 deletions(-) diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 443464a..55f4817 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -50,7 +50,7 @@ function p2pkh(a, opts) { if (a.address) return _address().hash; if (a.pubkey || o.pubkey) - return bcrypto.hash160(a.pubkey || o.pubkey); // eslint-disable-line + return bcrypto.hash160(a.pubkey || o.pubkey); }); lazy.prop(o, 'output', function () { if (!o.hash) diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index 98951c6..7b269b7 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -55,7 +55,7 @@ function p2wpkh(a, opts) { if (a.address) return _address().data; if (a.pubkey || o.pubkey) - return bcrypto.hash160(a.pubkey || o.pubkey); // eslint-disable-line + return bcrypto.hash160(a.pubkey || o.pubkey); }); lazy.prop(o, 'output', function () { if (!o.hash) diff --git a/src/transaction.js b/src/transaction.js index 6619b79..34d7b40 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -369,13 +369,13 @@ class Transaction { offset += slice.copy(buffer, offset); } function writeUInt8(i) { - offset = buffer.writeUInt8(i, offset); + offset = (buffer).writeUInt8(i, offset); } function writeUInt32(i) { - offset = buffer.writeUInt32LE(i, offset); + offset = (buffer).writeUInt32LE(i, offset); } function writeInt32(i) { - offset = buffer.writeInt32LE(i, offset); + offset = (buffer).writeInt32LE(i, offset); } function writeUInt64(i) { offset = bufferutils.writeUInt64LE(buffer, i, offset); diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 2121156..1cdc6bf 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -270,7 +270,7 @@ class TransactionBuilder { return this.__inputs.every(input => { if (input.signatures === undefined) return true; - return input.signatures.every((signature => { + return input.signatures.every(signature => { if (!signature) return true; const hashType = signatureHashType(signature); @@ -283,7 +283,8 @@ class TransactionBuilder { // of more outputs return nInputs <= nOutputs; } - })); + return false; + }); }); } __overMaximumFees(bytes) { diff --git a/ts_src/block.ts b/ts_src/block.ts index 82700aa..cb50559 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -129,7 +129,7 @@ export class Block { if (transactions.length === 0) throw errorMerkleNoTxes if (forWitness && !txesHaveWitness(transactions)) throw errorWitnessNotSegwit - const hashes = transactions.map(transaction => transaction.getHash((forWitness))) + const hashes = transactions.map(transaction => transaction.getHash(forWitness!)) const rootHash = fastMerkleRoot(hashes, bcrypto.hash256) @@ -139,7 +139,7 @@ export class Block { } hasWitnessCommit (): boolean { - return txesHaveWitness(>this.transactions) + return txesHaveWitness(this.transactions!) } byteLength (headersOnly: boolean): number { @@ -184,8 +184,8 @@ export class Block { } writeInt32(this.version) - writeSlice(this.prevHash) - writeSlice(this.merkleRoot) + writeSlice(this.prevHash!) + writeSlice(this.merkleRoot!) writeUInt32(this.timestamp) writeUInt32(this.bits) writeUInt32(this.nonce) @@ -212,7 +212,7 @@ export class Block { if (!this.transactions) throw errorMerkleNoTxes const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) - return (this.merkleRoot).compare(actualMerkleRoot) === 0 + return this.merkleRoot!.compare(actualMerkleRoot) === 0 } checkWitnessCommit (): boolean { @@ -220,7 +220,7 @@ export class Block { if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true) - return (this.witnessCommit).compare(actualWitnessCommit) === 0 + return this.witnessCommit!.compare(actualWitnessCommit) === 0 } checkProofOfWork (): boolean { diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index 8cc8899..bfaeb8b 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -36,15 +36,15 @@ export function p2data (a: Payment, opts?: PaymentOpts): Payment { }) lazy.prop(o, 'data', function () { if (!a.output) return - return (>bscript.decompile(a.output)).slice(1) + return bscript.decompile(a.output)!.slice(1) }) // extended validation if (opts.validate) { if (a.output) { const chunks = bscript.decompile(a.output) - if ((>chunks)[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') - if (!(>chunks).slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') + if (chunks![0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') + if (!chunks!.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') if (a.data && !stacksEqual(a.data, >o.data)) throw new TypeError('Data mismatch') } diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index 67b9692..34e2d31 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -29,7 +29,7 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { function isAcceptableSignature (x: Buffer | number) { return bscript.isCanonicalScriptSignature(x) || - ((opts).allowIncomplete && + (opts!.allowIncomplete && ( x === OPS.OP_0)) !== undefined // eslint-disable-line } @@ -85,7 +85,7 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { }) lazy.prop(o, 'signatures', function () { if (!a.input) return - return (>bscript.decompile(a.input)).slice(1) + return bscript.decompile(a.input)!.slice(1) }) lazy.prop(o, 'input', function () { if (!a.signatures) return @@ -105,35 +105,35 @@ export function p2ms (a: Payment, opts?: PaymentOpts): Payment { if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid') if ( - (o).m <= 0 || // eslint-disable-line - (o).n > 16 || // eslint-disable-line - (o).m > (o).n || // eslint-disable-line + o.m! <= 0 || // eslint-disable-line + o.n! > 16 || // eslint-disable-line + o.m! > o.n! || // eslint-disable-line o.n !== chunks.length - 3) throw new TypeError('Output is invalid') - if (!(>o.pubkeys).every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') + if (!o.pubkeys!.every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch') if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch') - if (a.pubkeys && !stacksEqual(a.pubkeys, (>o.pubkeys))) throw new TypeError('Pubkeys mismatch') + if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys!)) throw new TypeError('Pubkeys mismatch') } if (a.pubkeys) { if (a.n !== undefined && a.n !== a.pubkeys.length) throw new TypeError('Pubkey count mismatch') o.n = a.pubkeys.length - if (o.n < (o).m) throw new TypeError('Pubkey count cannot be less than m') + if (o.n < o.m!) throw new TypeError('Pubkey count cannot be less than m') } if (a.signatures) { - if (a.signatures.length < (o).m) throw new TypeError('Not enough signatures provided') - if (a.signatures.length > (o).m) throw new TypeError('Too many signatures provided') + if (a.signatures.length < o.m!) throw new TypeError('Not enough signatures provided') + if (a.signatures.length > o.m!) throw new TypeError('Too many signatures provided') } if (a.input) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') - if ((>o.signatures).length === 0 || !(>o.signatures).every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') + if (o.signatures!.length === 0 || !o.signatures!.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - if (a.signatures && !stacksEqual(a.signatures, (>o.signatures))) throw new TypeError('Signature mismatch') - if (a.m !== undefined && a.m !== (>a.signatures).length) throw new TypeError('Signature count mismatch') + if (a.signatures && !stacksEqual(a.signatures, o.signatures!)) throw new TypeError('Signature mismatch') + if (a.m !== undefined && a.m !== a.signatures!.length) throw new TypeError('Signature count mismatch') } } diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index 0825955..3385c56 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -27,7 +27,7 @@ export function p2pk (a: Payment, opts?: PaymentOpts): Payment { input: typef.maybe(typef.Buffer) }, a) - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) const network = a.network || BITCOIN_NETWORK const o: Payment = { network } @@ -61,16 +61,16 @@ export function p2pk (a: Payment, opts?: PaymentOpts): Payment { if (a.output) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') if (!ecc.isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid') - if (a.pubkey && !a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch') + if (a.pubkey && !a.pubkey.equals(o.pubkey!)) throw new TypeError('Pubkey mismatch') } if (a.signature) { - if (a.input && !a.input.equals(o.input)) throw new TypeError('Signature mismatch') + if (a.input && !a.input.equals(o.input!)) throw new TypeError('Signature mismatch') } if (a.input) { if (_chunks().length !== 1) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(o.signature)) throw new TypeError('Input has invalid signature') + if (!bscript.isCanonicalScriptSignature(o.signature!)) throw new TypeError('Input has invalid signature') } } diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index f12faf8..ddb9cc3 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -38,7 +38,7 @@ export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { const hash = payload.slice(1) return { version, hash } }) - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) const network = a.network || BITCOIN_NETWORK const o: Payment = { network } @@ -54,7 +54,7 @@ export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(3, 23) if (a.address) return _address().hash - if (a.pubkey || o.pubkey) return bcrypto.hash160( a.pubkey || o.pubkey) // eslint-disable-line + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!) }) lazy.prop(o, 'output', function () { if (!o.hash) return diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index e0292f3..1aa1a94 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -59,7 +59,7 @@ export function p2sh (a: Payment, opts?: PaymentOpts): Payment { const hash = payload.slice(1) return { version, hash } }) - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input) }) + const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) const _redeem = lazy.value(function (): Payment { const chunks = _chunks() return { @@ -75,7 +75,7 @@ export function p2sh (a: Payment, opts?: PaymentOpts): Payment { if (!o.hash) return const payload = Buffer.allocUnsafe(21) - payload.writeUInt8((o.network).scriptHash, 0) + payload.writeUInt8(o.network!.scriptHash, 0) o.hash.copy(payload, 1) return bs58check.encode(payload) }) @@ -173,8 +173,8 @@ export function p2sh (a: Payment, opts?: PaymentOpts): Payment { if (a.redeem.network && a.redeem.network !== network) throw new TypeError('Network mismatch') if (a.input) { const redeem = _redeem() - if (a.redeem.output && !a.redeem.output.equals(redeem.output)) throw new TypeError('Redeem.output mismatch') - if (a.redeem.input && !a.redeem.input.equals(redeem.input)) throw new TypeError('Redeem.input mismatch') + if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) throw new TypeError('Redeem.output mismatch') + if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) throw new TypeError('Redeem.input mismatch') } checkRedeem(a.redeem) diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index b40085b..6cfecc4 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -59,7 +59,7 @@ export function p2wpkh (a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(2, 22) if (a.address) return _address().data - if (a.pubkey || o.pubkey) return bcrypto.hash160( a.pubkey || o.pubkey) // eslint-disable-line + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!) }) lazy.prop(o, 'output', function () { if (!o.hash) return diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 7e2f237..452dcc3 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -58,7 +58,7 @@ export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { data: Buffer.from(data) } }) - const _rchunks = <()=>Array>lazy.value(function () { return bscript.decompile((a.redeem).input) }) + const _rchunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.redeem!.input!) }) let network = a.network if (!network) { @@ -71,7 +71,7 @@ export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { if (!o.hash) return const words = bech32.toWords(o.hash) words.unshift(0x00) - return bech32.encode((network).bech32, words) + return bech32.encode(network!.bech32, words) }) lazy.prop(o, 'hash', function () { if (a.output) return a.output.slice(2) @@ -158,7 +158,7 @@ export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { // is the redeem output non-empty? if (a.redeem.output) { - if ((>bscript.decompile(a.redeem.output)).length === 0) throw new TypeError('Redeem.output is invalid') + if (bscript.decompile(a.redeem.output)!.length === 0) throw new TypeError('Redeem.output is invalid') // match hash against other sources const hash2 = bcrypto.sha256(a.redeem.output) diff --git a/ts_src/script.ts b/ts_src/script.ts index 79e3342..64b74ad 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -125,7 +125,7 @@ export function decompile (buffer: Buffer | Array): Arrayop) + chunks.push(op) } else { chunks.push(data) } diff --git a/ts_src/templates/scripthash/input.ts b/ts_src/templates/scripthash/input.ts index 90af0fe..7b3107d 100644 --- a/ts_src/templates/scripthash/input.ts +++ b/ts_src/templates/scripthash/input.ts @@ -10,14 +10,14 @@ import * as p2wsho from '../witnessscripthash/output' export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = >bscript.decompile(script) + const chunks = bscript.decompile(script)! if (chunks.length < 1) return false const lastChunk = chunks[chunks.length - 1] if (!Buffer.isBuffer(lastChunk)) return false - const scriptSigChunks = >bscript.decompile(bscript.compile(chunks.slice(0, -1))) - const redeemScriptChunks = bscript.decompile(lastChunk) + const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1)))! + const redeemScriptChunks = bscript.decompile(lastChunk) // is redeemScript a valid script? if (!redeemScriptChunks) return false diff --git a/ts_src/templates/witnesscommitment/output.ts b/ts_src/templates/witnesscommitment/output.ts index 71e8df3..0bdf11c 100644 --- a/ts_src/templates/witnesscommitment/output.ts +++ b/ts_src/templates/witnesscommitment/output.ts @@ -32,5 +32,5 @@ export function encode (commitment: Buffer): Buffer { export function decode (buffer: Buffer): Buffer { typeforce(check, buffer) - return ((>bscript.decompile(buffer))[1]).slice(4, 36) + return (bscript.decompile(buffer)![1]).slice(4, 36) } diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 29b49c8..e6e1d24 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -294,8 +294,8 @@ export class Transaction { if (inIndex >= this.ins.length) return ONE // ignore OP_CODESEPARATOR - const ourScript = bscript.compile((>bscript.decompile(prevOutScript)).filter((x) => { - return x !== opcodes.OP_CODESEPARATOR + const ourScript = bscript.compile(bscript.decompile(prevOutScript)!.filter((x) => { + return x !== opcodes.OP_CODESEPARATOR })) const txTmp = this.clone() @@ -471,28 +471,28 @@ export class Transaction { } private __toBuffer (buffer?: Buffer, initialOffset?: number, __allowWitness?: boolean): Buffer { - if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength((__allowWitness))) + if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness!)) let offset = initialOffset || 0 function writeSlice (slice: Buffer): void { - offset += slice.copy(buffer, offset) + offset += slice.copy(buffer!, offset) } function writeUInt8 (i: number) { - offset = (buffer).writeUInt8(i, offset) + offset = (buffer!).writeUInt8(i, offset) } function writeUInt32 (i: number) { - offset = (buffer).writeUInt32LE(i, offset) + offset = (buffer!).writeUInt32LE(i, offset) } function writeInt32 (i: number) { - offset = (buffer).writeInt32LE(i, offset) + offset = (buffer!).writeInt32LE(i, offset) } function writeUInt64 (i: number) { - offset = bufferutils.writeUInt64LE(buffer, i, offset) + offset = bufferutils.writeUInt64LE(buffer!, i, offset) } function writeVarInt (i: number) { @@ -548,7 +548,7 @@ export class Transaction { writeUInt32(this.locktime) // avoid slicing unless necessary - if (initialOffset !== undefined) return buffer.slice((initialOffset), offset) + if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) return buffer } diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 59fc102..969462c 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -50,11 +50,11 @@ interface TxbOutput { } function txIsString(tx: Buffer | string | Transaction): tx is string { - return typeof (tx) === 'string' || tx instanceof String + return typeof tx === 'string' || tx instanceof String } function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { - return (tx) instanceof Transaction + return tx instanceof Transaction } export class TransactionBuilder { @@ -209,7 +209,7 @@ export class TransactionBuilder { scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network) } - return this.__tx.addOutput(scriptPubKey, value) + return this.__tx.addOutput(scriptPubKey, value) } build (): Transaction { @@ -232,15 +232,15 @@ export class TransactionBuilder { this.__inputs.forEach((input, i) => { if (!input.prevOutType && !allowIncomplete) throw new Error('Transaction is not complete') - const result = build(input.prevOutType, input, allowIncomplete) + const result = build(input.prevOutType!, input, allowIncomplete) if (!result) { if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) throw new Error('Unknown input type') if (!allowIncomplete) throw new Error('Not enough information') return } - tx.setInputScript(i, result.input) - tx.setWitness(i, >result.witness) + tx.setInputScript(i, result.input!) + tx.setWitness(i, result.witness!) }) if (!allowIncomplete) { @@ -270,7 +270,7 @@ export class TransactionBuilder { throw new Error('Inconsistent redeemScript') } - const ourPubKey = keyPair.publicKey || (<()=>Buffer>keyPair.getPublicKey)() + const ourPubKey = keyPair.publicKey || keyPair.getPublicKey!() if (!canSign(input)) { if (witnessValue !== undefined) { if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue') @@ -297,9 +297,9 @@ export class TransactionBuilder { } // enforce in order signing of public keys - const signed = (>input.pubkeys).some((pubKey, i) => { - if (!ourPubKey.equals(pubKey)) return false - if ((>input.signatures)[i]) throw new Error('Signature already exists') + const signed = input.pubkeys!.some((pubKey, i) => { + if (!ourPubKey.equals(pubKey!)) return false + if (input.signatures![i]) throw new Error('Signature already exists') // TODO: add tests if (ourPubKey.length !== 33 && input.hasWitness) { @@ -307,7 +307,7 @@ export class TransactionBuilder { } const signature = keyPair.sign(signatureHash) - ;(>input.signatures)[i] = bscript.signature.encode(signature, hashType) + input.signatures![i] = bscript.signature.encode(signature, hashType) return true }) @@ -355,7 +355,7 @@ export class TransactionBuilder { return this.__inputs.every(input => { if (input.signatures === undefined) return true - return input.signatures.every(<(signature: Buffer | undefined)=>boolean>(signature => { + return input.signatures.every(signature => { if (!signature) return true const hashType = signatureHashType(signature) @@ -367,13 +367,14 @@ export class TransactionBuilder { // of more outputs return nInputs <= nOutputs } - })) + return false + }) }) } private __overMaximumFees (bytes: number): boolean { // not all inputs will have .value defined - const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0) + const incoming = this.__inputs.reduce((a, x) => a + (x.value! >>> 0), 0) // but all outputs do, and if we have any input value // we can immediately determine if the outputs are too small @@ -449,14 +450,14 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str witness: witnessStack }) - const outputType = classify.output((redeem).output) - const expanded = expandInput((redeem).input, >(redeem).witness, outputType, (redeem).output) + const outputType = classify.output(redeem!.output!) + const expanded = expandInput(redeem!.input!, redeem!.witness!, outputType, redeem!.output) if (!expanded.prevOutType) return {} return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2SH, - redeemScript: (redeem).output, + redeemScript: redeem!.output, redeemScriptType: expanded.prevOutType, witnessScript: expanded.witnessScript, witnessScriptType: expanded.witnessScriptType, @@ -471,19 +472,19 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str input: scriptSig, witness: witnessStack }) - const outputType = classify.output((redeem).output) + const outputType = classify.output(redeem!.output!) let expanded if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput((redeem).input, >(redeem).witness, outputType) + expanded = expandInput(redeem!.input!, redeem!.witness!, outputType) } else { - expanded = expandInput(bscript.compile(>(redeem).witness), [], outputType, (redeem).output) + expanded = expandInput(bscript.compile(redeem!.witness!), [], outputType, redeem!.output) } if (!expanded.prevOutType) return {} return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2WSH, - witnessScript: (redeem).output, + witnessScript: redeem!.output, witnessScriptType: expanded.prevOutType, pubkeys: expanded.pubkeys, @@ -500,12 +501,12 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str // could be done in expandInput, but requires the original Transaction for hashForSignature function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: number): void { if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return - if ((>input.pubkeys).length === (>input.signatures).length) return + if (input.pubkeys!.length === input.signatures!.length) return - const unmatched = (>input.signatures).concat() + const unmatched = input.signatures!.concat() - input.signatures = >(>input.pubkeys).map(pubKey => { - const keyPair = ECPair.fromPublicKey(pubKey) + input.signatures = input.pubkeys!.map(pubKey => { + const keyPair = ECPair.fromPublicKey(pubKey!) let match: Buffer | undefined // check for a signature @@ -515,7 +516,7 @@ function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: numbe // TODO: avoid O(n) hashForSignature const parsed = bscript.signature.decode(signature) - const hash = transaction.hashForSignature(vin, (input.redeemScript), parsed.hashType) + const hash = transaction.hashForSignature(vin, input.redeemScript!, parsed.hashType) // skip if signature does not match pubKey if (!keyPair.verify(hash, parsed.signature)) return false @@ -542,7 +543,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { // does our hash160(pubKey) match the output scripts? const pkh1 = payments.p2pkh({ output: script }).hash const pkh2 = bcrypto.hash160(ourPubKey) - if (!(pkh1).equals(pkh2)) return { type } + if (!pkh1!.equals(pkh2)) return { type } return { type, @@ -557,7 +558,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { // does our hash160(pubKey) match the output scripts? const wpkh1 = payments.p2wpkh({ output: script }).hash const wpkh2 = bcrypto.hash160(ourPubKey) - if (!(wpkh1).equals(wpkh2)) return { type } + if (!wpkh1!.equals(wpkh2)) return { type } return { type, @@ -580,7 +581,7 @@ function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { return { type, pubkeys: p2ms.pubkeys, - signatures: (>p2ms.pubkeys).map((): undefined => undefined), + signatures: p2ms.pubkeys!.map((): undefined => undefined), maxSignatures: p2ms.m } } @@ -597,10 +598,10 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, const p2shAlt = payments.p2sh({ redeem: p2wsh }) // enforces P2SH(P2WSH(...)) - if (!(p2wsh.hash).equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') - if (!(p2sh.hash).equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') + if (!p2wsh.hash!.equals(p2wshAlt.hash!)) throw new Error('Witness script inconsistent with prevOutScript') + if (!p2sh.hash!.equals(p2shAlt.hash!)) throw new Error('Redeem script inconsistent with prevOutScript') - const expanded = expandOutput((p2wsh.redeem).output, ourPubKey) + const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -637,10 +638,10 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, try { p2shAlt = payments.p2sh({ output: input.prevOutScript }) } catch (e) { throw new Error('PrevOutScript must be P2SH') } - if (!(p2sh.hash).equals(p2shAlt.hash)) throw new Error('Redeem script inconsistent with prevOutScript') + if (!p2sh.hash!.equals(p2shAlt.hash!)) throw new Error('Redeem script inconsistent with prevOutScript') } - const expanded = expandOutput((p2sh.redeem).output, ourPubKey) + const expanded = expandOutput(p2sh.redeem!.output!, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -648,7 +649,7 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, let signScript = redeemScript if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output! } return { @@ -669,14 +670,14 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, } if (witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) if (input.prevOutScript) { const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }) - if (!(p2wsh.hash).equals(p2wshAlt.hash)) throw new Error('Witness script inconsistent with prevOutScript') + if (!p2wsh.hash!.equals(p2wshAlt.hash!)) throw new Error('Witness script inconsistent with prevOutScript') } - const expanded = expandOutput((p2wsh.redeem).output, ourPubKey) + const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey) if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures @@ -784,7 +785,7 @@ function build (type: string, input: TxbInput, allowIncomplete?: boolean): Payme return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }) } case SCRIPT_TYPES.P2SH: { - const redeem = build(input.redeemScriptType, input, allowIncomplete) + const redeem = build(input.redeemScriptType!, input, allowIncomplete) if (!redeem) return return payments.p2sh({ @@ -796,7 +797,7 @@ function build (type: string, input: TxbInput, allowIncomplete?: boolean): Payme }) } case SCRIPT_TYPES.P2WSH: { - const redeem = build(input.witnessScriptType, input, allowIncomplete) + const redeem = build(input.witnessScriptType!, input, allowIncomplete) if (!redeem) return return payments.p2wsh({ From c143e9c855912d6d60e5bd5fc9aea188a868cdf3 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 15 Jan 2019 17:48:10 +0900 Subject: [PATCH 104/183] Specify version to help prevent large diffs --- package.json | 6 +++--- tsconfig.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c00414a..a77761b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "bitcoinjs" ], "scripts": { - "build": "tsc -d -p ./tsconfig.json", + "build": "tsc -p ./tsconfig.json", "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", @@ -39,7 +39,7 @@ "src" ], "dependencies": { - "@types/node": "^10.12.18", + "@types/node": "10.12.18", "bech32": "^1.1.2", "bip32": "git+https://github.com/junderw/bip32.git#typeScript", "bip66": "^1.1.0", @@ -52,7 +52,7 @@ "randombytes": "^2.0.1", "tiny-secp256k1": "^1.0.0", "typeforce": "^1.11.3", - "typescript": "^3.2.2", + "typescript": "3.2.2", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" }, diff --git a/tsconfig.json b/tsconfig.json index 787769d..0ab4612 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "target": "ES2015", "module": "commonjs", "outDir": "./src", + "declaration": true, "declarationDir": "./types", "rootDir": "./ts_src", "types": [ From 581ab5f13622fde017ff8a07f1af7703dd89545e Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 17 Jan 2019 16:52:58 +0900 Subject: [PATCH 105/183] Add files to package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a77761b..2a38c47 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git" }, "files": [ - "src" + "src", + "types" ], "dependencies": { "@types/node": "10.12.18", From e52abecee2425917e703984903bf5d3d13f99bbf Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 17 Jan 2019 17:01:15 +0900 Subject: [PATCH 106/183] Move to checkTxRoots and warn checkMerkleRoot deprecation --- src/block.js | 11 ++++++++++- test/block.js | 10 ++-------- ts_src/block.ts | 13 ++++++++++++- types/block.d.ts | 4 +++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/block.js b/src/block.js index 5b4776f..6f4721a 100644 --- a/src/block.js +++ b/src/block.js @@ -167,13 +167,22 @@ class Block { toHex(headersOnly) { return this.toBuffer(headersOnly).toString('hex'); } + checkTxRoots() { + return this.__checkMerkleRoot() && + (this.hasWitnessCommit() ? this.__checkWitnessCommit() : true); + } checkMerkleRoot() { + console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + + 'deprecated in v5. Please use checkTxRoots instead.'); + return this.checkTxRoots(); + } + __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); return this.merkleRoot.compare(actualMerkleRoot) === 0; } - checkWitnessCommit() { + __checkWitnessCommit() { if (!this.transactions) throw errorMerkleNoTxes; if (!this.hasWitnessCommit()) diff --git a/test/block.js b/test/block.js index 76b043d..e646737 100644 --- a/test/block.js +++ b/test/block.js @@ -125,7 +125,7 @@ describe('Block', function () { }) }) - describe('checkMerkleRoot', function () { + describe('checkTxRoots', function () { fixtures.valid.forEach(function (f) { if (f.hex.length === 160) return @@ -136,14 +136,8 @@ describe('Block', function () { }) it('returns ' + f.valid + ' for ' + f.id, function () { - assert.strictEqual(block.checkMerkleRoot(), true) + assert.strictEqual(block.checkTxRoots(), true) }) - - if (f.witnessCommit) { - it('validates witness commit for ' + f.id, function () { - assert.strictEqual(block.checkWitnessCommit(), true) - }) - } }) }) diff --git a/ts_src/block.ts b/ts_src/block.ts index cb50559..e5ea071 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -208,14 +208,25 @@ export class Block { return this.toBuffer(headersOnly).toString('hex') } + checkTxRoots (): boolean { + return this.__checkMerkleRoot() && + (this.hasWitnessCommit() ? this.__checkWitnessCommit() : true) + } + checkMerkleRoot (): boolean { + console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + + 'deprecated in v5. Please use checkTxRoots instead.') + return this.checkTxRoots() + } + + __checkMerkleRoot (): boolean { if (!this.transactions) throw errorMerkleNoTxes const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) return this.merkleRoot!.compare(actualMerkleRoot) === 0 } - checkWitnessCommit (): boolean { + __checkWitnessCommit (): boolean { if (!this.transactions) throw errorMerkleNoTxes if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit diff --git a/types/block.d.ts b/types/block.d.ts index ff98de2..3ff2926 100644 --- a/types/block.d.ts +++ b/types/block.d.ts @@ -21,7 +21,9 @@ export declare class Block { getUTCDate(): Date; toBuffer(headersOnly: boolean): Buffer; toHex(headersOnly: boolean): string; + checkTxRoots(): boolean; checkMerkleRoot(): boolean; - checkWitnessCommit(): boolean; + __checkMerkleRoot(): boolean; + __checkWitnessCommit(): boolean; checkProofOfWork(): boolean; } From 4c6ea8045937b87bb11db1da255bd0bea1a3a403 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 17 Jan 2019 17:10:52 +0900 Subject: [PATCH 107/183] Check for segwit block with no witness commit --- src/block.js | 67 ++++++++++++++++++++++++++++++++------------- ts_src/block.ts | 70 ++++++++++++++++++++++++++++++++++-------------- types/block.d.ts | 2 ++ 3 files changed, 100 insertions(+), 39 deletions(-) diff --git a/src/block.js b/src/block.js index 6f4721a..cb593ac 100644 --- a/src/block.js +++ b/src/block.js @@ -9,10 +9,8 @@ const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); -const errorBufferTooSmall = new Error('Buffer too small (< 80 bytes)'); -function txesHaveWitness(transactions) { - return transactions !== undefined && - transactions instanceof Array && +function txesHaveWitnessCommit(transactions) { + return transactions instanceof Array && transactions[0] && transactions[0].ins && transactions[0].ins instanceof Array && @@ -21,6 +19,14 @@ function txesHaveWitness(transactions) { transactions[0].ins[0].witness instanceof Array && transactions[0].ins[0].witness.length > 0; } +function anyTxHasWitness(transactions) { + return transactions instanceof Array && + transactions.some(tx => typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some(input => typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0)); +} class Block { constructor() { this.version = 1; @@ -34,7 +40,7 @@ class Block { } static fromBuffer(buffer) { if (buffer.length < 80) - throw errorBufferTooSmall; + throw new Error('Buffer too small (< 80 bytes)'); let offset = 0; const readSlice = (n) => { offset += n; @@ -75,18 +81,10 @@ class Block { const tx = readTransaction(); block.transactions.push(tx); } + let witnessCommit = block.getWitnessCommit(); // This Block contains a witness commit - if (block.hasWitnessCommit()) { - // The merkle root for the witness data is in an OP_RETURN output. - // There is no rule for the index of the output, so use filter to find it. - // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed - // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = block.transactions[0].outs - .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) - .map(out => out.script.slice(6, 38)); - // Use the commit with the highest output (should only be one though) - block.witnessCommit = witnessCommits[witnessCommits.length - 1]; - } + if (witnessCommit) + block.witnessCommit = witnessCommit; return block; } static fromHex(hex) { @@ -103,7 +101,7 @@ class Block { typeforce([{ getHash: types.Function }], transactions); if (transactions.length === 0) throw errorMerkleNoTxes; - if (forWitness && !txesHaveWitness(transactions)) + if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit; const hashes = transactions.map(transaction => transaction.getHash(forWitness)); const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); @@ -111,8 +109,34 @@ class Block { ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) : rootHash; } + getWitnessCommit() { + if (!txesHaveWitnessCommit(this.transactions)) + return null; + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + let witnessCommits = this.transactions[0].outs + .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) + .map(out => out.script.slice(6, 38)); + if (witnessCommits.length === 0) + return null; + // Use the commit with the highest output (should only be one though) + let result = witnessCommits[witnessCommits.length - 1]; + if (!(result instanceof Buffer && result.length === 32)) + return null; + return result; + } hasWitnessCommit() { - return txesHaveWitness(this.transactions); + if (this.witnessCommit instanceof Buffer && + this.witnessCommit.length === 32) + return true; + if (this.getWitnessCommit() !== null) + return true; + return false; + } + hasWitness() { + return anyTxHasWitness(this.transactions); } byteLength(headersOnly) { if (headersOnly || !this.transactions) @@ -168,8 +192,13 @@ class Block { return this.toBuffer(headersOnly).toString('hex'); } checkTxRoots() { + // If the Block has segwit transactions but no witness commit, + // there's no way it can be valid, so fail the check. + let hasWitnessCommit = this.hasWitnessCommit(); + if (!hasWitnessCommit && this.hasWitness()) + return false; return this.__checkMerkleRoot() && - (this.hasWitnessCommit() ? this.__checkWitnessCommit() : true); + (hasWitnessCommit ? this.__checkWitnessCommit() : true); } checkMerkleRoot() { console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + diff --git a/ts_src/block.ts b/ts_src/block.ts index e5ea071..e3d1fc5 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -9,11 +9,9 @@ const varuint = require('varuint-bitcoin') const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions') const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block') -const errorBufferTooSmall = new Error('Buffer too small (< 80 bytes)') -function txesHaveWitness (transactions: Array): boolean { - return transactions !== undefined && - transactions instanceof Array && +function txesHaveWitnessCommit (transactions: Array): boolean { + return transactions instanceof Array && transactions[0] && transactions[0].ins && transactions[0].ins instanceof Array && @@ -23,6 +21,19 @@ function txesHaveWitness (transactions: Array): boolean { transactions[0].ins[0].witness.length > 0 } +function anyTxHasWitness (transactions: Array): boolean { + return transactions instanceof Array && + transactions.some(tx => + typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some(input => + typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0 + ) + ) +} + export class Block { version: number prevHash?: Buffer @@ -45,7 +56,7 @@ export class Block { } static fromBuffer (buffer: Buffer): Block { - if (buffer.length < 80) throw errorBufferTooSmall + if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)') let offset: number = 0 const readSlice = (n: number): Buffer => { @@ -95,19 +106,9 @@ export class Block { block.transactions.push(tx) } + let witnessCommit = block.getWitnessCommit() // This Block contains a witness commit - if (block.hasWitnessCommit()) { - // The merkle root for the witness data is in an OP_RETURN output. - // There is no rule for the index of the output, so use filter to find it. - // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed - // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = block.transactions[0].outs - .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) - .map(out => out.script.slice(6, 38)) - - // Use the commit with the highest output (should only be one though) - block.witnessCommit = witnessCommits[witnessCommits.length - 1] - } + if (witnessCommit) block.witnessCommit = witnessCommit return block } @@ -127,7 +128,7 @@ export class Block { static calculateMerkleRoot (transactions: Array, forWitness?: boolean): Buffer { typeforce([{ getHash: types.Function }], transactions) if (transactions.length === 0) throw errorMerkleNoTxes - if (forWitness && !txesHaveWitness(transactions)) throw errorWitnessNotSegwit + if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit const hashes = transactions.map(transaction => transaction.getHash(forWitness!)) @@ -138,8 +139,33 @@ export class Block { : rootHash } + getWitnessCommit (): Buffer | null { + if (!txesHaveWitnessCommit(this.transactions!)) return null + + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + let witnessCommits = this.transactions![0].outs + .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) + .map(out => out.script.slice(6, 38)) + if (witnessCommits.length === 0) return null + // Use the commit with the highest output (should only be one though) + let result = witnessCommits[witnessCommits.length - 1] + + if (!(result instanceof Buffer && result.length === 32)) return null + return result + } + hasWitnessCommit (): boolean { - return txesHaveWitness(this.transactions!) + if (this.witnessCommit instanceof Buffer && + this.witnessCommit.length === 32) return true + if (this.getWitnessCommit() !== null) return true + return false + } + + hasWitness (): boolean { + return anyTxHasWitness(this.transactions!) } byteLength (headersOnly: boolean): number { @@ -209,8 +235,12 @@ export class Block { } checkTxRoots (): boolean { + // If the Block has segwit transactions but no witness commit, + // there's no way it can be valid, so fail the check. + let hasWitnessCommit = this.hasWitnessCommit() + if (!hasWitnessCommit && this.hasWitness()) return false return this.__checkMerkleRoot() && - (this.hasWitnessCommit() ? this.__checkWitnessCommit() : true) + (hasWitnessCommit ? this.__checkWitnessCommit() : true) } checkMerkleRoot (): boolean { diff --git a/types/block.d.ts b/types/block.d.ts index 3ff2926..8b4f2f1 100644 --- a/types/block.d.ts +++ b/types/block.d.ts @@ -14,7 +14,9 @@ export declare class Block { static fromHex(hex: string): Block; static calculateTarget(bits: number): Buffer; static calculateMerkleRoot(transactions: Array, forWitness?: boolean): Buffer; + getWitnessCommit(): Buffer | null; hasWitnessCommit(): boolean; + hasWitness(): boolean; byteLength(headersOnly: boolean): number; getHash(): Buffer; getId(): string; From 5990ece108b00ccd0d0f61c0b5fbbf3b1fb4fa38 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 17 Jan 2019 17:35:49 +0900 Subject: [PATCH 108/183] Merge Integration test changes from master --- test/integration/addresses.js | 95 +++++++++++++++----------------- test/integration/transactions.js | 34 +++++++++++- 2 files changed, 75 insertions(+), 54 deletions(-) diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 0024410..7cf2612 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -2,34 +2,35 @@ const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') const dhttp = require('dhttp/200') - -const LITECOIN = { - messagePrefix: '\x19Litecoin Signed Message:\n', - bip32: { - public: 0x019da462, - private: 0x019d9cfe - }, - pubKeyHash: 0x30, - scriptHash: 0x32, - wif: 0xb0 -} - -// deterministic RNG for testing only -function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } +const TESTNET = bitcoin.networks.testnet describe('bitcoinjs-lib (addresses)', function () { - it('can generate a random address', function () { - const keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) + it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', function (done) { + const keyPair = bitcoin.ECPair.makeRandom() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') + // bitcoin P2PKH addresses start with a '1' + assert.strictEqual(address.startsWith('1'), true) + + dhttp({ + method: 'GET', + url: 'https://blockchain.info/rawaddr/' + address + }, function (err, result) { + if (err) return done(err) + + // random private keys [probably!] have no transactions + assert.strictEqual(result.n_tx, 0) + assert.strictEqual(result.total_received, 0) + assert.strictEqual(result.total_sent, 0) + done() + }) }) it('can import an address via WIF', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') + assert.strictEqual(address, '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH') }) it('can generate a P2SH, pay-to-multisig (2-of-3) address', function () { @@ -46,19 +47,19 @@ describe('bitcoinjs-lib (addresses)', function () { }) it('can generate a SegWit address', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) - assert.strictEqual(address, 'bc1qt97wqg464zrhnx23upykca5annqvwkwujjglky') + assert.strictEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4') }) it('can generate a SegWit address (via P2SH)', function () { - const keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') + const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) }) - assert.strictEqual(address, '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53') + assert.strictEqual(address, '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN') }) it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', function () { @@ -89,41 +90,31 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, '3P4mrxQfmExfhxqjLnR2Ah4WES5EB1KBrN') }) - it('can support the retrieval of transactions for an address (via 3PBP)', function (done) { - const keyPair = bitcoin.ECPair.makeRandom() - const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) - - dhttp({ - method: 'GET', - url: 'https://blockchain.info/rawaddr/' + address - }, function (err, result) { - if (err) return done(err) - - // random private keys [probably!] have no transactions - assert.strictEqual(result.n_tx, 0) - assert.strictEqual(result.total_received, 0) - assert.strictEqual(result.total_sent, 0) - done() - }) - }) - - // other networks + // examples using other network information it('can generate a Testnet address', function () { - const testnet = bitcoin.networks.testnet - const keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: rng }) - const wif = keyPair.toWIF() - const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: testnet }) + const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET }) + const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET }) - assert.strictEqual(address, 'mubSzQNtZfDj1YdNP6pNDuZy6zs6GDn61L') - assert.strictEqual(wif, 'cRgnQe9MUu1JznntrLaoQpB476M8PURvXVQB5R2eqms5tXnzNsrr') + // bitcoin testnet P2PKH addresses start with a 'm' or 'n' + assert.strictEqual(address.startsWith('m') || address.startsWith('n'), true) }) it('can generate a Litecoin address', function () { - const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN, rng: rng }) - const wif = keyPair.toWIF() + // WARNING: although possible, bitcoinjs is NOT necessarily compatible with Litecoin + const LITECOIN = { + messagePrefix: '\x19Litecoin Signed Message:\n', + bip32: { + public: 0x019da462, + private: 0x019d9cfe + }, + pubKeyHash: 0x30, + scriptHash: 0x32, + wif: 0xb0 + } + + const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN }) - assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') - assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') + assert.strictEqual(address.startsWith('L'), true) }) }) diff --git a/test/integration/transactions.js b/test/integration/transactions.js index e828414..f725241 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -64,7 +64,7 @@ describe('bitcoinjs-lib (transactions)', function () { txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend" txb.addOutput(aliceCpkh.address, 1e4) // Alice's change - // (in)(4e4 + 2e4) - (out)(1e4 + 3e4) = (fee)2e4 = 20000, this is the miner fee + // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee // Alice signs each input with the respective private keys txb.sign(0, alice1) @@ -258,7 +258,7 @@ describe('bitcoinjs-lib (transactions)', function () { }) }) - it('can verify Transaction signatures', function () { + it('can verify Transaction (P2PKH) signatures', function () { const txHex = '010000000321c5f7e7bc98b3feda84aad36a5c99a02bcb8823a2f3eccbcd5da209698b5c20000000006b48304502210099e021772830207cf7c55b69948d3b16b4dcbf1f55a9cd80ebf8221a169735f9022064d33f11d62cd28240b3862afc0b901adc9f231c7124dd19bdb30367b61964c50121032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63dffffffff8a75ce85441ddb3f342708ee33cc8ed418b07d9ba9e0e7c4e1cccfe9f52d8a88000000006946304302207916c23dae212c95a920423902fa44e939fb3d542f4478a7b46e9cde53705800021f0d74e9504146e404c1b8f9cba4dff2d4782e3075491c9ed07ce4a7d1c4461a01210216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2affffffffdfef93f69fe32e944fad79fa8f882b3a155d80383252348caba1a77a5abbf7ef000000006b483045022100faa6e9ca289b46c64764a624c59ac30d9abcf1d4a04c4de9089e67cbe0d300a502206930afa683f6807502de5c2431bf9a1fd333c8a2910a76304df0f3d23d83443f0121039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18fffffffff01ff4b0000000000001976a9146c86476d1d85cd60116cd122a274e6a570a5a35c88acc96d0700' const keyPairs = [ '032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d', @@ -281,4 +281,34 @@ describe('bitcoinjs-lib (transactions)', function () { assert.strictEqual(keyPair.verify(hash, ss.signature), true) }) }) + + it('can verify Transaction (P2SH(P2WPKH)) signatures', function () { + const utxos = { + 'f72d1d83ac40fcedd01415751556a905844ab5f44bbb7728565ebb91b1590109:0': { + value: 50000 + } + } + + const txHex = '02000000000101090159b191bb5e562877bb4bf4b54a8405a95615751514d0edfc40ac831d2df7000000001716001435a179e5516947a39ae9c8a25e9fe62c0fc598edffffffff01204e0000000000001976a91431d43308d3c886d53e9ae8a45728370571ff456988ac0247304402206ec41f685b997a51f325b07ee852e82a535f6b52ef54485cc133e05168aa052a022070bafa86108acb51c77b2b259ae8fb7fd1efa10fef804fcfe9b13c2db719acf5012103fb03e9d0a9af86cbed94225dbb8bb70f6b82109bce0a61ddcf41dab6cbb4871100000000' + const tx = bitcoin.Transaction.fromHex(txHex) + + tx.ins.forEach(function (input, i) { + const txId = Buffer.from(input.hash).reverse().toString('hex') + const utxo = utxos[`${txId}:${i}`] + if (!utxo) throw new Error('Missing utxo') + + const p2sh = bitcoin.payments.p2sh({ + input: input.script, + witness: input.witness + }) + const p2wpkh = bitcoin.payments.p2wpkh(p2sh.redeem) + const p2pkh = bitcoin.payments.p2pkh({ pubkey: p2wpkh.pubkey }) // because P2WPKH is annoying + + const ss = bitcoin.script.signature.decode(p2wpkh.signature) + const hash = tx.hashForWitnessV0(i, p2pkh.output, utxo.value, ss.hashType) + const keyPair = bitcoin.ECPair.fromPublicKey(p2wpkh.pubkey) // aka, cQ3EtF4mApRcogNGSeyPTKbmfxxn3Yfb1wecfKSws9a8bnYuxoAk + + assert.strictEqual(keyPair.verify(hash, ss.signature), true) + }) + }) }) From 3fa86d0f3a034eb8dc8ee4781225852d396d3166 Mon Sep 17 00:00:00 2001 From: johnta0 <22534726+johnta0@users.noreply.github.com> Date: Sat, 19 Jan 2019 12:44:54 +0900 Subject: [PATCH 109/183] Remove unused module declaration --- ts_src/address.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ts_src/address.ts b/ts_src/address.ts index 7d9d351..4299321 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -1,4 +1,3 @@ -import * as Networks from './networks' import { Network } from './networks' import * as types from './types' import * as bscript from './script' From e1ca3775958b20f8249e993a06966346e5411d91 Mon Sep 17 00:00:00 2001 From: johnta0 <22534726+johnta0@users.noreply.github.com> Date: Thu, 24 Jan 2019 12:08:29 +0900 Subject: [PATCH 110/183] Generate package-lock.json Co-authored-by: junderw --- package-lock.json | 4745 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4745 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e34ecd4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4745 @@ +{ + "name": "bitcoinjs-lib", + "version": "4.0.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base-x": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", + "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bech32": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.3.tgz", + "integrity": "sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg==" + }, + "bindings": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" + }, + "bip32": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-1.0.2.tgz", + "integrity": "sha512-kedLYj8yvYzND+EfzeoMSlGiN7ImiRBF/MClJSZPkMfcU+OQO7ZpL5L/Yg+TunebBZIHhunstiQF//KLKSF5rg==", + "requires": { + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "tiny-secp256k1": "^1.0.0", + "typeforce": "^1.11.5", + "wif": "^2.0.6" + } + }, + "bip39": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.5.0.tgz", + "integrity": "sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==", + "dev": true, + "requires": { + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1", + "safe-buffer": "^5.0.1", + "unorm": "^1.3.3" + } + }, + "bip65": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz", + "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==", + "dev": true + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bip68": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz", + "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==", + "dev": true + }, + "bitcoin-ops": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", + "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "deglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", + "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "dev": true, + "requires": { + "find-root": "^1.0.0", + "glob": "^7.0.5", + "ignore": "^3.0.9", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1" + } + }, + "dhttp": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz", + "integrity": "sha512-map1b8iyvxSv0uEw3DUDDK5XvH3aYA7QU9DcXy8e3FBIXSwHPHTZWVrOot7Iu9mieWq5XcrZemEJlob6IdCBmg==", + "dev": true, + "requires": { + "statuses": "^1.5.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", + "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "eslint-config-standard": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz", + "integrity": "sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw==", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz", + "integrity": "sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", + "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz", + "integrity": "sha1-JgAu+/ylmJtyiKwEdQi9JPIXsWk=", + "dev": true, + "requires": { + "builtin-modules": "^1.1.1", + "contains-path": "^0.1.0", + "debug": "^2.6.8", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.1.1", + "has": "^1.0.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-node": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", + "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "dev": true, + "requires": { + "ignore": "^3.3.6", + "minimatch": "^3.0.4", + "resolve": "^1.3.3", + "semver": "^5.4.1" + } + }, + "eslint-plugin-promise": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", + "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", + "dev": true + }, + "eslint-plugin-react": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz", + "integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==", + "dev": true, + "requires": { + "doctrine": "^2.0.2", + "has": "^1.0.1", + "jsx-ast-utils": "^2.0.1", + "prop-types": "^15.6.0" + } + }, + "eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "dev": true + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.10.0.tgz", + "integrity": "sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoodwink": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hoodwink/-/hoodwink-2.0.0.tgz", + "integrity": "sha512-j1jog3tDfhpWlqbVbh29qc7FG7w+NT4ed+QQFGqvww83+50AzzretB7wykZGOe28mBdvCYH3GdHaVWJQ2lJ/4w==", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "^3.0.3" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merkle-lib": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", + "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimaldata": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz", + "integrity": "sha1-AfOywB2LJzmEP9hT1AY2xaLrdms=", + "dev": true, + "requires": { + "bitcoin-ops": "^1.3.0", + "pushdata-bitcoin": "^1.0.1" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "nyc": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz", + "integrity": "sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "arrify": "^1.0.1", + "caching-transform": "^1.0.0", + "convert-source-map": "^1.5.1", + "debug-log": "^1.0.1", + "default-require-extensions": "^1.0.0", + "find-cache-dir": "^0.1.1", + "find-up": "^2.1.0", + "foreground-child": "^1.5.3", + "glob": "^7.0.6", + "istanbul-lib-coverage": "^1.1.2", + "istanbul-lib-hook": "^1.1.0", + "istanbul-lib-instrument": "^1.10.0", + "istanbul-lib-report": "^1.1.3", + "istanbul-lib-source-maps": "^1.2.3", + "istanbul-reports": "^1.4.0", + "md5-hex": "^1.2.0", + "merge-source-map": "^1.1.0", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.0", + "resolve-from": "^2.0.0", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.1", + "spawn-wrap": "^1.4.2", + "test-exclude": "^4.2.0", + "yargs": "11.1.0", + "yargs-parser": "^8.0.0" + }, + "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "requires": { + "default-require-extensions": "^1.0.0" + } + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "atob": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-generator": { + "version": "6.26.1", + "bundled": true, + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "base": { + "version": "0.11.2", + "bundled": true, + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "md5-hex": "^1.2.0", + "mkdirp": "^0.5.1", + "write-file-atomic": "^1.1.4" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "core-js": { + "version": "2.5.6", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "^2.0.0" + } + }, + "define-property": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "detect-indent": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "fragment-cache": { + "version": "0.2.1", + "bundled": true, + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "get-value": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "9.18.0", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "has-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invariant": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-odd": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "^0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "bundled": true, + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.3", + "bundled": true, + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "loose-envify": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "js-tokens": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "^0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "merge-source-map": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "nanomatch": { + "version": "1.2.9", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-odd": "^2.0.0", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "object.pick": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + } + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "bundled": true, + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "ret": { + "version": "0.1.15", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-regex": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "set-value": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true + }, + "source-map-resolve": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "atob": "^2.0.0", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "split-string": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "arrify": "^1.0.1", + "micromatch": "^3.1.8", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "to-fast-properties": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "trim-right": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "union-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "bundled": true, + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "bundled": true, + "dev": true + }, + "use": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.0", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "requires": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "dev": true, + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "proxyquire": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz", + "integrity": "sha512-kptdFArCfGRtQFv3Qwjr10lwbEV0TBJYvfqzhwucyfEXqVgmnAkyEw/S3FYzR5HI9i5QOq4rcqQjZ6AlknlCDQ==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.8.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pushdata-bitcoin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", + "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", + "requires": { + "bitcoin-ops": "^1.3.0" + } + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "*" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "standard": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/standard/-/standard-11.0.1.tgz", + "integrity": "sha512-nu0jAcHiSc8H+gJCXeiziMVZNDYi8MuqrYJKxTgjP4xKXZMKm311boqQIzDrYI/ktosltxt2CbDjYQs9ANC8IA==", + "dev": true, + "requires": { + "eslint": "~4.18.0", + "eslint-config-standard": "11.0.0", + "eslint-config-standard-jsx": "5.0.0", + "eslint-plugin-import": "~2.9.0", + "eslint-plugin-node": "~6.0.0", + "eslint-plugin-promise": "~3.7.0", + "eslint-plugin-react": "~7.7.0", + "eslint-plugin-standard": "~3.0.1", + "standard-engine": "~8.0.0" + } + }, + "standard-engine": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-8.0.1.tgz", + "integrity": "sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw==", + "dev": true, + "requires": { + "deglob": "^2.1.0", + "get-stdin": "^6.0.0", + "minimist": "^1.1.0", + "pkg-conf": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tiny-secp256k1": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.0.1.tgz", + "integrity": "sha512-Wz2kMPWtCI5XBftFeF3bUL8uz2+VlasniKwOkRPjvL7h1QVd9rbhrve/HWUu747kJKzVf1XHonzcdM4Ut8fvww==", + "requires": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.10.0" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "unorm": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", + "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "varuint-bitcoin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz", + "integrity": "sha512-jCEPG+COU/1Rp84neKTyDJQr478/hAfVp5xxYn09QEH0yBjbmPeMfuuQIrp+BUD83hybtYZKhr5elV3bvdV1bA==", + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wif": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", + "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "requires": { + "bs58check": "<3.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } +} From 568e5c818988eeb01deba5e8bb52d6930ac6ac4c Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 25 Jan 2019 14:55:56 +0900 Subject: [PATCH 111/183] 4.0.3 --- CHANGELOG.md | 10 ++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 451a168..f31645b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 4.0.3 +__fixed__ +- Fixed `TransactionBuilder` to require that the Transaction has outputs before signing (#1151) +- Fixed `payments.p2sh`, which now takes the network from the redeem attribute if one is not given in the object argument (#1232) +- Fixed `Block.calculateTarget` to allow for exponents up to 29 (#1285) +- Fixed some low priority rarely occurring bugs with multisig payments and `TransactionBuilder` multisig processing (#1307) + +__added__ +- Regtest network object to `networks` (#1261) + # 4.0.2 __fixed__ - Fixed `TransactionBuilder` not throwing when payment type validation should fail (#1195) diff --git a/package-lock.json b/package-lock.json index e34ecd4..3009813 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "4.0.2", + "version": "4.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 755be28..0c3a31f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "4.0.2", + "version": "4.0.3", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "engines": { From 06868f520e6a75b8dd1acdb60f522a8a55f2f6d9 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Mon, 4 Mar 2019 00:05:11 +0900 Subject: [PATCH 112/183] build: move typescript to devDependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a38c47..384b53d 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "randombytes": "^2.0.1", "tiny-secp256k1": "^1.0.0", "typeforce": "^1.11.3", - "typescript": "3.2.2", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" }, @@ -71,6 +70,7 @@ "nyc": "^11.8.0", "proxyquire": "^2.0.1", "standard": "^11.0.1", + "typescript": "3.2.2", "typescript-eslint-parser": "^21.0.2" }, "license": "MIT", From de361673cf99738231a8422fd8bf3c0fc57c27ff Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Mon, 4 Mar 2019 00:10:12 +0900 Subject: [PATCH 113/183] build: add compiler options to forbid unused local variables and parameters --- ts_src/payments/p2sh.ts | 2 +- ts_src/payments/p2wsh.ts | 2 +- tsconfig.json | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index 1aa1a94..daaa8cc 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -1,5 +1,5 @@ import { Payment, PaymentOpts } from './index' // eslint-disable-line -import { Network, bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line +import { bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 452dcc3..edb0a69 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -1,5 +1,5 @@ import { Payment, PaymentOpts } from './index' // eslint-disable-line -import { Network, bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line +import { bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line import * as bscript from '../script' import * as bcrypto from '../crypto' import * as lazy from './lazy' diff --git a/tsconfig.json b/tsconfig.json index 0ab4612..f770a45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,9 @@ "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, - "esModuleInterop": false + "esModuleInterop": false, + "noUnusedLocals": true, + "noUnusedParameters": true }, "include": [ "ts_src/**/*.ts" From c74ab67ccf23b3796b17808e765ff580685b31ef Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sun, 3 Mar 2019 23:07:34 +0900 Subject: [PATCH 114/183] style: add prettier --- .prettierignore | 0 .prettierrc.json | 4 ++++ package.json | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..e69de29 diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..a20502b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/package.json b/package.json index 384b53d..e55b1a8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", + "format": "prettier ts_src/*.ts ts_src/**/*.ts --ignore-path ./.prettierignore --write", "integration": "npm run build && npm run nobuild:integration", "nobuild:coverage-report": "nyc report --reporter=lcov", "nobuild:coverage-html": "nyc report --reporter=html", @@ -68,6 +69,7 @@ "minimaldata": "^1.0.2", "mocha": "^5.2.0", "nyc": "^11.8.0", + "prettier": "^1.16.4", "proxyquire": "^2.0.1", "standard": "^11.0.1", "typescript": "3.2.2", From 03632f15072470ffa3fd1b6f4e3cbf9d19c6fee9 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sun, 3 Mar 2019 23:07:49 +0900 Subject: [PATCH 115/183] style: apply prettier --- ts_src/address.ts | 120 +++-- ts_src/block.ts | 373 ++++++++------- ts_src/bufferutils.ts | 57 ++- ts_src/classify.ts | 96 ++-- ts_src/crypto.ts | 28 +- ts_src/ecpair.ts | 174 +++---- ts_src/index.ts | 42 +- ts_src/networks.ts | 22 +- ts_src/payments/embed.ts | 91 ++-- ts_src/payments/index.ts | 50 +- ts_src/payments/lazy.ts | 34 +- ts_src/payments/p2ms.ts | 234 +++++---- ts_src/payments/p2pk.ts | 114 ++--- ts_src/payments/p2pkh.ts | 213 +++++---- ts_src/payments/p2sh.ts | 237 +++++----- ts_src/payments/p2wpkh.ts | 212 +++++---- ts_src/payments/p2wsh.ts | 227 +++++---- ts_src/script.ts | 244 +++++----- ts_src/script_number.ts | 77 +-- ts_src/script_signature.ts | 88 ++-- ts_src/templates/nulldata.ts | 21 +- ts_src/transaction.ts | 712 +++++++++++++++------------- ts_src/transaction_builder.ts | 867 ++++++++++++++++++++-------------- ts_src/types.ts | 64 +-- 24 files changed, 2380 insertions(+), 2017 deletions(-) diff --git a/ts_src/address.ts b/ts_src/address.ts index 4299321..d547e78 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -1,101 +1,119 @@ -import { Network } from './networks' -import * as types from './types' -import * as bscript from './script' -import * as networks from './networks' -import * as payments from './payments' +import { Network } from './networks'; +import * as types from './types'; +import * as bscript from './script'; +import * as networks from './networks'; +import * as payments from './payments'; -const bech32 = require('bech32') -const bs58check = require('bs58check') -const typeforce = require('typeforce') +const bech32 = require('bech32'); +const bs58check = require('bs58check'); +const typeforce = require('typeforce'); export type Base58CheckResult = { hash: Buffer; version: number; -} +}; export type Bech32Result = { version: number; prefix: string; data: Buffer; -} +}; -export function fromBase58Check (address: string): Base58CheckResult { - const payload = bs58check.decode(address) +export function fromBase58Check(address: string): Base58CheckResult { + const payload = bs58check.decode(address); // TODO: 4.0.0, move to "toOutputScript" - if (payload.length < 21) throw new TypeError(address + ' is too short') - if (payload.length > 21) throw new TypeError(address + ' is too long') + if (payload.length < 21) throw new TypeError(address + ' is too short'); + if (payload.length > 21) throw new TypeError(address + ' is too long'); - const version = payload.readUInt8(0) - const hash = payload.slice(1) + const version = payload.readUInt8(0); + const hash = payload.slice(1); - return { version: version, hash: hash } + return { version: version, hash: hash }; } -export function fromBech32 (address: string): Bech32Result { - const result = bech32.decode(address) - const data = bech32.fromWords(result.words.slice(1)) +export function fromBech32(address: string): Bech32Result { + const result = bech32.decode(address); + const data = bech32.fromWords(result.words.slice(1)); return { version: result.words[0], prefix: result.prefix, - data: Buffer.from(data) - } + data: Buffer.from(data), + }; } -export function toBase58Check (hash: Buffer, version: number): string { - typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments) +export function toBase58Check(hash: Buffer, version: number): string { + typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); - const payload = Buffer.allocUnsafe(21) - payload.writeUInt8(version, 0) - hash.copy(payload, 1) + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(version, 0); + hash.copy(payload, 1); - return bs58check.encode(payload) + return bs58check.encode(payload); } -export function toBech32 (data: Buffer, version: number, prefix: string): string { - const words = bech32.toWords(data) - words.unshift(version) +export function toBech32( + data: Buffer, + version: number, + prefix: string, +): string { + const words = bech32.toWords(data); + words.unshift(version); - return bech32.encode(prefix, words) + return bech32.encode(prefix, words); } -export function fromOutputScript (output: Buffer, network: Network): string { //TODO: Network - network = network || networks.bitcoin +export function fromOutputScript(output: Buffer, network: Network): string { + //TODO: Network + network = network || networks.bitcoin; - try { return payments.p2pkh({ output, network }).address } catch (e) {} - try { return payments.p2sh({ output, network }).address } catch (e) {} - try { return payments.p2wpkh({ output, network }).address } catch (e) {} - try { return payments.p2wsh({ output, network }).address } catch (e) {} + try { + return payments.p2pkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2sh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wpkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wsh({ output, network }).address; + } catch (e) {} - throw new Error(bscript.toASM(output) + ' has no matching Address') + throw new Error(bscript.toASM(output) + ' has no matching Address'); } -export function toOutputScript (address: string, network: Network): Buffer { - network = network || networks.bitcoin +export function toOutputScript(address: string, network: Network): Buffer { + network = network || networks.bitcoin; - let decodeBase58: Base58CheckResult | undefined = undefined - let decodeBech32: Bech32Result | undefined = undefined + let decodeBase58: Base58CheckResult | undefined = undefined; + let decodeBech32: Bech32Result | undefined = undefined; try { - decodeBase58 = fromBase58Check(address) + decodeBase58 = fromBase58Check(address); } catch (e) {} if (decodeBase58) { - if (decodeBase58.version === network.pubKeyHash) return payments.p2pkh({ hash: decodeBase58.hash }).output - if (decodeBase58.version === network.scriptHash) return payments.p2sh({ hash: decodeBase58.hash }).output + if (decodeBase58.version === network.pubKeyHash) + return payments.p2pkh({ hash: decodeBase58.hash }).output; + if (decodeBase58.version === network.scriptHash) + return payments.p2sh({ hash: decodeBase58.hash }).output; } else { try { - decodeBech32 = fromBech32(address) + decodeBech32 = fromBech32(address); } catch (e) {} if (decodeBech32) { - if (decodeBech32.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix') + if (decodeBech32.prefix !== network.bech32) + throw new Error(address + ' has an invalid prefix'); if (decodeBech32.version === 0) { - if (decodeBech32.data.length === 20) return payments.p2wpkh({ hash: decodeBech32.data }).output - if (decodeBech32.data.length === 32) return payments.p2wsh({ hash: decodeBech32.data }).output + if (decodeBech32.data.length === 20) + return payments.p2wpkh({ hash: decodeBech32.data }).output; + if (decodeBech32.data.length === 32) + return payments.p2wsh({ hash: decodeBech32.data }).output; } } } - throw new Error(address + ' has no matching Script') + throw new Error(address + ' has no matching Script'); } diff --git a/ts_src/block.ts b/ts_src/block.ts index e3d1fc5..feb141e 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -1,17 +1,22 @@ -import { Transaction } from './transaction' -import * as types from './types' -import * as bcrypto from './crypto' -import { reverseBuffer } from './bufferutils' - -const fastMerkleRoot = require('merkle-lib/fastRoot') -const typeforce = require('typeforce') -const varuint = require('varuint-bitcoin') - -const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions') -const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block') - -function txesHaveWitnessCommit (transactions: Array): boolean { - return transactions instanceof Array && +import { Transaction } from './transaction'; +import * as types from './types'; +import * as bcrypto from './crypto'; +import { reverseBuffer } from './bufferutils'; + +const fastMerkleRoot = require('merkle-lib/fastRoot'); +const typeforce = require('typeforce'); +const varuint = require('varuint-bitcoin'); + +const errorMerkleNoTxes = new TypeError( + 'Cannot compute merkle root for zero transactions', +); +const errorWitnessNotSegwit = new TypeError( + 'Cannot compute witness commit for non-segwit block', +); + +function txesHaveWitnessCommit(transactions: Array): boolean { + return ( + transactions instanceof Array && transactions[0] && transactions[0].ins && transactions[0].ins instanceof Array && @@ -19,255 +24,281 @@ function txesHaveWitnessCommit (transactions: Array): boolean { transactions[0].ins[0].witness && transactions[0].ins[0].witness instanceof Array && transactions[0].ins[0].witness.length > 0 + ); } -function anyTxHasWitness (transactions: Array): boolean { - return transactions instanceof Array && - transactions.some(tx => - typeof tx === 'object' && - tx.ins instanceof Array && - tx.ins.some(input => - typeof input === 'object' && - input.witness instanceof Array && - input.witness.length > 0 - ) +function anyTxHasWitness(transactions: Array): boolean { + return ( + transactions instanceof Array && + transactions.some( + tx => + typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some( + input => + typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0, + ), ) + ); } export class Block { - version: number - prevHash?: Buffer - merkleRoot?: Buffer - timestamp: number - witnessCommit?: Buffer - bits: number - nonce: number - transactions?: Array - - constructor () { - this.version = 1 - this.timestamp = 0 - this.bits = 0 - this.nonce = 0 - this.prevHash = undefined - this.merkleRoot = undefined - this.witnessCommit = undefined - this.transactions = undefined + version: number; + prevHash?: Buffer; + merkleRoot?: Buffer; + timestamp: number; + witnessCommit?: Buffer; + bits: number; + nonce: number; + transactions?: Array; + + constructor() { + this.version = 1; + this.timestamp = 0; + this.bits = 0; + this.nonce = 0; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.witnessCommit = undefined; + this.transactions = undefined; } - static fromBuffer (buffer: Buffer): Block { - if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)') + static fromBuffer(buffer: Buffer): Block { + if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); - let offset: number = 0 + let offset: number = 0; const readSlice = (n: number): Buffer => { - offset += n - return buffer.slice(offset - n, offset) - } + offset += n; + return buffer.slice(offset - n, offset); + }; const readUInt32 = (): number => { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i - } + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; + }; const readInt32 = (): number => { - const i = buffer.readInt32LE(offset) - offset += 4 - return i - } + const i = buffer.readInt32LE(offset); + offset += 4; + return i; + }; - const block = new Block() - block.version = readInt32() - block.prevHash = readSlice(32) - block.merkleRoot = readSlice(32) - block.timestamp = readUInt32() - block.bits = readUInt32() - block.nonce = readUInt32() + const block = new Block(); + block.version = readInt32(); + block.prevHash = readSlice(32); + block.merkleRoot = readSlice(32); + block.timestamp = readUInt32(); + block.bits = readUInt32(); + block.nonce = readUInt32(); - if (buffer.length === 80) return block + if (buffer.length === 80) return block; const readVarInt = (): number => { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi - } + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; + }; const readTransaction = (): any => { - const tx = Transaction.fromBuffer(buffer.slice(offset), true) - offset += tx.byteLength() - return tx - } + const tx = Transaction.fromBuffer(buffer.slice(offset), true); + offset += tx.byteLength(); + return tx; + }; - const nTransactions = readVarInt() - block.transactions = [] + const nTransactions = readVarInt(); + block.transactions = []; for (var i = 0; i < nTransactions; ++i) { - const tx = readTransaction() - block.transactions.push(tx) + const tx = readTransaction(); + block.transactions.push(tx); } - let witnessCommit = block.getWitnessCommit() + let witnessCommit = block.getWitnessCommit(); // This Block contains a witness commit - if (witnessCommit) block.witnessCommit = witnessCommit + if (witnessCommit) block.witnessCommit = witnessCommit; - return block + return block; } - static fromHex (hex: string): Block { - return Block.fromBuffer(Buffer.from(hex, 'hex')) + static fromHex(hex: string): Block { + return Block.fromBuffer(Buffer.from(hex, 'hex')); } - static calculateTarget (bits: number): Buffer { - const exponent = ((bits & 0xff000000) >> 24) - 3 - const mantissa = bits & 0x007fffff - const target = Buffer.alloc(32, 0) - target.writeUIntBE(mantissa, 29 - exponent, 3) - return target + static calculateTarget(bits: number): Buffer { + const exponent = ((bits & 0xff000000) >> 24) - 3; + const mantissa = bits & 0x007fffff; + const target = Buffer.alloc(32, 0); + target.writeUIntBE(mantissa, 29 - exponent, 3); + return target; } - static calculateMerkleRoot (transactions: Array, forWitness?: boolean): Buffer { - typeforce([{ getHash: types.Function }], transactions) - if (transactions.length === 0) throw errorMerkleNoTxes - if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit + static calculateMerkleRoot( + transactions: Array, + forWitness?: boolean, + ): Buffer { + typeforce([{ getHash: types.Function }], transactions); + if (transactions.length === 0) throw errorMerkleNoTxes; + if (forWitness && !txesHaveWitnessCommit(transactions)) + throw errorWitnessNotSegwit; - const hashes = transactions.map(transaction => transaction.getHash(forWitness!)) + const hashes = transactions.map(transaction => + transaction.getHash(forWitness!), + ); - const rootHash = fastMerkleRoot(hashes, bcrypto.hash256) + const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); return forWitness - ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) - : rootHash + ? bcrypto.hash256( + Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + ) + : rootHash; } - getWitnessCommit (): Buffer | null { - if (!txesHaveWitnessCommit(this.transactions!)) return null + getWitnessCommit(): Buffer | null { + if (!txesHaveWitnessCommit(this.transactions!)) return null; // The merkle root for the witness data is in an OP_RETURN output. // There is no rule for the index of the output, so use filter to find it. // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = this.transactions![0].outs - .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) - .map(out => out.script.slice(6, 38)) - if (witnessCommits.length === 0) return null + let witnessCommits = this.transactions![0].outs.filter(out => + out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + ).map(out => out.script.slice(6, 38)); + if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) - let result = witnessCommits[witnessCommits.length - 1] + let result = witnessCommits[witnessCommits.length - 1]; - if (!(result instanceof Buffer && result.length === 32)) return null - return result + if (!(result instanceof Buffer && result.length === 32)) return null; + return result; } - hasWitnessCommit (): boolean { - if (this.witnessCommit instanceof Buffer && - this.witnessCommit.length === 32) return true - if (this.getWitnessCommit() !== null) return true - return false + hasWitnessCommit(): boolean { + if ( + this.witnessCommit instanceof Buffer && + this.witnessCommit.length === 32 + ) + return true; + if (this.getWitnessCommit() !== null) return true; + return false; } - hasWitness (): boolean { - return anyTxHasWitness(this.transactions!) + hasWitness(): boolean { + return anyTxHasWitness(this.transactions!); } - byteLength (headersOnly: boolean): number { - if (headersOnly || !this.transactions) return 80 + byteLength(headersOnly: boolean): number { + if (headersOnly || !this.transactions) return 80; - return 80 + varuint.encodingLength(this.transactions.length) + + return ( + 80 + + varuint.encodingLength(this.transactions.length) + this.transactions.reduce((a, x) => a + x.byteLength(), 0) + ); } - getHash (): Buffer { - return bcrypto.hash256(this.toBuffer(true)) + getHash(): Buffer { + return bcrypto.hash256(this.toBuffer(true)); } - getId (): string { - return reverseBuffer(this.getHash()).toString('hex') + getId(): string { + return reverseBuffer(this.getHash()).toString('hex'); } - getUTCDate (): Date { - const date = new Date(0) // epoch - date.setUTCSeconds(this.timestamp) + getUTCDate(): Date { + const date = new Date(0); // epoch + date.setUTCSeconds(this.timestamp); - return date + return date; } // TODO: buffer, offset compatibility - toBuffer (headersOnly: boolean): Buffer { - const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)) + toBuffer(headersOnly: boolean): Buffer { + const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); - let offset: number = 0 + let offset: number = 0; const writeSlice = (slice: Buffer): void => { - slice.copy(buffer, offset) - offset += slice.length - } + slice.copy(buffer, offset); + offset += slice.length; + }; const writeInt32 = (i: number): void => { - buffer.writeInt32LE(i, offset) - offset += 4 - } + buffer.writeInt32LE(i, offset); + offset += 4; + }; const writeUInt32 = (i: number): void => { - buffer.writeUInt32LE(i, offset) - offset += 4 - } + buffer.writeUInt32LE(i, offset); + offset += 4; + }; - writeInt32(this.version) - writeSlice(this.prevHash!) - writeSlice(this.merkleRoot!) - writeUInt32(this.timestamp) - writeUInt32(this.bits) - writeUInt32(this.nonce) + writeInt32(this.version); + writeSlice(this.prevHash!); + writeSlice(this.merkleRoot!); + writeUInt32(this.timestamp); + writeUInt32(this.bits); + writeUInt32(this.nonce); - if (headersOnly || !this.transactions) return buffer + if (headersOnly || !this.transactions) return buffer; - varuint.encode(this.transactions.length, buffer, offset) - offset += varuint.encode.bytes + varuint.encode(this.transactions.length, buffer, offset); + offset += varuint.encode.bytes; this.transactions.forEach(tx => { - const txSize = tx.byteLength() // TODO: extract from toBuffer? - tx.toBuffer(buffer, offset) - offset += txSize - }) + const txSize = tx.byteLength(); // TODO: extract from toBuffer? + tx.toBuffer(buffer, offset); + offset += txSize; + }); - return buffer + return buffer; } - toHex (headersOnly: boolean): string { - return this.toBuffer(headersOnly).toString('hex') + toHex(headersOnly: boolean): string { + return this.toBuffer(headersOnly).toString('hex'); } - checkTxRoots (): boolean { + checkTxRoots(): boolean { // If the Block has segwit transactions but no witness commit, // there's no way it can be valid, so fail the check. - let hasWitnessCommit = this.hasWitnessCommit() - if (!hasWitnessCommit && this.hasWitness()) return false - return this.__checkMerkleRoot() && + let hasWitnessCommit = this.hasWitnessCommit(); + if (!hasWitnessCommit && this.hasWitness()) return false; + return ( + this.__checkMerkleRoot() && (hasWitnessCommit ? this.__checkWitnessCommit() : true) + ); } - checkMerkleRoot (): boolean { - console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + - 'deprecated in v5. Please use checkTxRoots instead.') - return this.checkTxRoots() + checkMerkleRoot(): boolean { + console.warn( + 'Deprecation Warning: Block method checkMerkleRoot will be ' + + 'deprecated in v5. Please use checkTxRoots instead.', + ); + return this.checkTxRoots(); } - __checkMerkleRoot (): boolean { - if (!this.transactions) throw errorMerkleNoTxes + __checkMerkleRoot(): boolean { + if (!this.transactions) throw errorMerkleNoTxes; - const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) - return this.merkleRoot!.compare(actualMerkleRoot) === 0 + const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); + return this.merkleRoot!.compare(actualMerkleRoot) === 0; } - __checkWitnessCommit (): boolean { - if (!this.transactions) throw errorMerkleNoTxes - if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit + __checkWitnessCommit(): boolean { + if (!this.transactions) throw errorMerkleNoTxes; + if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; - const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true) - return this.witnessCommit!.compare(actualWitnessCommit) === 0 + const actualWitnessCommit = Block.calculateMerkleRoot( + this.transactions, + true, + ); + return this.witnessCommit!.compare(actualWitnessCommit) === 0; } - checkProofOfWork (): boolean { - const hash: Buffer = reverseBuffer(this.getHash()) - const target = Block.calculateTarget(this.bits) + checkProofOfWork(): boolean { + const hash: Buffer = reverseBuffer(this.getHash()); + const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0 + return hash.compare(target) <= 0; } } diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index 3ef7492..adb6060 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -1,37 +1,44 @@ // https://github.com/feross/buffer/blob/master/index.js#L1127 -function verifuint (value: number, max: number): void { - if (typeof value !== 'number') throw new Error('cannot write a non-number as a number') - if (value < 0) throw new Error('specified a negative value for writing an unsigned value') - if (value > max) throw new Error('RangeError: value out of range') - if (Math.floor(value) !== value) throw new Error('value has a fractional component') +function verifuint(value: number, max: number): void { + if (typeof value !== 'number') + throw new Error('cannot write a non-number as a number'); + if (value < 0) + throw new Error('specified a negative value for writing an unsigned value'); + if (value > max) throw new Error('RangeError: value out of range'); + if (Math.floor(value) !== value) + throw new Error('value has a fractional component'); } -export function readUInt64LE (buffer: Buffer, offset: number): number { - const a = buffer.readUInt32LE(offset) - let b = buffer.readUInt32LE(offset + 4) - b *= 0x100000000 +export function readUInt64LE(buffer: Buffer, offset: number): number { + const a = buffer.readUInt32LE(offset); + let b = buffer.readUInt32LE(offset + 4); + b *= 0x100000000; - verifuint(b + a, 0x001fffffffffffff) - return b + a + verifuint(b + a, 0x001fffffffffffff); + return b + a; } -export function writeUInt64LE (buffer: Buffer, value: number, offset: number): number { - verifuint(value, 0x001fffffffffffff) +export function writeUInt64LE( + buffer: Buffer, + value: number, + offset: number, +): number { + verifuint(value, 0x001fffffffffffff); - buffer.writeInt32LE(value & -1, offset) - buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) - return offset + 8 + buffer.writeInt32LE(value & -1, offset); + buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); + return offset + 8; } -export function reverseBuffer (buffer: Buffer): Buffer { - if (buffer.length < 1) return buffer - let j = buffer.length - 1 - let tmp = 0 +export function reverseBuffer(buffer: Buffer): Buffer { + if (buffer.length < 1) return buffer; + let j = buffer.length - 1; + let tmp = 0; for (let i = 0; i < buffer.length / 2; i++) { - tmp = buffer[i] - buffer[i] = buffer[j] - buffer[j] = tmp - j-- + tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + j--; } - return buffer + return buffer; } diff --git a/ts_src/classify.ts b/ts_src/classify.ts index 9a5c849..0de93f9 100644 --- a/ts_src/classify.ts +++ b/ts_src/classify.ts @@ -1,65 +1,69 @@ -import { decompile } from './script' -import * as multisig from './templates/multisig' -import * as nullData from './templates/nulldata' -import * as pubKey from './templates/pubkey' -import * as pubKeyHash from './templates/pubkeyhash' -import * as scriptHash from './templates/scripthash' -import * as witnessPubKeyHash from './templates/witnesspubkeyhash' -import * as witnessScriptHash from './templates/witnessscripthash' -import * as witnessCommitment from './templates/witnesscommitment' +import { decompile } from './script'; +import * as multisig from './templates/multisig'; +import * as nullData from './templates/nulldata'; +import * as pubKey from './templates/pubkey'; +import * as pubKeyHash from './templates/pubkeyhash'; +import * as scriptHash from './templates/scripthash'; +import * as witnessPubKeyHash from './templates/witnesspubkeyhash'; +import * as witnessScriptHash from './templates/witnessscripthash'; +import * as witnessCommitment from './templates/witnesscommitment'; const types = { - P2MS: 'multisig', - NONSTANDARD: 'nonstandard', - NULLDATA: 'nulldata', - P2PK: 'pubkey', - P2PKH: 'pubkeyhash', - P2SH: 'scripthash', - P2WPKH: 'witnesspubkeyhash', - P2WSH: 'witnessscripthash', - WITNESS_COMMITMENT: 'witnesscommitment' -} + P2MS: 'multisig', + NONSTANDARD: 'nonstandard', + NULLDATA: 'nulldata', + P2PK: 'pubkey', + P2PKH: 'pubkeyhash', + P2SH: 'scripthash', + P2WPKH: 'witnesspubkeyhash', + P2WSH: 'witnessscripthash', + WITNESS_COMMITMENT: 'witnesscommitment', +}; -function classifyOutput (script: Buffer): string { - if (witnessPubKeyHash.output.check(script)) return types.P2WPKH - if (witnessScriptHash.output.check(script)) return types.P2WSH - if (pubKeyHash.output.check(script)) return types.P2PKH - if (scriptHash.output.check(script)) return types.P2SH +function classifyOutput(script: Buffer): string { + if (witnessPubKeyHash.output.check(script)) return types.P2WPKH; + if (witnessScriptHash.output.check(script)) return types.P2WSH; + if (pubKeyHash.output.check(script)) return types.P2PKH; + if (scriptHash.output.check(script)) return types.P2SH; // XXX: optimization, below functions .decompile before use - const chunks = decompile(script) - if (!chunks) throw new TypeError('Invalid script') + const chunks = decompile(script); + if (!chunks) throw new TypeError('Invalid script'); - if (multisig.output.check(chunks)) return types.P2MS - if (pubKey.output.check(chunks)) return types.P2PK - if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT - if (nullData.output.check(chunks)) return types.NULLDATA + if (multisig.output.check(chunks)) return types.P2MS; + if (pubKey.output.check(chunks)) return types.P2PK; + if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT; + if (nullData.output.check(chunks)) return types.NULLDATA; - return types.NONSTANDARD + return types.NONSTANDARD; } -function classifyInput (script: Buffer, allowIncomplete: boolean): string { +function classifyInput(script: Buffer, allowIncomplete: boolean): string { // XXX: optimization, below functions .decompile before use - const chunks = decompile(script) - if (!chunks) throw new TypeError('Invalid script') + const chunks = decompile(script); + if (!chunks) throw new TypeError('Invalid script'); - if (pubKeyHash.input.check(chunks)) return types.P2PKH - if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH - if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS - if (pubKey.input.check(chunks)) return types.P2PK + if (pubKeyHash.input.check(chunks)) return types.P2PKH; + if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH; + if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS; + if (pubKey.input.check(chunks)) return types.P2PK; - return types.NONSTANDARD + return types.NONSTANDARD; } -function classifyWitness (script: Array, allowIncomplete: boolean): string { +function classifyWitness( + script: Array, + allowIncomplete: boolean, +): string { // XXX: optimization, below functions .decompile before use - const chunks = decompile(script) - if (!chunks) throw new TypeError('Invalid script') + const chunks = decompile(script); + if (!chunks) throw new TypeError('Invalid script'); - if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH - if (witnessScriptHash.input.check(>chunks, allowIncomplete)) return types.P2WSH + if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH; + if (witnessScriptHash.input.check(>chunks, allowIncomplete)) + return types.P2WSH; - return types.NONSTANDARD + return types.NONSTANDARD; } export { @@ -67,4 +71,4 @@ export { classifyOutput as output, classifyWitness as witness, types, -} +}; diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts index 6aabb5b..6d92e60 100644 --- a/ts_src/crypto.ts +++ b/ts_src/crypto.ts @@ -1,21 +1,27 @@ -const createHash = require('create-hash') +const createHash = require('create-hash'); -export function ripemd160 (buffer: Buffer): Buffer { - return createHash('rmd160').update(buffer).digest() +export function ripemd160(buffer: Buffer): Buffer { + return createHash('rmd160') + .update(buffer) + .digest(); } -export function sha1 (buffer: Buffer): Buffer { - return createHash('sha1').update(buffer).digest() +export function sha1(buffer: Buffer): Buffer { + return createHash('sha1') + .update(buffer) + .digest(); } -export function sha256 (buffer: Buffer): Buffer { - return createHash('sha256').update(buffer).digest() +export function sha256(buffer: Buffer): Buffer { + return createHash('sha256') + .update(buffer) + .digest(); } -export function hash160 (buffer: Buffer): Buffer { - return ripemd160(sha256(buffer)) +export function hash160(buffer: Buffer): Buffer { + return ripemd160(sha256(buffer)); } -export function hash256 (buffer: Buffer): Buffer { - return sha256(sha256(buffer)) +export function hash256(buffer: Buffer): Buffer { + return sha256(sha256(buffer)); } diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index ad28adf..15ec00a 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -1,130 +1,132 @@ -import { Network } from './networks' -import * as NETWORKS from './networks' -import * as types from './types' -const ecc = require('tiny-secp256k1') -const randomBytes = require('randombytes') -const typeforce = require('typeforce') -const wif = require('wif') - -const isOptions = typeforce.maybe(typeforce.compile({ - compressed: types.maybe(types.Boolean), - network: types.maybe(types.Network) -})) +import { Network } from './networks'; +import * as NETWORKS from './networks'; +import * as types from './types'; +const ecc = require('tiny-secp256k1'); +const randomBytes = require('randombytes'); +const typeforce = require('typeforce'); +const wif = require('wif'); + +const isOptions = typeforce.maybe( + typeforce.compile({ + compressed: types.maybe(types.Boolean), + network: types.maybe(types.Network), + }), +); interface ECPairOptions { - compressed?: boolean - network?: Network - rng?(arg0: Buffer): Buffer + compressed?: boolean; + network?: Network; + rng?(arg0: Buffer): Buffer; } export interface ECPairInterface { - compressed: boolean - network: Network - privateKey?: Buffer - publicKey?: Buffer - toWIF(): string - sign(hash: Buffer): Buffer - verify(hash: Buffer, signature: Buffer): Buffer - getPublicKey?(): Buffer + compressed: boolean; + network: Network; + privateKey?: Buffer; + publicKey?: Buffer; + toWIF(): string; + sign(hash: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): Buffer; + getPublicKey?(): Buffer; } class ECPair implements ECPairInterface { - compressed: boolean - network: Network - private __d?: Buffer - private __Q?: Buffer - - constructor (d?: Buffer, Q?: Buffer, options?: ECPairOptions) { - if (options === undefined) options = {} - this.compressed = options.compressed === undefined ? true : options.compressed - this.network = options.network || NETWORKS.bitcoin - - this.__d = undefined - this.__Q = undefined - if (d !== undefined) this.__d = d - if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed) + compressed: boolean; + network: Network; + private __d?: Buffer; + private __Q?: Buffer; + + constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions) { + if (options === undefined) options = {}; + this.compressed = + options.compressed === undefined ? true : options.compressed; + this.network = options.network || NETWORKS.bitcoin; + + this.__d = undefined; + this.__Q = undefined; + if (d !== undefined) this.__d = d; + if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed); } - get privateKey (): Buffer | undefined { - return this.__d + get privateKey(): Buffer | undefined { + return this.__d; } - get publicKey (): Buffer | undefined { - if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed) - return this.__Q + get publicKey(): Buffer | undefined { + if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed); + return this.__Q; } - toWIF (): string { - if (!this.__d) throw new Error('Missing private key') - return wif.encode(this.network.wif, this.__d, this.compressed) + toWIF(): string { + if (!this.__d) throw new Error('Missing private key'); + return wif.encode(this.network.wif, this.__d, this.compressed); } - sign (hash: Buffer): Buffer { - if (!this.__d) throw new Error('Missing private key') - return ecc.sign(hash, this.__d) + sign(hash: Buffer): Buffer { + if (!this.__d) throw new Error('Missing private key'); + return ecc.sign(hash, this.__d); } - verify (hash: Buffer, signature: Buffer): Buffer { - return ecc.verify(hash, this.publicKey, signature) + verify(hash: Buffer, signature: Buffer): Buffer { + return ecc.verify(hash, this.publicKey, signature); } } -function fromPrivateKey (buffer: Buffer, options?: ECPairOptions): ECPair { - typeforce(types.Buffer256bit, buffer) - if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)') - typeforce(isOptions, options) +function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair { + typeforce(types.Buffer256bit, buffer); + if (!ecc.isPrivate(buffer)) + throw new TypeError('Private key not in range [1, n)'); + typeforce(isOptions, options); - return new ECPair(buffer, undefined, options) + return new ECPair(buffer, undefined, options); } -function fromPublicKey (buffer: Buffer, options?: ECPairOptions): ECPair { - typeforce(ecc.isPoint, buffer) - typeforce(isOptions, options) - return new ECPair(undefined, buffer, options) +function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair { + typeforce(ecc.isPoint, buffer); + typeforce(isOptions, options); + return new ECPair(undefined, buffer, options); } -function fromWIF (string: string, network?: Network | Array): ECPair { - const decoded = wif.decode(string) - const version = decoded.version +function fromWIF(string: string, network?: Network | Array): ECPair { + const decoded = wif.decode(string); + const version = decoded.version; // list of networks? if (types.Array(network)) { - network = (>network).filter(function (x: Network) { - return version === x.wif - }).pop() + network = (>network) + .filter(function(x: Network) { + return version === x.wif; + }) + .pop(); - if (!network) throw new Error('Unknown network version') + if (!network) throw new Error('Unknown network version'); - // otherwise, assume a network object (or default to bitcoin) + // otherwise, assume a network object (or default to bitcoin) } else { - network = network || NETWORKS.bitcoin + network = network || NETWORKS.bitcoin; - if (version !== (network).wif) throw new Error('Invalid network version') + if (version !== (network).wif) + throw new Error('Invalid network version'); } return fromPrivateKey(decoded.privateKey, { compressed: decoded.compressed, - network: network - }) + network: network, + }); } -function makeRandom (options?: ECPairOptions): ECPair { - typeforce(isOptions, options) - if (options === undefined) options = {} - const rng = options.rng || randomBytes +function makeRandom(options?: ECPairOptions): ECPair { + typeforce(isOptions, options); + if (options === undefined) options = {}; + const rng = options.rng || randomBytes; - let d + let d; do { - d = rng(32) - typeforce(types.Buffer256bit, d) - } while (!ecc.isPrivate(d)) + d = rng(32); + typeforce(types.Buffer256bit, d); + } while (!ecc.isPrivate(d)); - return fromPrivateKey(d, options) + return fromPrivateKey(d, options); } -export { - makeRandom, - fromPrivateKey, - fromPublicKey, - fromWIF -} +export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF }; diff --git a/ts_src/index.ts b/ts_src/index.ts index 7574048..fce7304 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -1,28 +1,20 @@ -import * as bip32 from 'bip32' -import * as ECPair from './ecpair' -import * as address from './address' -import * as crypto from './crypto' -import * as networks from './networks' -import * as payments from './payments' -import * as script from './script' +import * as bip32 from 'bip32'; +import * as ECPair from './ecpair'; +import * as address from './address'; +import * as crypto from './crypto'; +import * as networks from './networks'; +import * as payments from './payments'; +import * as script from './script'; -export { - ECPair, - address, - bip32, - crypto, - networks, - payments, - script, -} +export { ECPair, address, bip32, crypto, networks, payments, script }; -export { Block } from './block' -export { Transaction } from './transaction' -export { TransactionBuilder } from './transaction_builder' -export { OPS as opcodes } from './script' +export { Block } from './block'; +export { Transaction } from './transaction'; +export { TransactionBuilder } from './transaction_builder'; +export { OPS as opcodes } from './script'; -export { Payment, PaymentOpts } from './payments' -export { Input as TxInput, Output as TxOutput } from './transaction' -export { Network } from './networks' -export { OpCode } from './script' -export { BIP32Interface } from 'bip32' +export { Payment, PaymentOpts } from './payments'; +export { Input as TxInput, Output as TxOutput } from './transaction'; +export { Network } from './networks'; +export { OpCode } from './script'; +export { BIP32Interface } from 'bip32'; diff --git a/ts_src/networks.ts b/ts_src/networks.ts index 11147af..0212a44 100644 --- a/ts_src/networks.ts +++ b/ts_src/networks.ts @@ -7,43 +7,43 @@ export type Network = { pubKeyHash: number; scriptHash: number; wif: number; -} +}; type bip32 = { public: number; private: number; -} +}; export const bitcoin: Network = { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'bc', bip32: { public: 0x0488b21e, - private: 0x0488ade4 + private: 0x0488ade4, }, pubKeyHash: 0x00, scriptHash: 0x05, - wif: 0x80 -} + wif: 0x80, +}; export const regtest: Network = { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'bcrt', bip32: { public: 0x043587cf, - private: 0x04358394 + private: 0x04358394, }, pubKeyHash: 0x6f, scriptHash: 0xc4, - wif: 0xef -} + wif: 0xef, +}; export const testnet: Network = { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'tb', bip32: { public: 0x043587cf, - private: 0x04358394 + private: 0x04358394, }, pubKeyHash: 0x6f, scriptHash: 0xc4, - wif: 0xef -} + wif: 0xef, +}; diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index bfaeb8b..f7225a7 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -1,54 +1,59 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import * as bscript from '../script' -import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' -const typef = require('typeforce') -const OPS = bscript.OPS - -function stacksEqual (a: Array, b: Array): boolean { - if (a.length !== b.length) return false - - return a.every(function (x, i) { - return x.equals(b[i]) - }) +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import * as bscript from '../script'; +import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +const typef = require('typeforce'); +const OPS = bscript.OPS; + +function stacksEqual(a: Array, b: Array): boolean { + if (a.length !== b.length) return false; + + return a.every(function(x, i) { + return x.equals(b[i]); + }); } // output: OP_RETURN ... -export function p2data (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.data && - !a.output - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - typef({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - data: typef.maybe(typef.arrayOf(typef.Buffer)) - }, a) - - const network = a.network || BITCOIN_NETWORK - const o = { network } - - lazy.prop(o, 'output', function () { - if (!a.data) return - return bscript.compile((>[OPS.OP_RETURN]).concat(a.data)) - }) - lazy.prop(o, 'data', function () { - if (!a.output) return - return bscript.decompile(a.output)!.slice(1) - }) +export function p2data(a: Payment, opts?: PaymentOpts): Payment { + if (!a.data && !a.output) throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + typef( + { + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + data: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + + const network = a.network || BITCOIN_NETWORK; + const o = { network }; + + lazy.prop(o, 'output', function() { + if (!a.data) return; + return bscript.compile( + (>[OPS.OP_RETURN]).concat(a.data), + ); + }); + lazy.prop(o, 'data', function() { + if (!a.output) return; + return bscript.decompile(a.output)!.slice(1); + }); // extended validation if (opts.validate) { if (a.output) { - const chunks = bscript.decompile(a.output) - if (chunks![0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid') - if (!chunks!.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid') - - if (a.data && !stacksEqual(a.data, >o.data)) throw new TypeError('Data mismatch') + const chunks = bscript.decompile(a.output); + if (chunks![0] !== OPS.OP_RETURN) + throw new TypeError('Output is invalid'); + if (!chunks!.slice(1).every(typef.Buffer)) + throw new TypeError('Output is invalid'); + + if (a.data && !stacksEqual(a.data, >o.data)) + throw new TypeError('Data mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 7fc72d8..9791661 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -1,35 +1,35 @@ -import { Network } from '../networks' // eslint-disable-line -import { p2data as embed } from './embed' -import { p2ms } from './p2ms' -import { p2pk } from './p2pk' -import { p2pkh } from './p2pkh' -import { p2sh } from './p2sh' -import { p2wpkh } from './p2wpkh' -import { p2wsh } from './p2wsh' +import { Network } from '../networks'; // eslint-disable-line +import { p2data as embed } from './embed'; +import { p2ms } from './p2ms'; +import { p2pk } from './p2pk'; +import { p2pkh } from './p2pkh'; +import { p2sh } from './p2sh'; +import { p2wpkh } from './p2wpkh'; +import { p2wsh } from './p2wsh'; export interface Payment { - network?: Network, - output?: Buffer, - data?: Array, - m?: number, - n?: number, - pubkeys?: Array, - input?: Buffer, - signatures?: Array, - pubkey?: Buffer, - signature?: Buffer, - address?: string, - hash?: Buffer, - redeem?: Payment, - witness?: Array, + network?: Network; + output?: Buffer; + data?: Array; + m?: number; + n?: number; + pubkeys?: Array; + input?: Buffer; + signatures?: Array; + pubkey?: Buffer; + signature?: Buffer; + address?: string; + hash?: Buffer; + redeem?: Payment; + witness?: Array; } export interface PaymentOpts { - validate?: boolean, - allowIncomplete?: boolean, + validate?: boolean; + allowIncomplete?: boolean; } -export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh } +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; // TODO // witness commitment diff --git a/ts_src/payments/lazy.ts b/ts_src/payments/lazy.ts index a6f0951..474c8e9 100644 --- a/ts_src/payments/lazy.ts +++ b/ts_src/payments/lazy.ts @@ -1,28 +1,28 @@ -export function prop (object: Object, name: string, f: ()=>any): void { +export function prop(object: Object, name: string, f: () => any): void { Object.defineProperty(object, name, { configurable: true, enumerable: true, - get: function () { - let value = f.call(this) - this[name] = value - return value + get: function() { + let value = f.call(this); + this[name] = value; + return value; }, - set: function (value) { + set: function(value) { Object.defineProperty(this, name, { configurable: true, enumerable: true, value: value, - writable: true - }) - } - }) + writable: true, + }); + }, + }); } -export function value (f: ()=>T): ()=>T { - let value: T - return function (): T { - if (value !== undefined) return value - value = f() - return value - } +export function value(f: () => T): () => T { + let value: T; + return function(): T { + if (value !== undefined) return value; + value = f(); + return value; + }; } diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index 34e2d31..fce7616 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -1,141 +1,165 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import * as bscript from '../script' -import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' -const OPS = bscript.OPS -const typef = require('typeforce') -const ecc = require('tiny-secp256k1') - -const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 - -function stacksEqual (a: Array, b: Array): boolean { - if (a.length !== b.length) return false - - return a.every(function (x, i) { - return x.equals(b[i]) - }) +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import * as bscript from '../script'; +import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +const OPS = bscript.OPS; +const typef = require('typeforce'); +const ecc = require('tiny-secp256k1'); + +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 + +function stacksEqual(a: Array, b: Array): boolean { + if (a.length !== b.length) return false; + + return a.every(function(x, i) { + return x.equals(b[i]); + }); } // input: OP_0 [signatures ...] // output: m [pubKeys ...] n OP_CHECKMULTISIG -export function p2ms (a: Payment, opts?: PaymentOpts): Payment { +export function p2ms(a: Payment, opts?: PaymentOpts): Payment { if ( !a.input && !a.output && !(a.pubkeys && a.m !== undefined) && !a.signatures - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - function isAcceptableSignature (x: Buffer | number) { - return bscript.isCanonicalScriptSignature(x) || - (opts!.allowIncomplete && - ( x === OPS.OP_0)) !== undefined // eslint-disable-line + ) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + function isAcceptableSignature(x: Buffer | number) { + return ( + bscript.isCanonicalScriptSignature(x) || + (opts!.allowIncomplete && x === OPS.OP_0) !== undefined + ); // eslint-disable-line } - typef({ - network: typef.maybe(typef.Object), - m: typef.maybe(typef.Number), - n: typef.maybe(typef.Number), - output: typef.maybe(typef.Buffer), - pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), - - signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - input: typef.maybe(typef.Buffer) - }, a) - - const network = a.network || BITCOIN_NETWORK - const o: Payment = { network } - - let chunks: Array = [] - let decoded = false - function decode (output: Buffer | Array): void { - if (decoded) return - decoded = true - chunks = >bscript.decompile(output) - o.m = chunks[0] - OP_INT_BASE // eslint-disable-line - o.n = chunks[chunks.length - 2] - OP_INT_BASE // eslint-disable-line - o.pubkeys = >chunks.slice(1, -2) + typef( + { + network: typef.maybe(typef.Object), + m: typef.maybe(typef.Number), + n: typef.maybe(typef.Number), + output: typef.maybe(typef.Buffer), + pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), + + signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + input: typef.maybe(typef.Buffer), + }, + a, + ); + + const network = a.network || BITCOIN_NETWORK; + const o: Payment = { network }; + + let chunks: Array = []; + let decoded = false; + function decode(output: Buffer | Array): void { + if (decoded) return; + decoded = true; + chunks = >bscript.decompile(output); + o.m = chunks[0] - OP_INT_BASE; // eslint-disable-line + o.n = chunks[chunks.length - 2] - OP_INT_BASE; // eslint-disable-line + o.pubkeys = >chunks.slice(1, -2); } - lazy.prop(o, 'output', function () { - if (!a.m) return - if (!o.n) return - if (!a.pubkeys) return - return bscript.compile((>[]).concat( - OP_INT_BASE + a.m, - a.pubkeys, - OP_INT_BASE + o.n, - OPS.OP_CHECKMULTISIG - )) - }) - lazy.prop(o, 'm', function () { - if (!o.output) return - decode(o.output) - return o.m - }) - lazy.prop(o, 'n', function () { - if (!o.pubkeys) return - return o.pubkeys.length - }) - lazy.prop(o, 'pubkeys', function () { - if (!a.output) return - decode(a.output) - return o.pubkeys - }) - lazy.prop(o, 'signatures', function () { - if (!a.input) return - return bscript.decompile(a.input)!.slice(1) - }) - lazy.prop(o, 'input', function () { - if (!a.signatures) return - return bscript.compile((>[OPS.OP_0]).concat(a.signatures)) - }) - lazy.prop(o, 'witness', function () { - if (!o.input) return - return [] - }) + lazy.prop(o, 'output', function() { + if (!a.m) return; + if (!o.n) return; + if (!a.pubkeys) return; + return bscript.compile( + (>[]).concat( + OP_INT_BASE + a.m, + a.pubkeys, + OP_INT_BASE + o.n, + OPS.OP_CHECKMULTISIG, + ), + ); + }); + lazy.prop(o, 'm', function() { + if (!o.output) return; + decode(o.output); + return o.m; + }); + lazy.prop(o, 'n', function() { + if (!o.pubkeys) return; + return o.pubkeys.length; + }); + lazy.prop(o, 'pubkeys', function() { + if (!a.output) return; + decode(a.output); + return o.pubkeys; + }); + lazy.prop(o, 'signatures', function() { + if (!a.input) return; + return bscript.decompile(a.input)!.slice(1); + }); + lazy.prop(o, 'input', function() { + if (!a.signatures) return; + return bscript.compile( + (>[OPS.OP_0]).concat(a.signatures), + ); + }); + lazy.prop(o, 'witness', function() { + if (!o.input) return; + return []; + }); // extended validation if (opts.validate) { if (a.output) { - decode(a.output) - if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid') - if (!typef.Number(chunks[chunks.length - 2])) throw new TypeError('Output is invalid') - if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid') + decode(a.output); + if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + if (!typef.Number(chunks[chunks.length - 2])) + throw new TypeError('Output is invalid'); + if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) + throw new TypeError('Output is invalid'); if ( o.m! <= 0 || // eslint-disable-line o.n! > 16 || // eslint-disable-line o.m! > o.n! || // eslint-disable-line - o.n !== chunks.length - 3) throw new TypeError('Output is invalid') - if (!o.pubkeys!.every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid') - - if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch') - if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch') - if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys!)) throw new TypeError('Pubkeys mismatch') + o.n !== chunks.length - 3 + ) + throw new TypeError('Output is invalid'); + if (!o.pubkeys!.every(x => ecc.isPoint(x))) + throw new TypeError('Output is invalid'); + + if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); + if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); + if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys!)) + throw new TypeError('Pubkeys mismatch'); } if (a.pubkeys) { - if (a.n !== undefined && a.n !== a.pubkeys.length) throw new TypeError('Pubkey count mismatch') - o.n = a.pubkeys.length + if (a.n !== undefined && a.n !== a.pubkeys.length) + throw new TypeError('Pubkey count mismatch'); + o.n = a.pubkeys.length; - if (o.n < o.m!) throw new TypeError('Pubkey count cannot be less than m') + if (o.n < o.m!) throw new TypeError('Pubkey count cannot be less than m'); } if (a.signatures) { - if (a.signatures.length < o.m!) throw new TypeError('Not enough signatures provided') - if (a.signatures.length > o.m!) throw new TypeError('Too many signatures provided') + if (a.signatures.length < o.m!) + throw new TypeError('Not enough signatures provided'); + if (a.signatures.length > o.m!) + throw new TypeError('Too many signatures provided'); } if (a.input) { - if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid') - if (o.signatures!.length === 0 || !o.signatures!.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)') - - if (a.signatures && !stacksEqual(a.signatures, o.signatures!)) throw new TypeError('Signature mismatch') - if (a.m !== undefined && a.m !== a.signatures!.length) throw new TypeError('Signature count mismatch') + if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); + if ( + o.signatures!.length === 0 || + !o.signatures!.every(isAcceptableSignature) + ) + throw new TypeError('Input has invalid signature(s)'); + + if (a.signatures && !stacksEqual(a.signatures, o.signatures!)) + throw new TypeError('Signature mismatch'); + if (a.m !== undefined && a.m !== a.signatures!.length) + throw new TypeError('Signature count mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index 3385c56..e17a8f2 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -1,78 +1,80 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import * as bscript from '../script' -import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' -const typef = require('typeforce') -const OPS = bscript.OPS -const ecc = require('tiny-secp256k1') +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import * as bscript from '../script'; +import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); // input: {signature} // output: {pubKey} OP_CHECKSIG -export function p2pk (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.input && - !a.output && - !a.pubkey && - !a.input && - !a.signature - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) +export function p2pk(a: Payment, opts?: PaymentOpts): Payment { + if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); - typef({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - pubkey: typef.maybe(ecc.isPoint), + typef( + { + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer) - }, a) + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), + }, + a, + ); - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) + const _chunks = <() => Array>lazy.value(function() { + return bscript.decompile(a.input!); + }); - const network = a.network || BITCOIN_NETWORK - const o: Payment = { network } + const network = a.network || BITCOIN_NETWORK; + const o: Payment = { network }; - lazy.prop(o, 'output', function () { - if (!a.pubkey) return - return bscript.compile([ - a.pubkey, - OPS.OP_CHECKSIG - ]) - }) - lazy.prop(o, 'pubkey', function () { - if (!a.output) return - return a.output.slice(1, -1) - }) - lazy.prop(o, 'signature', function () { - if (!a.input) return - return _chunks()[0] - }) - lazy.prop(o, 'input', function () { - if (!a.signature) return - return bscript.compile([a.signature]) - }) - lazy.prop(o, 'witness', function () { - if (!o.input) return - return [] - }) + lazy.prop(o, 'output', function() { + if (!a.pubkey) return; + return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); + }); + lazy.prop(o, 'pubkey', function() { + if (!a.output) return; + return a.output.slice(1, -1); + }); + lazy.prop(o, 'signature', function() { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', function() { + if (!a.signature) return; + return bscript.compile([a.signature]); + }); + lazy.prop(o, 'witness', function() { + if (!o.input) return; + return []; + }); // extended validation if (opts.validate) { if (a.output) { - if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') - if (!ecc.isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid') - if (a.pubkey && !a.pubkey.equals(o.pubkey!)) throw new TypeError('Pubkey mismatch') + if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) + throw new TypeError('Output is invalid'); + if (!ecc.isPoint(o.pubkey)) + throw new TypeError('Output pubkey is invalid'); + if (a.pubkey && !a.pubkey.equals(o.pubkey!)) + throw new TypeError('Pubkey mismatch'); } if (a.signature) { - if (a.input && !a.input.equals(o.input!)) throw new TypeError('Signature mismatch') + if (a.input && !a.input.equals(o.input!)) + throw new TypeError('Signature mismatch'); } if (a.input) { - if (_chunks().length !== 1) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(o.signature!)) throw new TypeError('Input has invalid signature') + if (_chunks().length !== 1) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(o.signature!)) + throw new TypeError('Input has invalid signature'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index ddb9cc3..ccac25d 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -1,101 +1,103 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import * as bscript from '../script' -import * as bcrypto from '../crypto' -import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' -const typef = require('typeforce') -const OPS = bscript.OPS -const ecc = require('tiny-secp256k1') +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import * as bscript from '../script'; +import * as bcrypto from '../crypto'; +import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); -const bs58check = require('bs58check') +const bs58check = require('bs58check'); // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG -export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.address && - !a.hash && - !a.output && - !a.pubkey && - !a.input - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - typef({ - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(25)), - - pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer) - }, a) - - const _address = lazy.value(function () { - const payload = bs58check.decode(a.address) - const version = payload.readUInt8(0) - const hash = payload.slice(1) - return { version, hash } - }) - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) - - const network = a.network || BITCOIN_NETWORK - const o: Payment = { network } - - lazy.prop(o, 'address', function () { - if (!o.hash) return - - const payload = Buffer.allocUnsafe(21) - payload.writeUInt8(network.pubKeyHash, 0) - o.hash.copy(payload, 1) - return bs58check.encode(payload) - }) - lazy.prop(o, 'hash', function () { - if (a.output) return a.output.slice(3, 23) - if (a.address) return _address().hash - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!) - }) - lazy.prop(o, 'output', function () { - if (!o.hash) return +export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(25)), + + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), + }, + a, + ); + + const _address = lazy.value(function() { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = <() => Array>lazy.value(function() { + return bscript.decompile(a.input!); + }); + + const network = a.network || BITCOIN_NETWORK; + const o: Payment = { network }; + + lazy.prop(o, 'address', function() { + if (!o.hash) return; + + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(network.pubKeyHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', function() { + if (a.output) return a.output.slice(3, 23); + if (a.address) return _address().hash; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!); + }); + lazy.prop(o, 'output', function() { + if (!o.hash) return; return bscript.compile([ OPS.OP_DUP, OPS.OP_HASH160, o.hash, OPS.OP_EQUALVERIFY, - OPS.OP_CHECKSIG - ]) - }) - lazy.prop(o, 'pubkey', function () { - if (!a.input) return - return _chunks()[1] - }) - lazy.prop(o, 'signature', function () { - if (!a.input) return - return _chunks()[0] - }) - lazy.prop(o, 'input', function () { - if (!a.pubkey) return - if (!a.signature) return - return bscript.compile([a.signature, a.pubkey]) - }) - lazy.prop(o, 'witness', function () { - if (!o.input) return - return [] - }) + OPS.OP_CHECKSIG, + ]); + }); + lazy.prop(o, 'pubkey', function() { + if (!a.input) return; + return _chunks()[1]; + }); + lazy.prop(o, 'signature', function() { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', function() { + if (!a.pubkey) return; + if (!a.signature) return; + return bscript.compile([a.signature, a.pubkey]); + }); + lazy.prop(o, 'witness', function() { + if (!o.input) return; + return []; + }); // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]) + let hash: Buffer = Buffer.from([]); if (a.address) { - if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch') - if (_address().hash.length !== 20) throw new TypeError('Invalid address') - hash = _address().hash + if (_address().version !== network.pubKeyHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') - else hash = a.hash + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; } if (a.output) { @@ -105,32 +107,41 @@ export function p2pkh (a: Payment, opts?: PaymentOpts): Payment { a.output[1] !== OPS.OP_HASH160 || a.output[2] !== 0x14 || a.output[23] !== OPS.OP_EQUALVERIFY || - a.output[24] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid') - - const hash2 = a.output.slice(3, 23) - if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') - else hash = hash2 + a.output[24] !== OPS.OP_CHECKSIG + ) + throw new TypeError('Output is invalid'); + + const hash2 = a.output.slice(3, 23); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; } if (a.pubkey) { - const pkh = bcrypto.hash160(a.pubkey) - if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') - else hash = pkh + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; } if (a.input) { - const chunks = _chunks() - if (chunks.length !== 2) throw new TypeError('Input is invalid') - if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature') - if (!ecc.isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey') - - if (a.signature && !a.signature.equals(chunks[0])) throw new TypeError('Signature mismatch') - if (a.pubkey && !a.pubkey.equals(chunks[1])) throw new TypeError('Pubkey mismatch') - - const pkh = bcrypto.hash160(chunks[1]) - if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + const chunks = _chunks(); + if (chunks.length !== 2) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(chunks[0])) + throw new TypeError('Input has invalid signature'); + if (!ecc.isPoint(chunks[1])) + throw new TypeError('Input has invalid pubkey'); + + if (a.signature && !a.signature.equals(chunks[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(chunks[1])) + throw new TypeError('Pubkey mismatch'); + + const pkh = bcrypto.hash160(chunks[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index daaa8cc..281e3df 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -19,109 +19,109 @@ function stacksEqual (a: Array, b: Array): boolean { // input: [redeemScriptSig ...] {redeemScript} // witness: // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL -export function p2sh (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.address && - !a.hash && - !a.output && - !a.redeem && - !a.input - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - typef({ - network: typef.maybe(typef.Object), - - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(23)), - - redeem: typef.maybe({ +export function p2sh(a: Payment, opts?: PaymentOpts): Payment { + if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + typef( + { network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), + + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(23)), + + redeem: typef.maybe({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }), input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) - }), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) - }, a) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); - let network = a.network + let network = a.network; if (!network) { - network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK; } - const o: Payment = { network } - - const _address = lazy.value(function () { - const payload = bs58check.decode(a.address) - const version = payload.readUInt8(0) - const hash = payload.slice(1) - return { version, hash } - }) - const _chunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.input!) }) - const _redeem = lazy.value(function (): Payment { - const chunks = _chunks() + const o: Payment = { network }; + + const _address = lazy.value(function() { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = <() => Array>lazy.value(function() { + return bscript.decompile(a.input!); + }); + const _redeem = lazy.value(function(): Payment { + const chunks = _chunks(); return { network, output: chunks[chunks.length - 1], input: bscript.compile(chunks.slice(0, -1)), - witness: a.witness || [] - } - }) + witness: a.witness || [], + }; + }); // output dependents - lazy.prop(o, 'address', function () { - if (!o.hash) return - - const payload = Buffer.allocUnsafe(21) - payload.writeUInt8(o.network!.scriptHash, 0) - o.hash.copy(payload, 1) - return bs58check.encode(payload) - }) - lazy.prop(o, 'hash', function () { + lazy.prop(o, 'address', function() { + if (!o.hash) return; + + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(o.network!.scriptHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', function() { // in order of least effort - if (a.output) return a.output.slice(2, 22) - if (a.address) return _address().hash - if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output) - }) - lazy.prop(o, 'output', function () { - if (!o.hash) return - return bscript.compile([ - OPS.OP_HASH160, - o.hash, - OPS.OP_EQUAL - ]) - }) + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().hash; + if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); + }); + lazy.prop(o, 'output', function() { + if (!o.hash) return; + return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); + }); // input dependents - lazy.prop(o, 'redeem', function () { - if (!a.input) return - return _redeem() - }) - lazy.prop(o, 'input', function () { - if (!a.redeem || !a.redeem.input || !a.redeem.output) return - return bscript.compile((>[]).concat( - >bscript.decompile(a.redeem.input), - a.redeem.output - )) - }) - lazy.prop(o, 'witness', function () { - if (o.redeem && o.redeem.witness) return o.redeem.witness - if (o.input) return [] - }) + lazy.prop(o, 'redeem', function() { + if (!a.input) return; + return _redeem(); + }); + lazy.prop(o, 'input', function() { + if (!a.redeem || !a.redeem.input || !a.redeem.output) return; + return bscript.compile( + (>[]).concat( + >bscript.decompile(a.redeem.input), + a.redeem.output, + ), + ); + }); + lazy.prop(o, 'witness', function() { + if (o.redeem && o.redeem.witness) return o.redeem.witness; + if (o.input) return []; + }); if (opts.validate) { - let hash: Buffer = Buffer.from([]) + let hash: Buffer = Buffer.from([]); if (a.address) { - if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch') - if (_address().hash.length !== 20) throw new TypeError('Invalid address') - hash = _address().hash + if (_address().version !== network.scriptHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') - else hash = a.hash + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; } if (a.output) { @@ -129,64 +129,79 @@ export function p2sh (a: Payment, opts?: PaymentOpts): Payment { a.output.length !== 23 || a.output[0] !== OPS.OP_HASH160 || a.output[1] !== 0x14 || - a.output[22] !== OPS.OP_EQUAL) throw new TypeError('Output is invalid') - - const hash2 = a.output.slice(2, 22) - if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') - else hash = hash2 + a.output[22] !== OPS.OP_EQUAL + ) + throw new TypeError('Output is invalid'); + + const hash2 = a.output.slice(2, 22); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; } // inlined to prevent 'no-inner-declarations' failing - const checkRedeem = function (redeem: Payment): void { + const checkRedeem = function(redeem: Payment): void { // is the redeem output empty/invalid? if (redeem.output) { - const decompile = bscript.decompile(redeem.output) - if (!decompile || decompile.length < 1) throw new TypeError('Redeem.output too short') + const decompile = bscript.decompile(redeem.output); + if (!decompile || decompile.length < 1) + throw new TypeError('Redeem.output too short'); // match hash against other sources - const hash2 = bcrypto.hash160(redeem.output) - if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') - else hash = hash2 + const hash2 = bcrypto.hash160(redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; } if (redeem.input) { - const hasInput = redeem.input.length > 0 - const hasWitness = redeem.witness && redeem.witness.length > 0 - if (!hasInput && !hasWitness) throw new TypeError('Empty input') - if (hasInput && hasWitness) throw new TypeError('Input and witness provided') + const hasInput = redeem.input.length > 0; + const hasWitness = redeem.witness && redeem.witness.length > 0; + if (!hasInput && !hasWitness) throw new TypeError('Empty input'); + if (hasInput && hasWitness) + throw new TypeError('Input and witness provided'); if (hasInput) { - const richunks = >bscript.decompile(redeem.input) - if (!bscript.isPushOnly(richunks)) throw new TypeError('Non push-only scriptSig') + const richunks = >( + bscript.decompile(redeem.input) + ); + if (!bscript.isPushOnly(richunks)) + throw new TypeError('Non push-only scriptSig'); } } - } + }; if (a.input) { - const chunks = _chunks() - if (!chunks || chunks.length < 1) throw new TypeError('Input too short') - if (!Buffer.isBuffer(_redeem().output)) throw new TypeError('Input is invalid') + const chunks = _chunks(); + if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); + if (!Buffer.isBuffer(_redeem().output)) + throw new TypeError('Input is invalid'); - checkRedeem(_redeem()) + checkRedeem(_redeem()); } if (a.redeem) { - if (a.redeem.network && a.redeem.network !== network) throw new TypeError('Network mismatch') + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); if (a.input) { - const redeem = _redeem() - if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) throw new TypeError('Redeem.output mismatch') - if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) throw new TypeError('Redeem.input mismatch') + const redeem = _redeem(); + if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) + throw new TypeError('Redeem.output mismatch'); + if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) + throw new TypeError('Redeem.input mismatch'); } - checkRedeem(a.redeem) + checkRedeem(a.redeem); } if (a.witness) { if ( a.redeem && a.redeem.witness && - !stacksEqual(a.redeem.witness, a.witness)) throw new TypeError('Witness and redeem.witness mismatch') + !stacksEqual(a.redeem.witness, a.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index 6cfecc4..ec7ed40 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -1,134 +1,142 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import * as bscript from '../script' -import * as bcrypto from '../crypto' -import * as lazy from './lazy' -import { bitcoin as BITCOIN_NETWORK } from '../networks' -const typef = require('typeforce') -const OPS = bscript.OPS -const ecc = require('tiny-secp256k1') +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import * as bscript from '../script'; +import * as bcrypto from '../crypto'; +import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +const typef = require('typeforce'); +const OPS = bscript.OPS; +const ecc = require('tiny-secp256k1'); -const bech32 = require('bech32') +const bech32 = require('bech32'); -const EMPTY_BUFFER = Buffer.alloc(0) +const EMPTY_BUFFER = Buffer.alloc(0); // witness: {signature} {pubKey} // input: <> // output: OP_0 {pubKeyHash} -export function p2wpkh (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.address && - !a.hash && - !a.output && - !a.pubkey && - !a.witness - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - typef({ - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - input: typef.maybe(typef.BufferN(0)), - network: typef.maybe(typef.Object), - output: typef.maybe(typef.BufferN(22)), - pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) - }, a) - - const _address = lazy.value(function () { - const result = bech32.decode(a.address) - const version = result.words.shift() - const data = bech32.fromWords(result.words) +export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + typef( + { + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + input: typef.maybe(typef.BufferN(0)), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.BufferN(22)), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + + const _address = lazy.value(function() { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); return { version, prefix: result.prefix, - data: Buffer.from(data) - } - }) - - const network = a.network || BITCOIN_NETWORK - const o: Payment = { network } - - lazy.prop(o, 'address', function () { - if (!o.hash) return - - const words = bech32.toWords(o.hash) - words.unshift(0x00) - return bech32.encode(network.bech32, words) - }) - lazy.prop(o, 'hash', function () { - if (a.output) return a.output.slice(2, 22) - if (a.address) return _address().data - if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!) - }) - lazy.prop(o, 'output', function () { - if (!o.hash) return - return bscript.compile([ - OPS.OP_0, - o.hash - ]) - }) - lazy.prop(o, 'pubkey', function () { - if (a.pubkey) return a.pubkey - if (!a.witness) return - return a.witness[1] - }) - lazy.prop(o, 'signature', function () { - if (!a.witness) return - return a.witness[0] - }) - lazy.prop(o, 'input', function () { - if (!o.witness) return - return EMPTY_BUFFER - }) - lazy.prop(o, 'witness', function () { - if (!a.pubkey) return - if (!a.signature) return - return [a.signature, a.pubkey] - }) + data: Buffer.from(data), + }; + }); + + const network = a.network || BITCOIN_NETWORK; + const o: Payment = { network }; + + lazy.prop(o, 'address', function() { + if (!o.hash) return; + + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', function() { + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().data; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!); + }); + lazy.prop(o, 'output', function() { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'pubkey', function() { + if (a.pubkey) return a.pubkey; + if (!a.witness) return; + return a.witness[1]; + }); + lazy.prop(o, 'signature', function() { + if (!a.witness) return; + return a.witness[0]; + }); + lazy.prop(o, 'input', function() { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', function() { + if (!a.pubkey) return; + if (!a.signature) return; + return [a.signature, a.pubkey]; + }); // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]) + let hash: Buffer = Buffer.from([]); if (a.address) { - if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch') - if (_address().version !== 0x00) throw new TypeError('Invalid address version') - if (_address().data.length !== 20) throw new TypeError('Invalid address data') - hash = _address().data + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 20) + throw new TypeError('Invalid address data'); + hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') - else hash = a.hash + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; } if (a.output) { if ( a.output.length !== 22 || a.output[0] !== OPS.OP_0 || - a.output[1] !== 0x14) throw new TypeError('Output is invalid') - if (hash.length > 0 && !hash.equals(a.output.slice(2))) throw new TypeError('Hash mismatch') - else hash = a.output.slice(2) + a.output[1] !== 0x14 + ) + throw new TypeError('Output is invalid'); + if (hash.length > 0 && !hash.equals(a.output.slice(2))) + throw new TypeError('Hash mismatch'); + else hash = a.output.slice(2); } if (a.pubkey) { - const pkh = bcrypto.hash160(a.pubkey) - if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') - else hash = pkh + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; } if (a.witness) { - if (a.witness.length !== 2) throw new TypeError('Witness is invalid') - if (!bscript.isCanonicalScriptSignature(a.witness[0])) throw new TypeError('Witness has invalid signature') - if (!ecc.isPoint(a.witness[1])) throw new TypeError('Witness has invalid pubkey') - - if (a.signature && !a.signature.equals(a.witness[0])) throw new TypeError('Signature mismatch') - if (a.pubkey && !a.pubkey.equals(a.witness[1])) throw new TypeError('Pubkey mismatch') - - const pkh = bcrypto.hash160(a.witness[1]) - if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch') + if (a.witness.length !== 2) throw new TypeError('Witness is invalid'); + if (!bscript.isCanonicalScriptSignature(a.witness[0])) + throw new TypeError('Witness has invalid signature'); + if (!ecc.isPoint(a.witness[1])) + throw new TypeError('Witness has invalid pubkey'); + + if (a.signature && !a.signature.equals(a.witness[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(a.witness[1])) + throw new TypeError('Pubkey mismatch'); + + const pkh = bcrypto.hash160(a.witness[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index edb0a69..5f9b02d 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -6,98 +6,95 @@ import * as lazy from './lazy' const typef = require('typeforce') const OPS = bscript.OPS -const bech32 = require('bech32') +const bech32 = require('bech32'); -const EMPTY_BUFFER = Buffer.alloc(0) +const EMPTY_BUFFER = Buffer.alloc(0); -function stacksEqual (a: Array, b: Array): boolean { - if (a.length !== b.length) return false +function stacksEqual(a: Array, b: Array): boolean { + if (a.length !== b.length) return false; - return a.every(function (x, i) { - return x.equals(b[i]) - }) + return a.every(function(x, i) { + return x.equals(b[i]); + }); } // input: <> // witness: [redeemScriptSig ...] {redeemScript} // output: OP_0 {sha256(redeemScript)} -export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { - if ( - !a.address && - !a.hash && - !a.output && - !a.redeem && - !a.witness - ) throw new TypeError('Not enough data') - opts = Object.assign({ validate: true }, opts || {}) - - typef({ - network: typef.maybe(typef.Object), - - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(32)), - output: typef.maybe(typef.BufferN(34)), - - redeem: typef.maybe({ - input: typef.maybe(typef.Buffer), +export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { + if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + + typef( + { network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) - }), - input: typef.maybe(typef.BufferN(0)), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) - }, a) - - const _address = lazy.value(function () { - const result = bech32.decode(a.address) - const version = result.words.shift() - const data = bech32.fromWords(result.words) + + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(32)), + output: typef.maybe(typef.BufferN(34)), + + redeem: typef.maybe({ + input: typef.maybe(typef.Buffer), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }), + input: typef.maybe(typef.BufferN(0)), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + + const _address = lazy.value(function() { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); return { version, prefix: result.prefix, - data: Buffer.from(data) - } - }) - const _rchunks = <()=>Array>lazy.value(function () { return bscript.decompile(a.redeem!.input!) }) - - let network = a.network + data: Buffer.from(data), + }; + }); + const _rchunks = <() => Array>lazy.value(function() { + return bscript.decompile(a.redeem!.input!); + }); + + let network = a.network; if (!network) { - network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK; } - const o: Payment = { network } - - lazy.prop(o, 'address', function () { - if (!o.hash) return - const words = bech32.toWords(o.hash) - words.unshift(0x00) - return bech32.encode(network!.bech32, words) - }) - lazy.prop(o, 'hash', function () { - if (a.output) return a.output.slice(2) - if (a.address) return _address().data - if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output) - }) - lazy.prop(o, 'output', function () { - if (!o.hash) return - return bscript.compile([ - OPS.OP_0, - o.hash - ]) - }) - lazy.prop(o, 'redeem', function () { - if (!a.witness) return + const o: Payment = { network }; + + lazy.prop(o, 'address', function() { + if (!o.hash) return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network!.bech32, words); + }); + lazy.prop(o, 'hash', function() { + if (a.output) return a.output.slice(2); + if (a.address) return _address().data; + if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + }); + lazy.prop(o, 'output', function() { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'redeem', function() { + if (!a.witness) return; return { output: a.witness[a.witness.length - 1], input: EMPTY_BUFFER, - witness: a.witness.slice(0, -1) - } - }) - lazy.prop(o, 'input', function () { - if (!o.witness) return - return EMPTY_BUFFER - }) - lazy.prop(o, 'witness', function () { + witness: a.witness.slice(0, -1), + }; + }); + lazy.prop(o, 'input', function() { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', function() { // transform redeem input to witness stack? if ( a.redeem && @@ -106,47 +103,55 @@ export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { a.redeem.output && a.redeem.output.length > 0 ) { - const stack = bscript.toStack(_rchunks()) + const stack = bscript.toStack(_rchunks()); // assign, and blank the existing input - o.redeem = Object.assign({ witness: stack }, a.redeem) - o.redeem.input = EMPTY_BUFFER - return (>[]).concat(stack, a.redeem.output) + o.redeem = Object.assign({ witness: stack }, a.redeem); + o.redeem.input = EMPTY_BUFFER; + return (>[]).concat(stack, a.redeem.output); } - if (!a.redeem) return - if (!a.redeem.output) return - if (!a.redeem.witness) return - return (>[]).concat(a.redeem.witness, a.redeem.output) - }) + if (!a.redeem) return; + if (!a.redeem.output) return; + if (!a.redeem.witness) return; + return (>[]).concat(a.redeem.witness, a.redeem.output); + }); // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]) + let hash: Buffer = Buffer.from([]); if (a.address) { - if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch') - if (_address().version !== 0x00) throw new TypeError('Invalid address version') - if (_address().data.length !== 32) throw new TypeError('Invalid address data') - hash = _address().data + if (_address().prefix !== network.bech32) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) throw new TypeError('Hash mismatch') - else hash = a.hash + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; } if (a.output) { if ( a.output.length !== 34 || a.output[0] !== OPS.OP_0 || - a.output[1] !== 0x20) throw new TypeError('Output is invalid') - const hash2 = a.output.slice(2) - if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') - else hash = hash2 + a.output[1] !== 0x20 + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; } if (a.redeem) { - if (a.redeem.network && a.redeem.network !== network) throw new TypeError('Network mismatch') + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); // is there two redeem sources? if ( @@ -154,26 +159,40 @@ export function p2wsh (a: Payment, opts?: PaymentOpts): Payment { a.redeem.input.length > 0 && a.redeem.witness && a.redeem.witness.length > 0 - ) throw new TypeError('Ambiguous witness source') + ) + throw new TypeError('Ambiguous witness source'); // is the redeem output non-empty? if (a.redeem.output) { - if (bscript.decompile(a.redeem.output)!.length === 0) throw new TypeError('Redeem.output is invalid') + if (bscript.decompile(a.redeem.output)!.length === 0) + throw new TypeError('Redeem.output is invalid'); // match hash against other sources - const hash2 = bcrypto.sha256(a.redeem.output) - if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch') - else hash = hash2 + const hash2 = bcrypto.sha256(a.redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; } - if (a.redeem.input && !bscript.isPushOnly(_rchunks())) throw new TypeError('Non push-only scriptSig') - if (a.witness && a.redeem.witness && !stacksEqual(a.witness, a.redeem.witness)) throw new TypeError('Witness and redeem.witness mismatch') + if (a.redeem.input && !bscript.isPushOnly(_rchunks())) + throw new TypeError('Non push-only scriptSig'); + if ( + a.witness && + a.redeem.witness && + !stacksEqual(a.witness, a.redeem.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); } if (a.witness) { - if (a.redeem && a.redeem.output && !a.redeem.output.equals(a.witness[a.witness.length - 1])) throw new TypeError('Witness and redeem.output mismatch') + if ( + a.redeem && + a.redeem.output && + !a.redeem.output.equals(a.witness[a.witness.length - 1]) + ) + throw new TypeError('Witness and redeem.output mismatch'); } } - return Object.assign(o, a) + return Object.assign(o, a); } diff --git a/ts_src/script.ts b/ts_src/script.ts index 64b74ad..36fef95 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -1,206 +1,218 @@ -import * as types from './types' -import * as scriptNumber from './script_number' -import * as scriptSignature from './script_signature' -const bip66 = require('bip66') -const ecc = require('tiny-secp256k1') -const pushdata = require('pushdata-bitcoin') -const typeforce = require('typeforce') - -export type OpCode = number -export const OPS = <{[index:string]: OpCode}> require('bitcoin-ops') - -const REVERSE_OPS = <{[index:number]: string}> require('bitcoin-ops/map') -const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 - -function isOPInt (value:number): boolean { - return types.Number(value) && - ((value === OPS.OP_0) || - (value >= OPS.OP_1 && value <= OPS.OP_16) || - (value === OPS.OP_1NEGATE)) +import * as types from './types'; +import * as scriptNumber from './script_number'; +import * as scriptSignature from './script_signature'; +const bip66 = require('bip66'); +const ecc = require('tiny-secp256k1'); +const pushdata = require('pushdata-bitcoin'); +const typeforce = require('typeforce'); + +export type OpCode = number; +export const OPS = <{ [index: string]: OpCode }>require('bitcoin-ops'); + +const REVERSE_OPS = <{ [index: number]: string }>require('bitcoin-ops/map'); +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 + +function isOPInt(value: number): boolean { + return ( + types.Number(value) && + (value === OPS.OP_0 || + (value >= OPS.OP_1 && value <= OPS.OP_16) || + value === OPS.OP_1NEGATE) + ); } -function isPushOnlyChunk (value: number | Buffer): boolean { - return types.Buffer(value) || isOPInt(value) +function isPushOnlyChunk(value: number | Buffer): boolean { + return types.Buffer(value) || isOPInt(value); } -export function isPushOnly (value: Array) { - return types.Array(value) && value.every(isPushOnlyChunk) +export function isPushOnly(value: Array) { + return types.Array(value) && value.every(isPushOnlyChunk); } -function asMinimalOP (buffer: Buffer): number | void { - if (buffer.length === 0) return OPS.OP_0 - if (buffer.length !== 1) return - if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0] - if (buffer[0] === 0x81) return OPS.OP_1NEGATE +function asMinimalOP(buffer: Buffer): number | void { + if (buffer.length === 0) return OPS.OP_0; + if (buffer.length !== 1) return; + if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; + if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } function chunksIsBuffer(buf: Buffer | Array): buf is Buffer { - return Buffer.isBuffer(buf) + return Buffer.isBuffer(buf); } -function chunksIsArray(buf: Buffer | Array): buf is Array { - return types.Array(buf) +function chunksIsArray( + buf: Buffer | Array, +): buf is Array { + return types.Array(buf); } function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer { - return Buffer.isBuffer(buf) + return Buffer.isBuffer(buf); } -export function compile (chunks: Buffer | Array): Buffer { +export function compile(chunks: Buffer | Array): Buffer { // TODO: remove me - if (chunksIsBuffer(chunks)) return chunks + if (chunksIsBuffer(chunks)) return chunks; - typeforce(types.Array, chunks) + typeforce(types.Array, chunks); - const bufferSize = chunks.reduce(function (accum: number, chunk) { + const bufferSize = chunks.reduce(function(accum: number, chunk) { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { - return accum + 1 + return accum + 1; } - return accum + pushdata.encodingLength(chunk.length) + chunk.length + return accum + pushdata.encodingLength(chunk.length) + chunk.length; } // opcode - return accum + 1 - }, 0.0) + return accum + 1; + }, 0.0); - const buffer = Buffer.allocUnsafe(bufferSize) - let offset = 0 + const buffer = Buffer.allocUnsafe(bufferSize); + let offset = 0; - chunks.forEach(function (chunk) { + chunks.forEach(function(chunk) { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy - const opcode = asMinimalOP(chunk) + const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - buffer.writeUInt8(opcode, offset) - offset += 1 - return + buffer.writeUInt8(opcode, offset); + offset += 1; + return; } - offset += pushdata.encode(buffer, chunk.length, offset) - chunk.copy(buffer, offset) - offset += chunk.length + offset += pushdata.encode(buffer, chunk.length, offset); + chunk.copy(buffer, offset); + offset += chunk.length; - // opcode + // opcode } else { - buffer.writeUInt8(chunk, offset) - offset += 1 + buffer.writeUInt8(chunk, offset); + offset += 1; } - }) + }); - if (offset !== buffer.length) throw new Error('Could not decode chunks') - return buffer + if (offset !== buffer.length) throw new Error('Could not decode chunks'); + return buffer; } -export function decompile (buffer: Buffer | Array): Array | null { +export function decompile( + buffer: Buffer | Array, +): Array | null { // TODO: remove me - if (chunksIsArray(buffer)) return buffer + if (chunksIsArray(buffer)) return buffer; - typeforce(types.Buffer, buffer) + typeforce(types.Buffer, buffer); - const chunks: Array = [] - let i = 0 + const chunks: Array = []; + let i = 0; while (i < buffer.length) { - const opcode = buffer[i] + const opcode = buffer[i]; // data chunk - if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) { - const d = pushdata.decode(buffer, i) + if (opcode > OPS.OP_0 && opcode <= OPS.OP_PUSHDATA4) { + const d = pushdata.decode(buffer, i); // did reading a pushDataInt fail? - if (d === null) return null - i += d.size + if (d === null) return null; + i += d.size; // attempt to read too much data? - if (i + d.number > buffer.length) return null + if (i + d.number > buffer.length) return null; - const data = buffer.slice(i, i + d.number) - i += d.number + const data = buffer.slice(i, i + d.number); + i += d.number; // decompile minimally - const op = asMinimalOP(data) + const op = asMinimalOP(data); if (op !== undefined) { - chunks.push(op) + chunks.push(op); } else { - chunks.push(data) + chunks.push(data); } - // opcode + // opcode } else { - chunks.push(opcode) + chunks.push(opcode); - i += 1 + i += 1; } } - return chunks + return chunks; } -export function toASM (chunks: Buffer | Array): string { +export function toASM(chunks: Buffer | Array): string { if (chunksIsBuffer(chunks)) { - chunks = >decompile(chunks) + chunks = >decompile(chunks); } - return chunks.map(function (chunk) { - // data? - if (singleChunkIsBuffer(chunk)) { - const op = asMinimalOP(chunk) - if (op === undefined) return chunk.toString('hex') - chunk = op - } + return chunks + .map(function(chunk) { + // data? + if (singleChunkIsBuffer(chunk)) { + const op = asMinimalOP(chunk); + if (op === undefined) return chunk.toString('hex'); + chunk = op; + } - // opcode! - return REVERSE_OPS[chunk] - }).join(' ') + // opcode! + return REVERSE_OPS[chunk]; + }) + .join(' '); } -export function fromASM (asm: string): Buffer { - typeforce(types.String, asm) +export function fromASM(asm: string): Buffer { + typeforce(types.String, asm); - return compile(asm.split(' ').map(function (chunkStr) { - // opcode? - if (OPS[chunkStr] !== undefined) return OPS[chunkStr] - typeforce(types.Hex, chunkStr) + return compile( + asm.split(' ').map(function(chunkStr) { + // opcode? + if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; + typeforce(types.Hex, chunkStr); - // data! - return Buffer.from(chunkStr, 'hex') - })) + // data! + return Buffer.from(chunkStr, 'hex'); + }), + ); } -export function toStack (chunks: Buffer | Array): Array { - chunks = >decompile(chunks) - typeforce(isPushOnly, chunks) +export function toStack( + chunks: Buffer | Array, +): Array { + chunks = >decompile(chunks); + typeforce(isPushOnly, chunks); - return chunks.map(function (op) { - if (singleChunkIsBuffer(op)) return op - if (op === OPS.OP_0) return Buffer.allocUnsafe(0) + return chunks.map(function(op) { + if (singleChunkIsBuffer(op)) return op; + if (op === OPS.OP_0) return Buffer.allocUnsafe(0); - return scriptNumber.encode(op - OP_INT_BASE) - }) + return scriptNumber.encode(op - OP_INT_BASE); + }); } -export function isCanonicalPubKey (buffer: Buffer): boolean { - return ecc.isPoint(buffer) +export function isCanonicalPubKey(buffer: Buffer): boolean { + return ecc.isPoint(buffer); } -export function isDefinedHashType (hashType: number): boolean { - const hashTypeMod = hashType & ~0x80 +export function isDefinedHashType(hashType: number): boolean { + const hashTypeMod = hashType & ~0x80; // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE - return hashTypeMod > 0x00 && hashTypeMod < 0x04 + return hashTypeMod > 0x00 && hashTypeMod < 0x04; } -export function isCanonicalScriptSignature (buffer: Buffer): boolean { - if (!Buffer.isBuffer(buffer)) return false - if (!isDefinedHashType(buffer[buffer.length - 1])) return false +export function isCanonicalScriptSignature(buffer: Buffer): boolean { + if (!Buffer.isBuffer(buffer)) return false; + if (!isDefinedHashType(buffer[buffer.length - 1])) return false; - return bip66.check(buffer.slice(0, -1)) + return bip66.check(buffer.slice(0, -1)); } -export const number = scriptNumber -export const signature = scriptSignature +export const number = scriptNumber; +export const signature = scriptSignature; diff --git a/ts_src/script_number.ts b/ts_src/script_number.ts index d88c463..cd48373 100644 --- a/ts_src/script_number.ts +++ b/ts_src/script_number.ts @@ -1,62 +1,71 @@ +export function decode( + buffer: Buffer, + maxLength?: number, + minimal?: boolean, +): number { + maxLength = maxLength || 4; + minimal = minimal === undefined ? true : minimal; - -export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): number { - maxLength = maxLength || 4 - minimal = minimal === undefined ? true : minimal - - const length = buffer.length - if (length === 0) return 0 - if (length > maxLength) throw new TypeError('Script number overflow') + const length = buffer.length; + if (length === 0) return 0; + if (length > maxLength) throw new TypeError('Script number overflow'); if (minimal) { if ((buffer[length - 1] & 0x7f) === 0) { - if (length <= 1 || (buffer[length - 2] & 0x80) === 0) throw new Error('Non-minimally encoded script number') + if (length <= 1 || (buffer[length - 2] & 0x80) === 0) + throw new Error('Non-minimally encoded script number'); } } // 40-bit if (length === 5) { - const a = buffer.readUInt32LE(0) - const b = buffer.readUInt8(4) + const a = buffer.readUInt32LE(0); + const b = buffer.readUInt8(4); - if (b & 0x80) return -(((b & ~0x80) * 0x100000000) + a) - return (b * 0x100000000) + a + if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); + return b * 0x100000000 + a; } // 32-bit / 24-bit / 16-bit / 8-bit - let result = 0 + let result = 0; for (var i = 0; i < length; ++i) { - result |= buffer[i] << (8 * i) + result |= buffer[i] << (8 * i); } - if (buffer[length - 1] & 0x80) return -(result & ~(0x80 << (8 * (length - 1)))) - return result + if (buffer[length - 1] & 0x80) + return -(result & ~(0x80 << (8 * (length - 1)))); + return result; } -function scriptNumSize (i: number): number { - return i > 0x7fffffff ? 5 - : i > 0x7fffff ? 4 - : i > 0x7fff ? 3 - : i > 0x7f ? 2 - : i > 0x00 ? 1 - : 0 +function scriptNumSize(i: number): number { + return i > 0x7fffffff + ? 5 + : i > 0x7fffff + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; } -export function encode (number: number): Buffer { - let value = Math.abs(number) - const size = scriptNumSize(value) - const buffer = Buffer.allocUnsafe(size) - const negative = number < 0 +export function encode(number: number): Buffer { + let value = Math.abs(number); + const size = scriptNumSize(value); + const buffer = Buffer.allocUnsafe(size); + const negative = number < 0; for (var i = 0; i < size; ++i) { - buffer.writeUInt8(value & 0xff, i) - value >>= 8 + buffer.writeUInt8(value & 0xff, i); + value >>= 8; } if (buffer[size - 1] & 0x80) { - buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1) + buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); } else if (negative) { - buffer[size - 1] |= 0x80 + buffer[size - 1] |= 0x80; } - return buffer + return buffer; } diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts index 3b5bc6e..1f11d00 100644 --- a/ts_src/script_signature.ts +++ b/ts_src/script_signature.ts @@ -1,64 +1,66 @@ -import * as types from './types' -const bip66 = require('bip66') +import * as types from './types'; +const bip66 = require('bip66'); -const typeforce = require('typeforce') +const typeforce = require('typeforce'); -const ZERO = Buffer.alloc(1, 0) -function toDER (x: Buffer): Buffer { - let i = 0 - while (x[i] === 0) ++i - if (i === x.length) return ZERO - x = x.slice(i) - if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length) - return x +const ZERO = Buffer.alloc(1, 0); +function toDER(x: Buffer): Buffer { + let i = 0; + while (x[i] === 0) ++i; + if (i === x.length) return ZERO; + x = x.slice(i); + if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + return x; } -function fromDER (x: Buffer): Buffer { - if (x[0] === 0x00) x = x.slice(1) - const buffer = Buffer.alloc(32, 0) - const bstart = Math.max(0, 32 - x.length) - x.copy(buffer, bstart) - return buffer +function fromDER(x: Buffer): Buffer { + if (x[0] === 0x00) x = x.slice(1); + const buffer = Buffer.alloc(32, 0); + const bstart = Math.max(0, 32 - x.length); + x.copy(buffer, bstart); + return buffer; } interface ScriptSignature { - signature: Buffer - hashType: number + signature: Buffer; + hashType: number; } // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) -export function decode (buffer: Buffer): ScriptSignature { - const hashType = buffer.readUInt8(buffer.length - 1) - const hashTypeMod = hashType & ~0x80 - if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) +export function decode(buffer: Buffer): ScriptSignature { + const hashType = buffer.readUInt8(buffer.length - 1); + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); - const decode = bip66.decode(buffer.slice(0, -1)) - const r = fromDER(decode.r) - const s = fromDER(decode.s) + const decode = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decode.r); + const s = fromDER(decode.s); return { signature: Buffer.concat([r, s], 64), - hashType: hashType - } + hashType: hashType, + }; } -export function encode (signature: Buffer, hashType: number): Buffer { - typeforce({ - signature: types.BufferN(64), - hashType: types.UInt8 - }, { signature, hashType }) +export function encode(signature: Buffer, hashType: number): Buffer { + typeforce( + { + signature: types.BufferN(64), + hashType: types.UInt8, + }, + { signature, hashType }, + ); - const hashTypeMod = hashType & ~0x80 - if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); - const hashTypeBuffer = Buffer.allocUnsafe(1) - hashTypeBuffer.writeUInt8(hashType, 0) + const hashTypeBuffer = Buffer.allocUnsafe(1); + hashTypeBuffer.writeUInt8(hashType, 0); - const r = toDER(signature.slice(0, 32)) - const s = toDER(signature.slice(32, 64)) + const r = toDER(signature.slice(0, 32)); + const s = toDER(signature.slice(32, 64)); - return Buffer.concat([ - bip66.encode(r, s), - hashTypeBuffer - ]) + return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/ts_src/templates/nulldata.ts b/ts_src/templates/nulldata.ts index 0833eac..f0694a3 100644 --- a/ts_src/templates/nulldata.ts +++ b/ts_src/templates/nulldata.ts @@ -1,17 +1,16 @@ // OP_RETURN {data} -import * as bscript from '../script' -const OPS = bscript.OPS +import * as bscript from '../script'; +const OPS = bscript.OPS; -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length > 1 && - buffer[0] === OPS.OP_RETURN + return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } -check.toJSON = function () { return 'null data output' } +check.toJSON = function() { + return 'null data output'; +}; -const output = { check } +const output = { check }; -export { - output -} +export { output }; diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index e6e1d24..a456a32 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -1,282 +1,311 @@ -import * as bcrypto from './crypto' -import * as bscript from './script' -import * as types from './types' -import * as bufferutils from './bufferutils' -import { reverseBuffer } from './bufferutils' -import { OPS as opcodes } from './script' +import * as bcrypto from './crypto'; +import * as bscript from './script'; +import * as types from './types'; +import * as bufferutils from './bufferutils'; +import { reverseBuffer } from './bufferutils'; +import { OPS as opcodes } from './script'; -const typeforce = require('typeforce') -const varuint = require('varuint-bitcoin') +const typeforce = require('typeforce'); +const varuint = require('varuint-bitcoin'); -function varSliceSize (someScript: Buffer): number { - const length = someScript.length +function varSliceSize(someScript: Buffer): number { + const length = someScript.length; - return varuint.encodingLength(length) + length + return varuint.encodingLength(length) + length; } -function vectorSize (someVector: Array): number { - const length = someVector.length +function vectorSize(someVector: Array): number { + const length = someVector.length; - return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { - return sum + varSliceSize(witness) - }, 0) + return ( + varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0) + ); } -const EMPTY_SCRIPT: Buffer = Buffer.allocUnsafe(0) -const EMPTY_WITNESS: Array = [] -const ZERO: Buffer = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex') -const ONE: Buffer = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex') -const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex') +const EMPTY_SCRIPT: Buffer = Buffer.allocUnsafe(0); +const EMPTY_WITNESS: Array = []; +const ZERO: Buffer = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', +); +const ONE: Buffer = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex', +); +const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT: BlankOutput = { script: EMPTY_SCRIPT, - valueBuffer: VALUE_UINT64_MAX -} + valueBuffer: VALUE_UINT64_MAX, +}; function isOutput(out: Output | BlankOutput): out is Output { - return (out).value !== undefined + return (out).value !== undefined; } export type BlankOutput = { - script: Buffer - valueBuffer: Buffer -} + script: Buffer; + valueBuffer: Buffer; +}; export type Output = { - script: Buffer - value: number -} + script: Buffer; + value: number; +}; export type Input = { - hash: Buffer - index: number - script: Buffer - sequence: number - witness: Array -} + hash: Buffer; + index: number; + script: Buffer; + sequence: number; + witness: Array; +}; export class Transaction { - version: number - locktime: number - ins: Array - outs: Array - - static readonly DEFAULT_SEQUENCE = 0xffffffff - static readonly SIGHASH_ALL = 0x01 - static readonly SIGHASH_NONE = 0x02 - static readonly SIGHASH_SINGLE = 0x03 - static readonly SIGHASH_ANYONECANPAY = 0x80 - static readonly ADVANCED_TRANSACTION_MARKER = 0x00 - static readonly ADVANCED_TRANSACTION_FLAG = 0x01 - - constructor () { - this.version = 1 - this.locktime = 0 - this.ins = [] - this.outs = [] + version: number; + locktime: number; + ins: Array; + outs: Array; + + static readonly DEFAULT_SEQUENCE = 0xffffffff; + static readonly SIGHASH_ALL = 0x01; + static readonly SIGHASH_NONE = 0x02; + static readonly SIGHASH_SINGLE = 0x03; + static readonly SIGHASH_ANYONECANPAY = 0x80; + static readonly ADVANCED_TRANSACTION_MARKER = 0x00; + static readonly ADVANCED_TRANSACTION_FLAG = 0x01; + + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; } - static fromBuffer (buffer: Buffer, __noStrict?: boolean): Transaction { - let offset: number = 0 + static fromBuffer(buffer: Buffer, __noStrict?: boolean): Transaction { + let offset: number = 0; - function readSlice (n: number): Buffer { - offset += n - return buffer.slice(offset - n, offset) + function readSlice(n: number): Buffer { + offset += n; + return buffer.slice(offset - n, offset); } - function readUInt32 (): number { - const i = buffer.readUInt32LE(offset) - offset += 4 - return i + function readUInt32(): number { + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; } - function readInt32 (): number { - const i = buffer.readInt32LE(offset) - offset += 4 - return i + function readInt32(): number { + const i = buffer.readInt32LE(offset); + offset += 4; + return i; } - function readUInt64 (): number { - const i = bufferutils.readUInt64LE(buffer, offset) - offset += 8 - return i + function readUInt64(): number { + const i = bufferutils.readUInt64LE(buffer, offset); + offset += 8; + return i; } - function readVarInt (): number { - const vi = varuint.decode(buffer, offset) - offset += varuint.decode.bytes - return vi + function readVarInt(): number { + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; } - function readVarSlice (): Buffer { - return readSlice(readVarInt()) + function readVarSlice(): Buffer { + return readSlice(readVarInt()); } - function readVector (): Array { - const count = readVarInt() - const vector: Array = [] - for (var i = 0; i < count; i++) vector.push(readVarSlice()) - return vector + function readVector(): Array { + const count = readVarInt(); + const vector: Array = []; + for (var i = 0; i < count; i++) vector.push(readVarSlice()); + return vector; } - const tx = new Transaction() - tx.version = readInt32() + const tx = new Transaction(); + tx.version = readInt32(); - const marker = buffer.readUInt8(offset) - const flag = buffer.readUInt8(offset + 1) + const marker = buffer.readUInt8(offset); + const flag = buffer.readUInt8(offset + 1); - let hasWitnesses = false - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - offset += 2 - hasWitnesses = true + let hasWitnesses = false; + if ( + marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG + ) { + offset += 2; + hasWitnesses = true; } - const vinLen = readVarInt() + const vinLen = readVarInt(); for (var i = 0; i < vinLen; ++i) { tx.ins.push({ hash: readSlice(32), index: readUInt32(), script: readVarSlice(), sequence: readUInt32(), - witness: EMPTY_WITNESS - }) + witness: EMPTY_WITNESS, + }); } - const voutLen = readVarInt() + const voutLen = readVarInt(); for (i = 0; i < voutLen; ++i) { tx.outs.push({ value: readUInt64(), - script: readVarSlice() - }) + script: readVarSlice(), + }); } if (hasWitnesses) { for (i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector() + tx.ins[i].witness = readVector(); } // was this pointless? - if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); } - tx.locktime = readUInt32() + tx.locktime = readUInt32(); - if (__noStrict) return tx - if (offset !== buffer.length) throw new Error('Transaction has unexpected data') + if (__noStrict) return tx; + if (offset !== buffer.length) + throw new Error('Transaction has unexpected data'); - return tx + return tx; } - static fromHex (hex: string): Transaction { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false) + static fromHex(hex: string): Transaction { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); } - static isCoinbaseHash (buffer: Buffer): boolean { - typeforce(types.Hash256bit, buffer) + static isCoinbaseHash(buffer: Buffer): boolean { + typeforce(types.Hash256bit, buffer); for (var i = 0; i < 32; ++i) { - if (buffer[i] !== 0) return false + if (buffer[i] !== 0) return false; } - return true + return true; } - isCoinbase (): boolean { - return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + isCoinbase(): boolean { + return ( + this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + ); } - addInput (hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number { - typeforce(types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer) - ), arguments) + addInput( + hash: Buffer, + index: number, + sequence?: number, + scriptSig?: Buffer, + ): number { + typeforce( + types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer), + ), + arguments, + ); if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE + sequence = Transaction.DEFAULT_SEQUENCE; } // Add the input and return the input's index - return (this.ins.push({ - hash: hash, - index: index, - script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, - witness: EMPTY_WITNESS - }) - 1) + return ( + this.ins.push({ + hash: hash, + index: index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS, + }) - 1 + ); } - addOutput (scriptPubKey: Buffer, value: number): number { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) + addOutput(scriptPubKey: Buffer, value: number): number { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value: value - }) - 1) + return ( + this.outs.push({ + script: scriptPubKey, + value: value, + }) - 1 + ); } - hasWitnesses (): boolean { - return this.ins.some((x) => { - return x.witness.length !== 0 - }) + hasWitnesses(): boolean { + return this.ins.some(x => { + return x.witness.length !== 0; + }); } - weight (): number { - const base = this.__byteLength(false) - const total = this.__byteLength(true) - return base * 3 + total + weight(): number { + const base = this.__byteLength(false); + const total = this.__byteLength(true); + return base * 3 + total; } - virtualSize (): number { - return Math.ceil(this.weight() / 4) + virtualSize(): number { + return Math.ceil(this.weight() / 4); } - byteLength (): number { - return this.__byteLength(true) + byteLength(): number { + return this.__byteLength(true); } - private __byteLength (__allowWitness: boolean): number { - const hasWitnesses = __allowWitness && this.hasWitnesses() + private __byteLength(__allowWitness: boolean): number { + const hasWitnesses = __allowWitness && this.hasWitnesses(); return ( (hasWitnesses ? 10 : 8) + varuint.encodingLength(this.ins.length) + varuint.encodingLength(this.outs.length) + this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script) + return sum + 40 + varSliceSize(input.script); }, 0) + this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script) + return sum + 8 + varSliceSize(output.script); }, 0) + - (hasWitnesses ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness) - }, 0) : 0) - ) + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0) + ); } - clone (): Transaction { - const newTx = new Transaction() - newTx.version = this.version - newTx.locktime = this.locktime + clone(): Transaction { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; - newTx.ins = this.ins.map((txIn) => { + newTx.ins = this.ins.map(txIn => { return { hash: txIn.hash, index: txIn.index, script: txIn.script, sequence: txIn.sequence, - witness: txIn.witness - } - }) + witness: txIn.witness, + }; + }); - newTx.outs = this.outs.map((txOut) => { + newTx.outs = this.outs.map(txOut => { return { script: txOut.script, - value: (txOut).value - } - }) + value: (txOut).value, + }; + }); - return newTx + return newTx; } /** @@ -287,284 +316,313 @@ export class Transaction { * hashType, and then hashes the result. * This hash can then be used to sign the provided transaction input. */ - hashForSignature (inIndex: number, prevOutScript: Buffer, hashType: number): Buffer { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) + hashForSignature( + inIndex: number, + prevOutScript: Buffer, + hashType: number, + ): Buffer { + typeforce( + types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + arguments, + ); // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) return ONE + if (inIndex >= this.ins.length) return ONE; // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript)!.filter((x) => { - return x !== opcodes.OP_CODESEPARATOR - })) + const ourScript = bscript.compile( + bscript.decompile(prevOutScript)!.filter(x => { + return x !== opcodes.OP_CODESEPARATOR; + }), + ); - const txTmp = this.clone() + const txTmp = this.clone(); // SIGHASH_NONE: ignore all outputs? (wildcard payee) if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = [] + txTmp.outs = []; // ignore sequence numbers (except at inIndex) txTmp.ins.forEach((input, i) => { - if (i === inIndex) return + if (i === inIndex) return; - input.sequence = 0 - }) + input.sequence = 0; + }); // SIGHASH_SINGLE: ignore all outputs, except at the same index? } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) return ONE + if (inIndex >= this.outs.length) return ONE; // truncate outputs after - txTmp.outs.length = inIndex + 1 + txTmp.outs.length = inIndex + 1; // "blank" outputs before for (var i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT + txTmp.outs[i] = BLANK_OUTPUT; } // ignore sequence numbers (except at inIndex) txTmp.ins.forEach((input, y) => { - if (y === inIndex) return + if (y === inIndex) return; - input.sequence = 0 - }) + input.sequence = 0; + }); } // SIGHASH_ANYONECANPAY: ignore inputs entirely? if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]] - txTmp.ins[0].script = ourScript + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; // SIGHASH_ALL: only ignore input scripts } else { // "blank" others input scripts - txTmp.ins.forEach((input) => { - input.script = EMPTY_SCRIPT - }) - txTmp.ins[inIndex].script = ourScript + txTmp.ins.forEach(input => { + input.script = EMPTY_SCRIPT; + }); + txTmp.ins[inIndex].script = ourScript; } // serialize and hash - const buffer: Buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4) - buffer.writeInt32LE(hashType, buffer.length - 4) - txTmp.__toBuffer(buffer, 0, false) + const buffer: Buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); - return bcrypto.hash256(buffer) + return bcrypto.hash256(buffer); } - hashForWitnessV0 (inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) + hashForWitnessV0( + inIndex: number, + prevOutScript: Buffer, + value: number, + hashType: number, + ): Buffer { + typeforce( + types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + arguments, + ); - let tbuffer: Buffer = Buffer.from([]) - let toffset: number = 0 + let tbuffer: Buffer = Buffer.from([]); + let toffset: number = 0; - function writeSlice (slice: Buffer): void { - toffset += slice.copy(tbuffer, toffset) + function writeSlice(slice: Buffer): void { + toffset += slice.copy(tbuffer, toffset); } - function writeUInt32 (i: number): void { - toffset = tbuffer.writeUInt32LE(i, toffset) + function writeUInt32(i: number): void { + toffset = tbuffer.writeUInt32LE(i, toffset); } - function writeUInt64 (i: number): void { - toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) + function writeUInt64(i: number): void { + toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset); } - function writeVarInt (i: number): void { - varuint.encode(i, tbuffer, toffset) - toffset += varuint.encode.bytes + function writeVarInt(i: number): void { + varuint.encode(i, tbuffer, toffset); + toffset += varuint.encode.bytes; } - function writeVarSlice (slice: Buffer): void { - writeVarInt(slice.length) - writeSlice(slice) + function writeVarSlice(slice: Buffer): void { + writeVarInt(slice.length); + writeSlice(slice); } - let hashOutputs = ZERO - let hashPrevouts = ZERO - let hashSequence = ZERO + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length) - toffset = 0 + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + toffset = 0; - this.ins.forEach((txIn) => { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - }) + this.ins.forEach(txIn => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + }); - hashPrevouts = bcrypto.hash256(tbuffer) + hashPrevouts = bcrypto.hash256(tbuffer); } - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && + if ( + !(hashType & Transaction.SIGHASH_ANYONECANPAY) && (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length) - toffset = 0 + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + toffset = 0; - this.ins.forEach((txIn) => { - writeUInt32(txIn.sequence) - }) + this.ins.forEach(txIn => { + writeUInt32(txIn.sequence); + }); - hashSequence = bcrypto.hash256(tbuffer) + hashSequence = bcrypto.hash256(tbuffer); } - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { + if ( + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { const txOutsSize = this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script) - }, 0) - - tbuffer = Buffer.allocUnsafe(txOutsSize) - toffset = 0 - - this.outs.forEach((out) => { - writeUInt64((out).value) - writeVarSlice(out.script) - }) - - hashOutputs = bcrypto.hash256(tbuffer) - } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { - const output = this.outs[inIndex] - - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)) - toffset = 0 - writeUInt64((output).value) - writeVarSlice(output.script) - - hashOutputs = bcrypto.hash256(tbuffer) - } - - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)) - toffset = 0 - - const input = this.ins[inIndex] - writeUInt32(this.version) - writeSlice(hashPrevouts) - writeSlice(hashSequence) - writeSlice(input.hash) - writeUInt32(input.index) - writeVarSlice(prevOutScript) - writeUInt64(value) - writeUInt32(input.sequence) - writeSlice(hashOutputs) - writeUInt32(this.locktime) - writeUInt32(hashType) - return bcrypto.hash256(tbuffer) + return sum + 8 + varSliceSize(output.script); + }, 0); + + tbuffer = Buffer.allocUnsafe(txOutsSize); + toffset = 0; + + this.outs.forEach(out => { + writeUInt64((out).value); + writeVarSlice(out.script); + }); + + hashOutputs = bcrypto.hash256(tbuffer); + } else if ( + (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length + ) { + const output = this.outs[inIndex]; + + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + toffset = 0; + writeUInt64((output).value); + writeVarSlice(output.script); + + hashOutputs = bcrypto.hash256(tbuffer); + } + + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + toffset = 0; + + const input = this.ins[inIndex]; + writeUInt32(this.version); + writeSlice(hashPrevouts); + writeSlice(hashSequence); + writeSlice(input.hash); + writeUInt32(input.index); + writeVarSlice(prevOutScript); + writeUInt64(value); + writeUInt32(input.sequence); + writeSlice(hashOutputs); + writeUInt32(this.locktime); + writeUInt32(hashType); + return bcrypto.hash256(tbuffer); } - getHash (forWitness?: boolean): Buffer { + getHash(forWitness?: boolean): Buffer { // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0) - return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)) + if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); } - getId (): string { + getId(): string { // transaction hash's are displayed in reverse order - return reverseBuffer(this.getHash(false)).toString('hex') + return reverseBuffer(this.getHash(false)).toString('hex'); } - toBuffer (buffer?: Buffer, initialOffset?: number): Buffer { - return this.__toBuffer(buffer, initialOffset, true) + toBuffer(buffer?: Buffer, initialOffset?: number): Buffer { + return this.__toBuffer(buffer, initialOffset, true); } - private __toBuffer (buffer?: Buffer, initialOffset?: number, __allowWitness?: boolean): Buffer { - if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness!)) + private __toBuffer( + buffer?: Buffer, + initialOffset?: number, + __allowWitness?: boolean, + ): Buffer { + if (!buffer) + buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness!)); - let offset = initialOffset || 0 + let offset = initialOffset || 0; - function writeSlice (slice: Buffer): void { - offset += slice.copy(buffer!, offset) + function writeSlice(slice: Buffer): void { + offset += slice.copy(buffer!, offset); } - function writeUInt8 (i: number) { - offset = (buffer!).writeUInt8(i, offset) + function writeUInt8(i: number) { + offset = buffer!.writeUInt8(i, offset); } - function writeUInt32 (i: number) { - offset = (buffer!).writeUInt32LE(i, offset) + function writeUInt32(i: number) { + offset = buffer!.writeUInt32LE(i, offset); } - function writeInt32 (i: number) { - offset = (buffer!).writeInt32LE(i, offset) + function writeInt32(i: number) { + offset = buffer!.writeInt32LE(i, offset); } - function writeUInt64 (i: number) { - offset = bufferutils.writeUInt64LE(buffer!, i, offset) + function writeUInt64(i: number) { + offset = bufferutils.writeUInt64LE(buffer!, i, offset); } - function writeVarInt (i: number) { - varuint.encode(i, buffer, offset) - offset += varuint.encode.bytes + function writeVarInt(i: number) { + varuint.encode(i, buffer, offset); + offset += varuint.encode.bytes; } - function writeVarSlice (slice: Buffer) { - writeVarInt(slice.length) - writeSlice(slice) + function writeVarSlice(slice: Buffer) { + writeVarInt(slice.length); + writeSlice(slice); } - function writeVector (vector: Array) { - writeVarInt(vector.length) - vector.forEach(writeVarSlice) + function writeVector(vector: Array) { + writeVarInt(vector.length); + vector.forEach(writeVarSlice); } - writeInt32(this.version) + writeInt32(this.version); - const hasWitnesses = __allowWitness && this.hasWitnesses() + const hasWitnesses = __allowWitness && this.hasWitnesses(); if (hasWitnesses) { - writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) - writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); } - writeVarInt(this.ins.length) + writeVarInt(this.ins.length); - this.ins.forEach((txIn) => { - writeSlice(txIn.hash) - writeUInt32(txIn.index) - writeVarSlice(txIn.script) - writeUInt32(txIn.sequence) - }) + this.ins.forEach(txIn => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + writeVarSlice(txIn.script); + writeUInt32(txIn.sequence); + }); - writeVarInt(this.outs.length) - this.outs.forEach((txOut) => { + writeVarInt(this.outs.length); + this.outs.forEach(txOut => { if (isOutput(txOut)) { - writeUInt64(txOut.value) + writeUInt64(txOut.value); } else { - writeSlice(txOut.valueBuffer) + writeSlice(txOut.valueBuffer); } - writeVarSlice(txOut.script) - }) + writeVarSlice(txOut.script); + }); if (hasWitnesses) { - this.ins.forEach((input) => { - writeVector(input.witness) - }) + this.ins.forEach(input => { + writeVector(input.witness); + }); } - writeUInt32(this.locktime) + writeUInt32(this.locktime); // avoid slicing unless necessary - if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) - return buffer + if (initialOffset !== undefined) return buffer.slice(initialOffset, offset); + return buffer; } - toHex () { - return this.toBuffer(undefined, undefined).toString('hex') + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); } - setInputScript (index: number, scriptSig: Buffer) { - typeforce(types.tuple(types.Number, types.Buffer), arguments) + setInputScript(index: number, scriptSig: Buffer) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); - this.ins[index].script = scriptSig + this.ins[index].script = scriptSig; } - setWitness (index: number, witness: Array) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments) + setWitness(index: number, witness: Array) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - this.ins[index].witness = witness + this.ins[index].witness = witness; } } diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 969462c..a3bd9e6 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -1,458 +1,528 @@ -import { Network } from './networks' -import * as networks from './networks' -import { reverseBuffer } from './bufferutils' -import { Transaction, Output } from './transaction' -import { ECPairInterface } from './ecpair' -import * as ECPair from './ecpair' -import * as types from './types' -import * as baddress from './address' -import * as bcrypto from './crypto' -import * as bscript from './script' -import { Payment } from './payments' -import * as payments from './payments' -import * as classify from './classify' -import { OPS as ops } from './script' -const typeforce = require('typeforce') - -const SCRIPT_TYPES = classify.types - -type TxbSignatures = Array | Array -type TxbPubkeys = Array -type TxbWitness = Array -type TxbScriptType = string -type TxbScript = Buffer +import { Network } from './networks'; +import * as networks from './networks'; +import { reverseBuffer } from './bufferutils'; +import { Transaction, Output } from './transaction'; +import { ECPairInterface } from './ecpair'; +import * as ECPair from './ecpair'; +import * as types from './types'; +import * as baddress from './address'; +import * as bcrypto from './crypto'; +import * as bscript from './script'; +import { Payment } from './payments'; +import * as payments from './payments'; +import * as classify from './classify'; +import { OPS as ops } from './script'; +const typeforce = require('typeforce'); + +const SCRIPT_TYPES = classify.types; + +type TxbSignatures = Array | Array; +type TxbPubkeys = Array; +type TxbWitness = Array; +type TxbScriptType = string; +type TxbScript = Buffer; interface TxbInput { - value?: number - hasWitness?: boolean - signScript?: TxbScript - signType?: TxbScriptType - prevOutScript?: TxbScript - redeemScript?: TxbScript - redeemScriptType?: TxbScriptType - prevOutType?: TxbScriptType - pubkeys?: TxbPubkeys - signatures?: TxbSignatures - witness?: TxbWitness - witnessScript?: TxbScript - witnessScriptType?: TxbScriptType - script?: TxbScript - sequence?: number - scriptSig?: TxbScript - maxSignatures?: number + value?: number; + hasWitness?: boolean; + signScript?: TxbScript; + signType?: TxbScriptType; + prevOutScript?: TxbScript; + redeemScript?: TxbScript; + redeemScriptType?: TxbScriptType; + prevOutType?: TxbScriptType; + pubkeys?: TxbPubkeys; + signatures?: TxbSignatures; + witness?: TxbWitness; + witnessScript?: TxbScript; + witnessScriptType?: TxbScriptType; + script?: TxbScript; + sequence?: number; + scriptSig?: TxbScript; + maxSignatures?: number; } interface TxbOutput { - type: string - pubkeys?: TxbPubkeys - signatures?: TxbSignatures - maxSignatures?: number + type: string; + pubkeys?: TxbPubkeys; + signatures?: TxbSignatures; + maxSignatures?: number; } function txIsString(tx: Buffer | string | Transaction): tx is string { - return typeof tx === 'string' || tx instanceof String + return typeof tx === 'string' || tx instanceof String; } function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { - return tx instanceof Transaction + return tx instanceof Transaction; } export class TransactionBuilder { - network: Network - maximumFeeRate: number - private __prevTxSet: { [index: string]: boolean } - private __inputs: Array - private __tx: Transaction + network: Network; + maximumFeeRate: number; + private __prevTxSet: { [index: string]: boolean }; + private __inputs: Array; + private __tx: Transaction; - constructor (network?: Network, maximumFeeRate?: number) { - this.__prevTxSet = {} - this.network = network || networks.bitcoin + constructor(network?: Network, maximumFeeRate?: number) { + this.__prevTxSet = {}; + this.network = network || networks.bitcoin; // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500 + this.maximumFeeRate = maximumFeeRate || 2500; - this.__inputs = [] - this.__tx = new Transaction() - this.__tx.version = 2 + this.__inputs = []; + this.__tx = new Transaction(); + this.__tx.version = 2; } - static fromTransaction (transaction: Transaction, network?: Network): TransactionBuilder { - const txb = new TransactionBuilder(network) + static fromTransaction( + transaction: Transaction, + network?: Network, + ): TransactionBuilder { + const txb = new TransactionBuilder(network); // Copy transaction fields - txb.setVersion(transaction.version) - txb.setLockTime(transaction.locktime) + txb.setVersion(transaction.version); + txb.setLockTime(transaction.locktime); // Copy outputs (done first to avoid signature invalidation) transaction.outs.forEach(txOut => { - txb.addOutput(txOut.script, (txOut).value) - }) + txb.addOutput(txOut.script, (txOut).value); + }); // Copy inputs transaction.ins.forEach(txIn => { txb.__addInputUnsafe(txIn.hash, txIn.index, { sequence: txIn.sequence, script: txIn.script, - witness: txIn.witness - }) - }) + witness: txIn.witness, + }); + }); // fix some things not possible through the public API txb.__inputs.forEach((input, i) => { - fixMultisigOrder(input, transaction, i) - }) + fixMultisigOrder(input, transaction, i); + }); - return txb + return txb; } - setLockTime (locktime: number): void { - typeforce(types.UInt32, locktime) + setLockTime(locktime: number): void { + typeforce(types.UInt32, locktime); // if any signatures exist, throw - if (this.__inputs.some(input => { - if (!input.signatures) return false + if ( + this.__inputs.some(input => { + if (!input.signatures) return false; - return input.signatures.some(s => s !== undefined) - })) { - throw new Error('No, this would invalidate signatures') + return input.signatures.some(s => s !== undefined); + }) + ) { + throw new Error('No, this would invalidate signatures'); } - this.__tx.locktime = locktime + this.__tx.locktime = locktime; } - setVersion (version: number): void { - typeforce(types.UInt32, version) + setVersion(version: number): void { + typeforce(types.UInt32, version); // XXX: this might eventually become more complex depending on what the versions represent - this.__tx.version = version + this.__tx.version = version; } - addInput (txHash: Buffer | string | Transaction, vout: number, sequence: number, prevOutScript: Buffer): number { + addInput( + txHash: Buffer | string | Transaction, + vout: number, + sequence: number, + prevOutScript: Buffer, + ): number { if (!this.__canModifyInputs()) { - throw new Error('No, this would invalidate signatures') + throw new Error('No, this would invalidate signatures'); } - let value: number | undefined = undefined + let value: number | undefined = undefined; // is it a hex string? if (txIsString(txHash)) { // transaction hashs's are displayed in reverse order, un-reverse it - txHash = reverseBuffer(Buffer.from(txHash, 'hex')) + txHash = reverseBuffer(Buffer.from(txHash, 'hex')); - // is it a Transaction object? + // is it a Transaction object? } else if (txIsTransaction(txHash)) { - const txOut = txHash.outs[vout] - prevOutScript = txOut.script - value = (txOut).value + const txOut = txHash.outs[vout]; + prevOutScript = txOut.script; + value = (txOut).value; - txHash = txHash.getHash(false) + txHash = txHash.getHash(false); } return this.__addInputUnsafe(txHash, vout, { sequence: sequence, prevOutScript: prevOutScript, - value: value - }) + value: value, + }); } - private __addInputUnsafe (txHash: Buffer, vout: number, options: TxbInput): number { + private __addInputUnsafe( + txHash: Buffer, + vout: number, + options: TxbInput, + ): number { if (Transaction.isCoinbaseHash(txHash)) { - throw new Error('coinbase inputs not supported') + throw new Error('coinbase inputs not supported'); } - const prevTxOut = txHash.toString('hex') + ':' + vout - if (this.__prevTxSet[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut) + const prevTxOut = txHash.toString('hex') + ':' + vout; + if (this.__prevTxSet[prevTxOut] !== undefined) + throw new Error('Duplicate TxOut: ' + prevTxOut); - let input = {} + let input = {}; // derive what we can from the scriptSig if (options.script !== undefined) { - input = expandInput(options.script, options.witness || []) + input = expandInput(options.script, options.witness || []); } // if an input value was given, retain it if (options.value !== undefined) { - input.value = options.value + input.value = options.value; } // derive what we can from the previous transactions output script if (!input.prevOutScript && options.prevOutScript) { - let prevOutType + let prevOutType; if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript) + const expanded = expandOutput(options.prevOutScript); if (expanded.pubkeys) { - input.pubkeys = expanded.pubkeys - input.signatures = expanded.signatures + input.pubkeys = expanded.pubkeys; + input.signatures = expanded.signatures; } - prevOutType = expanded.type + prevOutType = expanded.type; } - input.prevOutScript = options.prevOutScript - input.prevOutType = prevOutType || classify.output(options.prevOutScript) + input.prevOutScript = options.prevOutScript; + input.prevOutType = prevOutType || classify.output(options.prevOutScript); } - const vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig) - this.__inputs[vin] = input - this.__prevTxSet[prevTxOut] = true - return vin + const vin = this.__tx.addInput( + txHash, + vout, + options.sequence, + options.scriptSig, + ); + this.__inputs[vin] = input; + this.__prevTxSet[prevTxOut] = true; + return vin; } - addOutput (scriptPubKey: string | Buffer, value: number): number { + addOutput(scriptPubKey: string | Buffer, value: number): number { if (!this.__canModifyOutputs()) { - throw new Error('No, this would invalidate signatures') + throw new Error('No, this would invalidate signatures'); } // Attempt to get a script if it's a base58 or bech32 address string if (typeof scriptPubKey === 'string') { - scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network) + scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); } - return this.__tx.addOutput(scriptPubKey, value) + return this.__tx.addOutput(scriptPubKey, value); } - build (): Transaction { - return this.__build(false) + build(): Transaction { + return this.__build(false); } - buildIncomplete (): Transaction { - return this.__build(true) + buildIncomplete(): Transaction { + return this.__build(true); } - private __build (allowIncomplete?: boolean): Transaction { + private __build(allowIncomplete?: boolean): Transaction { if (!allowIncomplete) { - if (!this.__tx.ins.length) throw new Error('Transaction has no inputs') - if (!this.__tx.outs.length) throw new Error('Transaction has no outputs') + if (!this.__tx.ins.length) throw new Error('Transaction has no inputs'); + if (!this.__tx.outs.length) throw new Error('Transaction has no outputs'); } - const tx = this.__tx.clone() + const tx = this.__tx.clone(); // create script signatures from inputs this.__inputs.forEach((input, i) => { - if (!input.prevOutType && !allowIncomplete) throw new Error('Transaction is not complete') + if (!input.prevOutType && !allowIncomplete) + throw new Error('Transaction is not complete'); - const result = build(input.prevOutType!, input, allowIncomplete) + const result = build(input.prevOutType!, input, allowIncomplete); if (!result) { - if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) throw new Error('Unknown input type') - if (!allowIncomplete) throw new Error('Not enough information') - return + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) + throw new Error('Unknown input type'); + if (!allowIncomplete) throw new Error('Not enough information'); + return; } - tx.setInputScript(i, result.input!) - tx.setWitness(i, result.witness!) - }) + tx.setInputScript(i, result.input!); + tx.setWitness(i, result.witness!); + }); if (!allowIncomplete) { // do not rely on this, its merely a last resort if (this.__overMaximumFees(tx.virtualSize())) { - throw new Error('Transaction has absurd fees') + throw new Error('Transaction has absurd fees'); } } - return tx + return tx; } - sign (vin: number, keyPair: ECPairInterface, redeemScript: Buffer, hashType: number, witnessValue: number, witnessScript: Buffer) { + sign( + vin: number, + keyPair: ECPairInterface, + redeemScript: Buffer, + hashType: number, + witnessValue: number, + witnessScript: Buffer, + ) { // TODO: remove keyPair.network matching in 4.0.0 - if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network') - if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin) + if (keyPair.network && keyPair.network !== this.network) + throw new TypeError('Inconsistent network'); + if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin); - hashType = hashType || Transaction.SIGHASH_ALL - if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs') + hashType = hashType || Transaction.SIGHASH_ALL; + if (this.__needsOutputs(hashType)) + throw new Error('Transaction needs outputs'); - const input = this.__inputs[vin] + const input = this.__inputs[vin]; // if redeemScript was previously provided, enforce consistency - if (input.redeemScript !== undefined && - redeemScript && - !input.redeemScript.equals(redeemScript)) { - throw new Error('Inconsistent redeemScript') + if ( + input.redeemScript !== undefined && + redeemScript && + !input.redeemScript.equals(redeemScript) + ) { + throw new Error('Inconsistent redeemScript'); } - const ourPubKey = keyPair.publicKey || keyPair.getPublicKey!() + const ourPubKey = keyPair.publicKey || keyPair.getPublicKey!(); if (!canSign(input)) { if (witnessValue !== undefined) { - if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue') - typeforce(types.Satoshi, witnessValue) - input.value = witnessValue + if (input.value !== undefined && input.value !== witnessValue) + throw new Error("Input didn't match witnessValue"); + typeforce(types.Satoshi, witnessValue); + input.value = witnessValue; } if (!canSign(input)) { - const prepared = prepareInput(input, ourPubKey, redeemScript, witnessScript) + const prepared = prepareInput( + input, + ourPubKey, + redeemScript, + witnessScript, + ); // updates inline - Object.assign(input, prepared) + Object.assign(input, prepared); } - if (!canSign(input)) throw Error(input.prevOutType + ' not supported') + if (!canSign(input)) throw Error(input.prevOutType + ' not supported'); } // ready to sign - let signatureHash: Buffer + let signatureHash: Buffer; if (input.hasWitness) { - signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType) + signatureHash = this.__tx.hashForWitnessV0( + vin, + input.signScript, + input.value, + hashType, + ); } else { - signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType) + signatureHash = this.__tx.hashForSignature( + vin, + input.signScript, + hashType, + ); } // enforce in order signing of public keys const signed = input.pubkeys!.some((pubKey, i) => { - if (!ourPubKey.equals(pubKey!)) return false - if (input.signatures![i]) throw new Error('Signature already exists') + if (!ourPubKey.equals(pubKey!)) return false; + if (input.signatures![i]) throw new Error('Signature already exists'); // TODO: add tests if (ourPubKey.length !== 33 && input.hasWitness) { - throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH') + throw new Error( + 'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH', + ); } - const signature = keyPair.sign(signatureHash) - input.signatures![i] = bscript.signature.encode(signature, hashType) - return true - }) + const signature = keyPair.sign(signatureHash); + input.signatures![i] = bscript.signature.encode(signature, hashType); + return true; + }); - if (!signed) throw new Error('Key pair cannot sign for this input') + if (!signed) throw new Error('Key pair cannot sign for this input'); } - private __canModifyInputs (): boolean { + private __canModifyInputs(): boolean { return this.__inputs.every(input => { - if (!input.signatures) return true + if (!input.signatures) return true; return input.signatures.every(signature => { - if (!signature) return true - const hashType = signatureHashType(signature) + if (!signature) return true; + const hashType = signatureHashType(signature); // if SIGHASH_ANYONECANPAY is set, signatures would not // be invalidated by more inputs - return (hashType & Transaction.SIGHASH_ANYONECANPAY) !== 0 - }) - }) + return (hashType & Transaction.SIGHASH_ANYONECANPAY) !== 0; + }); + }); } - private __needsOutputs (signingHashType: number): boolean { + private __needsOutputs(signingHashType: number): boolean { if (signingHashType === Transaction.SIGHASH_ALL) { - return this.__tx.outs.length === 0 + return this.__tx.outs.length === 0; } // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // .build() will fail, but .buildIncomplete() is OK - return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { - if (!input.signatures) return false - - return input.signatures.some((signature) => { - if (!signature) return false // no signature, no issue - const hashType = signatureHashType(signature) - if (hashType & Transaction.SIGHASH_NONE) return false // SIGHASH_NONE doesn't care about outputs - return true // SIGHASH_* does care + return ( + this.__tx.outs.length === 0 && + this.__inputs.some(input => { + if (!input.signatures) return false; + + return input.signatures.some(signature => { + if (!signature) return false; // no signature, no issue + const hashType = signatureHashType(signature); + if (hashType & Transaction.SIGHASH_NONE) return false; // SIGHASH_NONE doesn't care about outputs + return true; // SIGHASH_* does care + }); }) - }) + ); } - private __canModifyOutputs (): boolean { - const nInputs = this.__tx.ins.length - const nOutputs = this.__tx.outs.length + private __canModifyOutputs(): boolean { + const nInputs = this.__tx.ins.length; + const nOutputs = this.__tx.outs.length; return this.__inputs.every(input => { - if (input.signatures === undefined) return true + if (input.signatures === undefined) return true; return input.signatures.every(signature => { - if (!signature) return true - const hashType = signatureHashType(signature) + if (!signature) return true; + const hashType = signatureHashType(signature); - const hashTypeMod = hashType & 0x1f - if (hashTypeMod === Transaction.SIGHASH_NONE) return true + const hashTypeMod = hashType & 0x1f; + if (hashTypeMod === Transaction.SIGHASH_NONE) return true; if (hashTypeMod === Transaction.SIGHASH_SINGLE) { // if SIGHASH_SINGLE is set, and nInputs > nOutputs // some signatures would be invalidated by the addition // of more outputs - return nInputs <= nOutputs + return nInputs <= nOutputs; } - return false - }) - }) + return false; + }); + }); } - private __overMaximumFees (bytes: number): boolean { + private __overMaximumFees(bytes: number): boolean { // not all inputs will have .value defined - const incoming = this.__inputs.reduce((a, x) => a + (x.value! >>> 0), 0) + const incoming = this.__inputs.reduce((a, x) => a + (x.value! >>> 0), 0); // but all outputs do, and if we have any input value // we can immediately determine if the outputs are too small - const outgoing = this.__tx.outs.reduce((a, x) => a + (x).value, 0) - const fee = incoming - outgoing - const feeRate = fee / bytes + const outgoing = this.__tx.outs.reduce((a, x) => a + (x).value, 0); + const fee = incoming - outgoing; + const feeRate = fee / bytes; - return feeRate > this.maximumFeeRate + return feeRate > this.maximumFeeRate; } } -function expandInput (scriptSig: Buffer, witnessStack: Array, type?: string, scriptPubKey?: Buffer): TxbInput { - if (scriptSig.length === 0 && witnessStack.length === 0) return {} +function expandInput( + scriptSig: Buffer, + witnessStack: Array, + type?: string, + scriptPubKey?: Buffer, +): TxbInput { + if (scriptSig.length === 0 && witnessStack.length === 0) return {}; if (!type) { - let ssType: string | undefined = classify.input(scriptSig, true) - let wsType: string | undefined = classify.witness(witnessStack, true) - if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined - if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined - type = ssType || wsType + let ssType: string | undefined = classify.input(scriptSig, true); + let wsType: string | undefined = classify.witness(witnessStack, true); + if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined; + if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined; + type = ssType || wsType; } switch (type) { case SCRIPT_TYPES.P2WPKH: { - const { output, pubkey, signature } = payments.p2wpkh({ witness: witnessStack }) + const { output, pubkey, signature } = payments.p2wpkh({ + witness: witnessStack, + }); return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2WPKH, pubkeys: [pubkey], - signatures: [signature] - } + signatures: [signature], + }; } case SCRIPT_TYPES.P2PKH: { - const { output, pubkey, signature } = payments.p2pkh({ input: scriptSig }) + const { output, pubkey, signature } = payments.p2pkh({ + input: scriptSig, + }); return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2PKH, pubkeys: [pubkey], - signatures: [signature] - } + signatures: [signature], + }; } case SCRIPT_TYPES.P2PK: { - const { signature } = payments.p2pk({ input: scriptSig }) + const { signature } = payments.p2pk({ input: scriptSig }); return { prevOutType: SCRIPT_TYPES.P2PK, pubkeys: [undefined], - signatures: [signature] - } + signatures: [signature], + }; } case SCRIPT_TYPES.P2MS: { - const { m, pubkeys, signatures } = payments.p2ms({ - input: scriptSig, - output: scriptPubKey - }, { allowIncomplete: true }) + const { m, pubkeys, signatures } = payments.p2ms( + { + input: scriptSig, + output: scriptPubKey, + }, + { allowIncomplete: true }, + ); return { prevOutType: SCRIPT_TYPES.P2MS, pubkeys: pubkeys, signatures: signatures, - maxSignatures: m - } + maxSignatures: m, + }; } } if (type === SCRIPT_TYPES.P2SH) { const { output, redeem } = payments.p2sh({ input: scriptSig, - witness: witnessStack - }) - - const outputType = classify.output(redeem!.output!) - const expanded = expandInput(redeem!.input!, redeem!.witness!, outputType, redeem!.output) - if (!expanded.prevOutType) return {} + witness: witnessStack, + }); + + const outputType = classify.output(redeem!.output!); + const expanded = expandInput( + redeem!.input!, + redeem!.witness!, + outputType, + redeem!.output, + ); + if (!expanded.prevOutType) return {}; return { prevOutScript: output, @@ -463,23 +533,28 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str witnessScriptType: expanded.witnessScriptType, pubkeys: expanded.pubkeys, - signatures: expanded.signatures - } + signatures: expanded.signatures, + }; } if (type === SCRIPT_TYPES.P2WSH) { const { output, redeem } = payments.p2wsh({ input: scriptSig, - witness: witnessStack - }) - const outputType = classify.output(redeem!.output!) - let expanded + witness: witnessStack, + }); + const outputType = classify.output(redeem!.output!); + let expanded; if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput(redeem!.input!, redeem!.witness!, outputType) + expanded = expandInput(redeem!.input!, redeem!.witness!, outputType); } else { - expanded = expandInput(bscript.compile(redeem!.witness!), [], outputType, redeem!.output) + expanded = expandInput( + bscript.compile(redeem!.witness!), + [], + outputType, + redeem!.output, + ); } - if (!expanded.prevOutType) return {} + if (!expanded.prevOutType) return {}; return { prevOutScript: output, @@ -488,127 +563,152 @@ function expandInput (scriptSig: Buffer, witnessStack: Array, type?: str witnessScriptType: expanded.prevOutType, pubkeys: expanded.pubkeys, - signatures: expanded.signatures - } + signatures: expanded.signatures, + }; } return { prevOutType: SCRIPT_TYPES.NONSTANDARD, - prevOutScript: scriptSig - } + prevOutScript: scriptSig, + }; } // could be done in expandInput, but requires the original Transaction for hashForSignature -function fixMultisigOrder (input: TxbInput, transaction: Transaction, vin: number): void { - if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return - if (input.pubkeys!.length === input.signatures!.length) return +function fixMultisigOrder( + input: TxbInput, + transaction: Transaction, + vin: number, +): void { + if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) + return; + if (input.pubkeys!.length === input.signatures!.length) return; - const unmatched = input.signatures!.concat() + const unmatched = input.signatures!.concat(); input.signatures = input.pubkeys!.map(pubKey => { - const keyPair = ECPair.fromPublicKey(pubKey!) - let match: Buffer | undefined + const keyPair = ECPair.fromPublicKey(pubKey!); + let match: Buffer | undefined; // check for a signature unmatched.some((signature, i) => { // skip if undefined || OP_0 - if (!signature) return false + if (!signature) return false; // TODO: avoid O(n) hashForSignature - const parsed = bscript.signature.decode(signature) - const hash = transaction.hashForSignature(vin, input.redeemScript!, parsed.hashType) + const parsed = bscript.signature.decode(signature); + const hash = transaction.hashForSignature( + vin, + input.redeemScript!, + parsed.hashType, + ); // skip if signature does not match pubKey - if (!keyPair.verify(hash, parsed.signature)) return false + if (!keyPair.verify(hash, parsed.signature)) return false; // remove matched signature from unmatched - unmatched[i] = undefined - match = signature + unmatched[i] = undefined; + match = signature; - return true - }) + return true; + }); - return match - }) + return match; + }); } -function expandOutput (script: Buffer, ourPubKey?: Buffer): TxbOutput { - typeforce(types.Buffer, script) - const type = classify.output(script) +function expandOutput(script: Buffer, ourPubKey?: Buffer): TxbOutput { + typeforce(types.Buffer, script); + const type = classify.output(script); switch (type) { case SCRIPT_TYPES.P2PKH: { - if (!ourPubKey) return { type } + if (!ourPubKey) return { type }; // does our hash160(pubKey) match the output scripts? - const pkh1 = payments.p2pkh({ output: script }).hash - const pkh2 = bcrypto.hash160(ourPubKey) - if (!pkh1!.equals(pkh2)) return { type } + const pkh1 = payments.p2pkh({ output: script }).hash; + const pkh2 = bcrypto.hash160(ourPubKey); + if (!pkh1!.equals(pkh2)) return { type }; return { type, pubkeys: [ourPubKey], - signatures: [undefined] - } + signatures: [undefined], + }; } case SCRIPT_TYPES.P2WPKH: { - if (!ourPubKey) return { type } + if (!ourPubKey) return { type }; // does our hash160(pubKey) match the output scripts? - const wpkh1 = payments.p2wpkh({ output: script }).hash - const wpkh2 = bcrypto.hash160(ourPubKey) - if (!wpkh1!.equals(wpkh2)) return { type } + const wpkh1 = payments.p2wpkh({ output: script }).hash; + const wpkh2 = bcrypto.hash160(ourPubKey); + if (!wpkh1!.equals(wpkh2)) return { type }; return { type, pubkeys: [ourPubKey], - signatures: [undefined] - } + signatures: [undefined], + }; } case SCRIPT_TYPES.P2PK: { - const p2pk = payments.p2pk({ output: script }) + const p2pk = payments.p2pk({ output: script }); return { type, pubkeys: [p2pk.pubkey], - signatures: [undefined] - } + signatures: [undefined], + }; } case SCRIPT_TYPES.P2MS: { - const p2ms = payments.p2ms({ output: script }) + const p2ms = payments.p2ms({ output: script }); return { type, pubkeys: p2ms.pubkeys, signatures: p2ms.pubkeys!.map((): undefined => undefined), - maxSignatures: p2ms.m - } + maxSignatures: p2ms.m, + }; } } - return { type } + return { type }; } -function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, witnessScript: Buffer): TxbInput { +function prepareInput( + input: TxbInput, + ourPubKey: Buffer, + redeemScript: Buffer, + witnessScript: Buffer, +): TxbInput { if (redeemScript && witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) - const p2wshAlt = payments.p2wsh({ output: redeemScript }) - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) - const p2shAlt = payments.p2sh({ redeem: p2wsh }) + const p2wsh = ( + payments.p2wsh({ redeem: { output: witnessScript } }) + ); + const p2wshAlt = payments.p2wsh({ output: redeemScript }); + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + const p2shAlt = payments.p2sh({ redeem: p2wsh }); // enforces P2SH(P2WSH(...)) - if (!p2wsh.hash!.equals(p2wshAlt.hash!)) throw new Error('Witness script inconsistent with prevOutScript') - if (!p2sh.hash!.equals(p2shAlt.hash!)) throw new Error('Redeem script inconsistent with prevOutScript') - - const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey) - if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') + if (!p2wsh.hash!.equals(p2wshAlt.hash!)) + throw new Error('Witness script inconsistent with prevOutScript'); + if (!p2sh.hash!.equals(p2shAlt.hash!)) + throw new Error('Redeem script inconsistent with prevOutScript'); + + const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')', + ); if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures + expanded.signatures = input.signatures; } - let signScript = witnessScript - if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure') + let signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); return { redeemScript, @@ -626,30 +726,39 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures - } + maxSignatures: expanded.maxSignatures, + }; } if (redeemScript) { - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); if (input.prevOutScript) { - let p2shAlt + let p2shAlt; try { - p2shAlt = payments.p2sh({ output: input.prevOutScript }) - } catch (e) { throw new Error('PrevOutScript must be P2SH') } - if (!p2sh.hash!.equals(p2shAlt.hash!)) throw new Error('Redeem script inconsistent with prevOutScript') - } - - const expanded = expandOutput(p2sh.redeem!.output!, ourPubKey) - if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')') + p2shAlt = payments.p2sh({ output: input.prevOutScript }); + } catch (e) { + throw new Error('PrevOutScript must be P2SH'); + } + if (!p2sh.hash!.equals(p2shAlt.hash!)) + throw new Error('Redeem script inconsistent with prevOutScript'); + } + + const expanded = expandOutput(p2sh.redeem!.output!, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as redeemScript (' + + bscript.toASM(redeemScript) + + ')', + ); if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures + expanded.signatures = input.signatures; } - let signScript = redeemScript + let signScript = redeemScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output! + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output!; } return { @@ -665,26 +774,34 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures - } + maxSignatures: expanded.maxSignatures, + }; } if (witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }) + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); if (input.prevOutScript) { - const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }) - if (!p2wsh.hash!.equals(p2wshAlt.hash!)) throw new Error('Witness script inconsistent with prevOutScript') - } - - const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey) - if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')') + const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }); + if (!p2wsh.hash!.equals(p2wshAlt.hash!)) + throw new Error('Witness script inconsistent with prevOutScript'); + } + + const expanded = expandOutput(p2wsh.redeem!.output!, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')', + ); if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures + expanded.signatures = input.signatures; } - let signScript = witnessScript - if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2WSH(P2WPKH) is a consensus failure') + let signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2WSH(P2WPKH) is a consensus failure'); return { witnessScript, @@ -699,25 +816,39 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures - } + maxSignatures: expanded.maxSignatures, + }; } if (input.prevOutType && input.prevOutScript) { // embedded scripts are not possible without extra information - if (input.prevOutType === SCRIPT_TYPES.P2SH) throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript') - if (input.prevOutType === SCRIPT_TYPES.P2WSH) throw new Error('PrevOutScript is ' + input.prevOutType + ', requires witnessScript') - if (!input.prevOutScript) throw new Error('PrevOutScript is missing') - - const expanded = expandOutput(input.prevOutScript, ourPubKey) - if (!expanded.pubkeys) throw new Error(expanded.type + ' not supported (' + bscript.toASM(input.prevOutScript) + ')') + if (input.prevOutType === SCRIPT_TYPES.P2SH) + throw new Error( + 'PrevOutScript is ' + input.prevOutType + ', requires redeemScript', + ); + if (input.prevOutType === SCRIPT_TYPES.P2WSH) + throw new Error( + 'PrevOutScript is ' + input.prevOutType + ', requires witnessScript', + ); + if (!input.prevOutScript) throw new Error('PrevOutScript is missing'); + + const expanded = expandOutput(input.prevOutScript, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported (' + + bscript.toASM(input.prevOutScript) + + ')', + ); if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures + expanded.signatures = input.signatures; } - let signScript = input.prevOutScript + let signScript = input.prevOutScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output + signScript = ( + payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output + ); } return { @@ -730,11 +861,11 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures - } + maxSignatures: expanded.maxSignatures, + }; } - const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output + const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; return { prevOutType: SCRIPT_TYPES.P2PKH, prevOutScript: prevOutScript, @@ -744,86 +875,92 @@ function prepareInput (input: TxbInput, ourPubKey: Buffer, redeemScript: Buffer, signType: SCRIPT_TYPES.P2PKH, pubkeys: [ourPubKey], - signatures: [undefined] - } + signatures: [undefined], + }; } -function build (type: string, input: TxbInput, allowIncomplete?: boolean): Payment | undefined { - const pubkeys = >(input.pubkeys || []) - let signatures = >(input.signatures || []) +function build( + type: string, + input: TxbInput, + allowIncomplete?: boolean, +): Payment | undefined { + const pubkeys = >(input.pubkeys || []); + let signatures = >(input.signatures || []); switch (type) { case SCRIPT_TYPES.P2PKH: { - if (pubkeys.length === 0) break - if (signatures.length === 0) break + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; - return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }) + return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }); } case SCRIPT_TYPES.P2WPKH: { - if (pubkeys.length === 0) break - if (signatures.length === 0) break + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; - return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }) + return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }); } case SCRIPT_TYPES.P2PK: { - if (pubkeys.length === 0) break - if (signatures.length === 0) break + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; - return payments.p2pk({ signature: signatures[0] }) + return payments.p2pk({ signature: signatures[0] }); } case SCRIPT_TYPES.P2MS: { - const m = input.maxSignatures + const m = input.maxSignatures; if (allowIncomplete) { - signatures = signatures.map(x => x || ops.OP_0) + signatures = signatures.map(x => x || ops.OP_0); } else { - signatures = signatures.filter(x => x) + signatures = signatures.filter(x => x); } // if the transaction is not not complete (complete), or if signatures.length === m, validate // otherwise, the number of OP_0's may be >= m, so don't validate (boo) - const validate = !allowIncomplete || (m === signatures.length) - return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }) + const validate = !allowIncomplete || m === signatures.length; + return payments.p2ms( + { m, pubkeys, signatures }, + { allowIncomplete, validate }, + ); } case SCRIPT_TYPES.P2SH: { - const redeem = build(input.redeemScriptType!, input, allowIncomplete) - if (!redeem) return + const redeem = build(input.redeemScriptType!, input, allowIncomplete); + if (!redeem) return; return payments.p2sh({ redeem: { output: redeem.output || input.redeemScript, input: redeem.input, - witness: redeem.witness - } - }) + witness: redeem.witness, + }, + }); } case SCRIPT_TYPES.P2WSH: { - const redeem = build(input.witnessScriptType!, input, allowIncomplete) - if (!redeem) return + const redeem = build(input.witnessScriptType!, input, allowIncomplete); + if (!redeem) return; return payments.p2wsh({ redeem: { output: input.witnessScript, input: redeem.input, - witness: redeem.witness - } - }) + witness: redeem.witness, + }, + }); } } } -function canSign (input: TxbInput): boolean { - return input.signScript !== undefined && +function canSign(input: TxbInput): boolean { + return ( + input.signScript !== undefined && input.signType !== undefined && input.pubkeys !== undefined && input.signatures !== undefined && input.signatures.length === input.pubkeys.length && input.pubkeys.length > 0 && - ( - input.hasWitness === false || - input.value !== undefined - ) + (input.hasWitness === false || input.value !== undefined) + ); } -function signatureHashType (buffer: Buffer): number { - return buffer.readUInt8(buffer.length - 1) +function signatureHashType(buffer: Buffer): number { + return buffer.readUInt8(buffer.length - 1); } diff --git a/ts_src/types.ts b/ts_src/types.ts index 8eacbdc..42ddb40 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -1,49 +1,51 @@ -const typeforce = require('typeforce') +const typeforce = require('typeforce'); -const UINT31_MAX: number = Math.pow(2, 31) - 1 -export function UInt31 (value: number): boolean { - return typeforce.UInt32(value) && value <= UINT31_MAX +const UINT31_MAX: number = Math.pow(2, 31) - 1; +export function UInt31(value: number): boolean { + return typeforce.UInt32(value) && value <= UINT31_MAX; } -export function BIP32Path (value: string): boolean { - return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) +export function BIP32Path(value: string): boolean { + return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } -BIP32Path.toJSON = function () { return 'BIP32 derivation path' } +BIP32Path.toJSON = function() { + return 'BIP32 derivation path'; +}; -const SATOSHI_MAX: number = 21 * 1e14 -export function Satoshi (value: number): boolean { - return typeforce.UInt53(value) && value <= SATOSHI_MAX +const SATOSHI_MAX: number = 21 * 1e14; +export function Satoshi(value: number): boolean { + return typeforce.UInt53(value) && value <= SATOSHI_MAX; } // external dependent types -export const ECPoint = typeforce.quacksLike('Point') +export const ECPoint = typeforce.quacksLike('Point'); // exposed, external API export const Network = typeforce.compile({ messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), bip32: { public: typeforce.UInt32, - private: typeforce.UInt32 + private: typeforce.UInt32, }, pubKeyHash: typeforce.UInt8, scriptHash: typeforce.UInt8, - wif: typeforce.UInt8 -}) + wif: typeforce.UInt8, +}); -export const Buffer256bit = typeforce.BufferN(32) -export const Hash160bit = typeforce.BufferN(20) -export const Hash256bit = typeforce.BufferN(32) -export const Number = typeforce.Number -export const Array = typeforce.Array -export const Boolean = typeforce.Boolean -export const String = typeforce.String -export const Buffer = typeforce.Buffer -export const Hex = typeforce.Hex -export const maybe = typeforce.maybe -export const tuple = typeforce.tuple -export const UInt8 = typeforce.UInt8 -export const UInt32 = typeforce.UInt32 -export const Function = typeforce.Function -export const BufferN = typeforce.BufferN -export const Null = typeforce.Null -export const oneOf = typeforce.oneOf +export const Buffer256bit = typeforce.BufferN(32); +export const Hash160bit = typeforce.BufferN(20); +export const Hash256bit = typeforce.BufferN(32); +export const Number = typeforce.Number; +export const Array = typeforce.Array; +export const Boolean = typeforce.Boolean; +export const String = typeforce.String; +export const Buffer = typeforce.Buffer; +export const Hex = typeforce.Hex; +export const maybe = typeforce.maybe; +export const tuple = typeforce.tuple; +export const UInt8 = typeforce.UInt8; +export const UInt32 = typeforce.UInt32; +export const Function = typeforce.Function; +export const BufferN = typeforce.BufferN; +export const Null = typeforce.Null; +export const oneOf = typeforce.oneOf; From 6526000999dd4344faaa8e4f906d22cb617f751d Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sun, 3 Mar 2019 23:20:36 +0900 Subject: [PATCH 116/183] style: remove standard --- package.json | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index e55b1a8..b9eb8d8 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,9 @@ "nobuild:coverage-html": "nyc report --reporter=html", "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", "nobuild:integration": "mocha --timeout 50000 test/integration/", - "nobuild:standard": "standard ts_src/**/*.ts", "nobuild:unit": "mocha", "prepare": "npm run build", - "standard": "npm run build && npm run nobuild:standard", - "test": "npm run build && npm run nobuild:standard && npm run nobuild:coverage", + "test": "npm run build && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, "repository": { @@ -71,15 +69,8 @@ "nyc": "^11.8.0", "prettier": "^1.16.4", "proxyquire": "^2.0.1", - "standard": "^11.0.1", "typescript": "3.2.2", "typescript-eslint-parser": "^21.0.2" }, - "license": "MIT", - "standard": { - "parser": "typescript-eslint-parser", - "plugins": [ - "typescript" - ] - } + "license": "MIT" } From 0ad8fbc6ba35b1f24113d498e16182ae5155db72 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sun, 3 Mar 2019 23:31:17 +0900 Subject: [PATCH 117/183] style: add build output after applying prettier --- src/address.js | 3 +- src/block.js | 21 ++++--- src/classify.js | 2 +- src/crypto.js | 12 +++- src/ecpair.js | 13 +++-- src/networks.js | 12 ++-- src/payments/embed.js | 5 +- src/payments/lazy.js | 4 +- src/payments/p2ms.js | 10 ++-- src/payments/p2pk.js | 17 ++---- src/payments/p2pkh.js | 14 ++--- src/payments/p2sh.js | 24 +++----- src/payments/p2wpkh.js | 15 ++--- src/payments/p2wsh.js | 31 +++++----- src/script.js | 14 +++-- src/script_number.js | 19 +++--- src/script_signature.js | 9 +-- src/templates/nulldata.js | 7 ++- src/transaction.js | 62 ++++++++++---------- src/transaction_builder.js | 116 +++++++++++++++++++++---------------- src/types.js | 8 ++- types/index.d.ts | 2 +- 22 files changed, 217 insertions(+), 203 deletions(-) diff --git a/src/address.js b/src/address.js index ed11e5c..f12cd8d 100644 --- a/src/address.js +++ b/src/address.js @@ -25,7 +25,7 @@ function fromBech32(address) { return { version: result.words[0], prefix: result.prefix, - data: Buffer.from(data) + data: Buffer.from(data), }; } exports.fromBech32 = fromBech32; @@ -44,6 +44,7 @@ function toBech32(data, version, prefix) { } exports.toBech32 = toBech32; function fromOutputScript(output, network) { + //TODO: Network network = network || networks.bitcoin; try { return payments.p2pkh({ output, network }).address; diff --git a/src/block.js b/src/block.js index cb593ac..eb3fb8b 100644 --- a/src/block.js +++ b/src/block.js @@ -10,22 +10,22 @@ const varuint = require('varuint-bitcoin'); const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); function txesHaveWitnessCommit(transactions) { - return transactions instanceof Array && + return (transactions instanceof Array && transactions[0] && transactions[0].ins && transactions[0].ins instanceof Array && transactions[0].ins[0] && transactions[0].ins[0].witness && transactions[0].ins[0].witness instanceof Array && - transactions[0].ins[0].witness.length > 0; + transactions[0].ins[0].witness.length > 0); } function anyTxHasWitness(transactions) { - return transactions instanceof Array && + return (transactions instanceof Array && transactions.some(tx => typeof tx === 'object' && tx.ins instanceof Array && tx.ins.some(input => typeof input === 'object' && input.witness instanceof Array && - input.witness.length > 0)); + input.witness.length > 0))); } class Block { constructor() { @@ -116,9 +116,7 @@ class Block { // There is no rule for the index of the output, so use filter to find it. // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = this.transactions[0].outs - .filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))) - .map(out => out.script.slice(6, 38)); + let witnessCommits = this.transactions[0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))).map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) @@ -141,8 +139,9 @@ class Block { byteLength(headersOnly) { if (headersOnly || !this.transactions) return 80; - return 80 + varuint.encodingLength(this.transactions.length) + - this.transactions.reduce((a, x) => a + x.byteLength(), 0); + return (80 + + varuint.encodingLength(this.transactions.length) + + this.transactions.reduce((a, x) => a + x.byteLength(), 0)); } getHash() { return bcrypto.hash256(this.toBuffer(true)); @@ -197,8 +196,8 @@ class Block { let hasWitnessCommit = this.hasWitnessCommit(); if (!hasWitnessCommit && this.hasWitness()) return false; - return this.__checkMerkleRoot() && - (hasWitnessCommit ? this.__checkWitnessCommit() : true); + return (this.__checkMerkleRoot() && + (hasWitnessCommit ? this.__checkWitnessCommit() : true)); } checkMerkleRoot() { console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + diff --git a/src/classify.js b/src/classify.js index a2109c2..0aec5c4 100644 --- a/src/classify.js +++ b/src/classify.js @@ -18,7 +18,7 @@ const types = { P2SH: 'scripthash', P2WPKH: 'witnesspubkeyhash', P2WSH: 'witnessscripthash', - WITNESS_COMMITMENT: 'witnesscommitment' + WITNESS_COMMITMENT: 'witnesscommitment', }; exports.types = types; function classifyOutput(script) { diff --git a/src/crypto.js b/src/crypto.js index 4165d30..d494b86 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -2,15 +2,21 @@ Object.defineProperty(exports, "__esModule", { value: true }); const createHash = require('create-hash'); function ripemd160(buffer) { - return createHash('rmd160').update(buffer).digest(); + return createHash('rmd160') + .update(buffer) + .digest(); } exports.ripemd160 = ripemd160; function sha1(buffer) { - return createHash('sha1').update(buffer).digest(); + return createHash('sha1') + .update(buffer) + .digest(); } exports.sha1 = sha1; function sha256(buffer) { - return createHash('sha256').update(buffer).digest(); + return createHash('sha256') + .update(buffer) + .digest(); } exports.sha256 = sha256; function hash160(buffer) { diff --git a/src/ecpair.js b/src/ecpair.js index d4dc94f..7d376ac 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -8,13 +8,14 @@ const typeforce = require('typeforce'); const wif = require('wif'); const isOptions = typeforce.maybe(typeforce.compile({ compressed: types.maybe(types.Boolean), - network: types.maybe(types.Network) + network: types.maybe(types.Network), })); class ECPair { constructor(d, Q, options) { if (options === undefined) options = {}; - this.compressed = options.compressed === undefined ? true : options.compressed; + this.compressed = + options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.bitcoin; this.__d = undefined; this.__Q = undefined; @@ -64,9 +65,11 @@ function fromWIF(string, network) { const version = decoded.version; // list of networks? if (types.Array(network)) { - network = network.filter(function (x) { + network = network + .filter(function (x) { return version === x.wif; - }).pop(); + }) + .pop(); if (!network) throw new Error('Unknown network version'); // otherwise, assume a network object (or default to bitcoin) @@ -78,7 +81,7 @@ function fromWIF(string, network) { } return fromPrivateKey(decoded.privateKey, { compressed: decoded.compressed, - network: network + network: network, }); } exports.fromWIF = fromWIF; diff --git a/src/networks.js b/src/networks.js index 821cd96..298808d 100644 --- a/src/networks.js +++ b/src/networks.js @@ -5,31 +5,31 @@ exports.bitcoin = { bech32: 'bc', bip32: { public: 0x0488b21e, - private: 0x0488ade4 + private: 0x0488ade4, }, pubKeyHash: 0x00, scriptHash: 0x05, - wif: 0x80 + wif: 0x80, }; exports.regtest = { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'bcrt', bip32: { public: 0x043587cf, - private: 0x04358394 + private: 0x04358394, }, pubKeyHash: 0x6f, scriptHash: 0xc4, - wif: 0xef + wif: 0xef, }; exports.testnet = { messagePrefix: '\x18Bitcoin Signed Message:\n', bech32: 'tb', bip32: { public: 0x043587cf, - private: 0x04358394 + private: 0x04358394, }, pubKeyHash: 0x6f, scriptHash: 0xc4, - wif: 0xef + wif: 0xef, }; diff --git a/src/payments/embed.js b/src/payments/embed.js index 7d341ab..0e2a0ae 100644 --- a/src/payments/embed.js +++ b/src/payments/embed.js @@ -14,14 +14,13 @@ function stacksEqual(a, b) { } // output: OP_RETURN ... function p2data(a, opts) { - if (!a.data && - !a.output) + if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ network: typef.maybe(typef.Object), output: typef.maybe(typef.Buffer), - data: typef.maybe(typef.arrayOf(typef.Buffer)) + data: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); const network = a.network || networks_1.bitcoin; const o = { network }; diff --git a/src/payments/lazy.js b/src/payments/lazy.js index 2c848e1..9eda8e8 100644 --- a/src/payments/lazy.js +++ b/src/payments/lazy.js @@ -14,9 +14,9 @@ function prop(object, name, f) { configurable: true, enumerable: true, value: value, - writable: true + writable: true, }); - } + }, }); } exports.prop = prop; diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index a45bd48..4e3c115 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -24,9 +24,8 @@ function p2ms(a, opts) { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); function isAcceptableSignature(x) { - return bscript.isCanonicalScriptSignature(x) || - (opts.allowIncomplete && - (x === OPS.OP_0)) !== undefined; // eslint-disable-line + return (bscript.isCanonicalScriptSignature(x) || + (opts.allowIncomplete && x === OPS.OP_0) !== undefined); // eslint-disable-line } typef({ network: typef.maybe(typef.Object), @@ -35,7 +34,7 @@ function p2ms(a, opts) { output: typef.maybe(typef.Buffer), pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - input: typef.maybe(typef.Buffer) + input: typef.maybe(typef.Buffer), }, a); const network = a.network || networks_1.bitcoin; const o = { network }; @@ -131,7 +130,8 @@ function p2ms(a, opts) { if (a.input) { if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); - if (o.signatures.length === 0 || !o.signatures.every(isAcceptableSignature)) + if (o.signatures.length === 0 || + !o.signatures.every(isAcceptableSignature)) throw new TypeError('Input has invalid signature(s)'); if (a.signatures && !stacksEqual(a.signatures, o.signatures)) throw new TypeError('Signature mismatch'); diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index ab8654d..9c9318f 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -9,11 +9,7 @@ const ecc = require('tiny-secp256k1'); // input: {signature} // output: {pubKey} OP_CHECKSIG function p2pk(a, opts) { - if (!a.input && - !a.output && - !a.pubkey && - !a.input && - !a.signature) + if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ @@ -21,18 +17,17 @@ function p2pk(a, opts) { output: typef.maybe(typef.Buffer), pubkey: typef.maybe(ecc.isPoint), signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer) + input: typef.maybe(typef.Buffer), }, a); - const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const _chunks = lazy.value(function () { + return bscript.decompile(a.input); + }); const network = a.network || networks_1.bitcoin; const o = { network }; lazy.prop(o, 'output', function () { if (!a.pubkey) return; - return bscript.compile([ - a.pubkey, - OPS.OP_CHECKSIG - ]); + return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); }); lazy.prop(o, 'pubkey', function () { if (!a.output) diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 55f4817..6b41a77 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -11,11 +11,7 @@ const bs58check = require('bs58check'); // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG function p2pkh(a, opts) { - if (!a.address && - !a.hash && - !a.output && - !a.pubkey && - !a.input) + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ @@ -25,7 +21,7 @@ function p2pkh(a, opts) { output: typef.maybe(typef.BufferN(25)), pubkey: typef.maybe(ecc.isPoint), signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer) + input: typef.maybe(typef.Buffer), }, a); const _address = lazy.value(function () { const payload = bs58check.decode(a.address); @@ -33,7 +29,9 @@ function p2pkh(a, opts) { const hash = payload.slice(1); return { version, hash }; }); - const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const _chunks = lazy.value(function () { + return bscript.decompile(a.input); + }); const network = a.network || networks_1.bitcoin; const o = { network }; lazy.prop(o, 'address', function () { @@ -60,7 +58,7 @@ function p2pkh(a, opts) { OPS.OP_HASH160, o.hash, OPS.OP_EQUALVERIFY, - OPS.OP_CHECKSIG + OPS.OP_CHECKSIG, ]); }); lazy.prop(o, 'pubkey', function () { diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index 8ec9910..bb8f0a0 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -18,11 +18,7 @@ function stacksEqual(a, b) { // witness: // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL function p2sh(a, opts) { - if (!a.address && - !a.hash && - !a.output && - !a.redeem && - !a.input) + if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ @@ -34,10 +30,10 @@ function p2sh(a, opts) { network: typef.maybe(typef.Object), output: typef.maybe(typef.Buffer), input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), }), input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); let network = a.network; if (!network) { @@ -50,14 +46,16 @@ function p2sh(a, opts) { const hash = payload.slice(1); return { version, hash }; }); - const _chunks = lazy.value(function () { return bscript.decompile(a.input); }); + const _chunks = lazy.value(function () { + return bscript.decompile(a.input); + }); const _redeem = lazy.value(function () { const chunks = _chunks(); return { network, output: chunks[chunks.length - 1], input: bscript.compile(chunks.slice(0, -1)), - witness: a.witness || [] + witness: a.witness || [], }; }); // output dependents @@ -81,11 +79,7 @@ function p2sh(a, opts) { lazy.prop(o, 'output', function () { if (!o.hash) return; - return bscript.compile([ - OPS.OP_HASH160, - o.hash, - OPS.OP_EQUAL - ]); + return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); }); // input dependents lazy.prop(o, 'redeem', function () { @@ -153,7 +147,7 @@ function p2sh(a, opts) { if (hasInput && hasWitness) throw new TypeError('Input and witness provided'); if (hasInput) { - const richunks = bscript.decompile(redeem.input); + const richunks = (bscript.decompile(redeem.input)); if (!bscript.isPushOnly(richunks)) throw new TypeError('Non push-only scriptSig'); } diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index 7b269b7..9165f96 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -13,11 +13,7 @@ const EMPTY_BUFFER = Buffer.alloc(0); // input: <> // output: OP_0 {pubKeyHash} function p2wpkh(a, opts) { - if (!a.address && - !a.hash && - !a.output && - !a.pubkey && - !a.witness) + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ @@ -28,7 +24,7 @@ function p2wpkh(a, opts) { output: typef.maybe(typef.BufferN(22)), pubkey: typef.maybe(ecc.isPoint), signature: typef.maybe(bscript.isCanonicalScriptSignature), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); const _address = lazy.value(function () { const result = bech32.decode(a.address); @@ -37,7 +33,7 @@ function p2wpkh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data) + data: Buffer.from(data), }; }); const network = a.network || networks_1.bitcoin; @@ -60,10 +56,7 @@ function p2wpkh(a, opts) { lazy.prop(o, 'output', function () { if (!o.hash) return; - return bscript.compile([ - OPS.OP_0, - o.hash - ]); + return bscript.compile([OPS.OP_0, o.hash]); }); lazy.prop(o, 'pubkey', function () { if (a.pubkey) diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index a7e9f8b..c5eb067 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -19,11 +19,7 @@ function stacksEqual(a, b) { // witness: [redeemScriptSig ...] {redeemScript} // output: OP_0 {sha256(redeemScript)} function p2wsh(a, opts) { - if (!a.address && - !a.hash && - !a.output && - !a.redeem && - !a.witness) + if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); typef({ @@ -35,10 +31,10 @@ function p2wsh(a, opts) { input: typef.maybe(typef.Buffer), network: typef.maybe(typef.Object), output: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), }), input: typef.maybe(typef.BufferN(0)), - witness: typef.maybe(typef.arrayOf(typef.Buffer)) + witness: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); const _address = lazy.value(function () { const result = bech32.decode(a.address); @@ -47,10 +43,12 @@ function p2wsh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data) + data: Buffer.from(data), }; }); - const _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input); }); + const _rchunks = lazy.value(function () { + return bscript.decompile(a.redeem.input); + }); let network = a.network; if (!network) { network = (a.redeem && a.redeem.network) || networks_1.bitcoin; @@ -74,10 +72,7 @@ function p2wsh(a, opts) { lazy.prop(o, 'output', function () { if (!o.hash) return; - return bscript.compile([ - OPS.OP_0, - o.hash - ]); + return bscript.compile([OPS.OP_0, o.hash]); }); lazy.prop(o, 'redeem', function () { if (!a.witness) @@ -85,7 +80,7 @@ function p2wsh(a, opts) { return { output: a.witness[a.witness.length - 1], input: EMPTY_BUFFER, - witness: a.witness.slice(0, -1) + witness: a.witness.slice(0, -1), }; }); lazy.prop(o, 'input', function () { @@ -165,11 +160,15 @@ function p2wsh(a, opts) { } if (a.redeem.input && !bscript.isPushOnly(_rchunks())) throw new TypeError('Non push-only scriptSig'); - if (a.witness && a.redeem.witness && !stacksEqual(a.witness, a.redeem.witness)) + if (a.witness && + a.redeem.witness && + !stacksEqual(a.witness, a.redeem.witness)) throw new TypeError('Witness and redeem.witness mismatch'); } if (a.witness) { - if (a.redeem && a.redeem.output && !a.redeem.output.equals(a.witness[a.witness.length - 1])) + if (a.redeem && + a.redeem.output && + !a.redeem.output.equals(a.witness[a.witness.length - 1])) throw new TypeError('Witness and redeem.output mismatch'); } } diff --git a/src/script.js b/src/script.js index 3d115cb..a114d1f 100644 --- a/src/script.js +++ b/src/script.js @@ -11,10 +11,10 @@ exports.OPS = require('bitcoin-ops'); const REVERSE_OPS = require('bitcoin-ops/map'); const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1 function isOPInt(value) { - return types.Number(value) && - ((value === exports.OPS.OP_0) || + return (types.Number(value) && + (value === exports.OPS.OP_0 || (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || - (value === exports.OPS.OP_1NEGATE)); + value === exports.OPS.OP_1NEGATE)); } function isPushOnlyChunk(value) { return types.Buffer(value) || isOPInt(value); @@ -96,7 +96,7 @@ function decompile(buffer) { while (i < buffer.length) { const opcode = buffer[i]; // data chunk - if ((opcode > exports.OPS.OP_0) && (opcode <= exports.OPS.OP_PUSHDATA4)) { + if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) { const d = pushdata.decode(buffer, i); // did reading a pushDataInt fail? if (d === null) @@ -129,7 +129,8 @@ function toASM(chunks) { if (chunksIsBuffer(chunks)) { chunks = decompile(chunks); } - return chunks.map(function (chunk) { + return chunks + .map(function (chunk) { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); @@ -139,7 +140,8 @@ function toASM(chunks) { } // opcode! return REVERSE_OPS[chunk]; - }).join(' '); + }) + .join(' '); } exports.toASM = toASM; function fromASM(asm) { diff --git a/src/script_number.js b/src/script_number.js index da12de6..a8c42d3 100644 --- a/src/script_number.js +++ b/src/script_number.js @@ -19,8 +19,8 @@ function decode(buffer, maxLength, minimal) { const a = buffer.readUInt32LE(0); const b = buffer.readUInt8(4); if (b & 0x80) - return -(((b & ~0x80) * 0x100000000) + a); - return (b * 0x100000000) + a; + return -((b & ~0x80) * 0x100000000 + a); + return b * 0x100000000 + a; } // 32-bit / 24-bit / 16-bit / 8-bit let result = 0; @@ -33,11 +33,16 @@ function decode(buffer, maxLength, minimal) { } exports.decode = decode; function scriptNumSize(i) { - return i > 0x7fffffff ? 5 - : i > 0x7fffff ? 4 - : i > 0x7fff ? 3 - : i > 0x7f ? 2 - : i > 0x00 ? 1 + return i > 0x7fffffff + ? 5 + : i > 0x7fffff + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 : 0; } function encode(number) { diff --git a/src/script_signature.js b/src/script_signature.js index c3372cd..c185981 100644 --- a/src/script_signature.js +++ b/src/script_signature.js @@ -34,14 +34,14 @@ function decode(buffer) { const s = fromDER(decode.s); return { signature: Buffer.concat([r, s], 64), - hashType: hashType + hashType: hashType, }; } exports.decode = decode; function encode(signature, hashType) { typeforce({ signature: types.BufferN(64), - hashType: types.UInt8 + hashType: types.UInt8, }, { signature, hashType }); const hashTypeMod = hashType & ~0x80; if (hashTypeMod <= 0 || hashTypeMod >= 4) @@ -50,9 +50,6 @@ function encode(signature, hashType) { hashTypeBuffer.writeUInt8(hashType, 0); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - return Buffer.concat([ - bip66.encode(r, s), - hashTypeBuffer - ]); + return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); } exports.encode = encode; diff --git a/src/templates/nulldata.js b/src/templates/nulldata.js index fd5320d..b5ffdce 100644 --- a/src/templates/nulldata.js +++ b/src/templates/nulldata.js @@ -5,10 +5,11 @@ const bscript = require("../script"); const OPS = bscript.OPS; function check(script) { const buffer = bscript.compile(script); - return buffer.length > 1 && - buffer[0] === OPS.OP_RETURN; + return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } exports.check = check; -check.toJSON = function () { return 'null data output'; }; +check.toJSON = function () { + return 'null data output'; +}; const output = { check }; exports.output = output; diff --git a/src/transaction.js b/src/transaction.js index 34d7b40..cfd31fe 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -14,9 +14,10 @@ function varSliceSize(someScript) { } function vectorSize(someVector) { const length = someVector.length; - return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { - return sum + varSliceSize(witness); - }, 0); + return (varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0)); } const EMPTY_SCRIPT = Buffer.allocUnsafe(0); const EMPTY_WITNESS = []; @@ -25,7 +26,7 @@ const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000 const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT = { script: EMPTY_SCRIPT, - valueBuffer: VALUE_UINT64_MAX + valueBuffer: VALUE_UINT64_MAX, }; function isOutput(out) { return out.value !== undefined; @@ -90,14 +91,14 @@ class Transaction { index: readUInt32(), script: readVarSlice(), sequence: readUInt32(), - witness: EMPTY_WITNESS + witness: EMPTY_WITNESS, }); } const voutLen = readVarInt(); for (i = 0; i < voutLen; ++i) { tx.outs.push({ value: readUInt64(), - script: readVarSlice() + script: readVarSlice(), }); } if (hasWitnesses) { @@ -127,7 +128,7 @@ class Transaction { return true; } isCoinbase() { - return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash); + return (this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)); } addInput(hash, index, sequence, scriptSig) { typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); @@ -140,7 +141,7 @@ class Transaction { index: index, script: scriptSig || EMPTY_SCRIPT, sequence: sequence, - witness: EMPTY_WITNESS + witness: EMPTY_WITNESS, }) - 1); } addOutput(scriptPubKey, value) { @@ -148,11 +149,11 @@ class Transaction { // Add the output and return the output's index return (this.outs.push({ script: scriptPubKey, - value: value + value: value, }) - 1); } hasWitnesses() { - return this.ins.some((x) => { + return this.ins.some(x => { return x.witness.length !== 0; }); } @@ -178,27 +179,29 @@ class Transaction { this.outs.reduce((sum, output) => { return sum + 8 + varSliceSize(output.script); }, 0) + - (hasWitnesses ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) : 0)); + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0)); } clone() { const newTx = new Transaction(); newTx.version = this.version; newTx.locktime = this.locktime; - newTx.ins = this.ins.map((txIn) => { + newTx.ins = this.ins.map(txIn => { return { hash: txIn.hash, index: txIn.index, script: txIn.script, sequence: txIn.sequence, - witness: txIn.witness + witness: txIn.witness, }; }); - newTx.outs = this.outs.map((txOut) => { + newTx.outs = this.outs.map(txOut => { return { script: txOut.script, - value: txOut.value + value: txOut.value, }; }); return newTx; @@ -217,7 +220,7 @@ class Transaction { if (inIndex >= this.ins.length) return ONE; // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter((x) => { + const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(x => { return x !== script_1.OPS.OP_CODESEPARATOR; })); const txTmp = this.clone(); @@ -257,7 +260,7 @@ class Transaction { } else { // "blank" others input scripts - txTmp.ins.forEach((input) => { + txTmp.ins.forEach(input => { input.script = EMPTY_SCRIPT; }); txTmp.ins[inIndex].script = ourScript; @@ -295,7 +298,7 @@ class Transaction { if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { tbuffer = Buffer.allocUnsafe(36 * this.ins.length); toffset = 0; - this.ins.forEach((txIn) => { + this.ins.forEach(txIn => { writeSlice(txIn.hash); writeUInt32(txIn.index); }); @@ -306,7 +309,7 @@ class Transaction { (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { tbuffer = Buffer.allocUnsafe(4 * this.ins.length); toffset = 0; - this.ins.forEach((txIn) => { + this.ins.forEach(txIn => { writeUInt32(txIn.sequence); }); hashSequence = bcrypto.hash256(tbuffer); @@ -318,13 +321,14 @@ class Transaction { }, 0); tbuffer = Buffer.allocUnsafe(txOutsSize); toffset = 0; - this.outs.forEach((out) => { + this.outs.forEach(out => { writeUInt64(out.value); writeVarSlice(out.script); }); hashOutputs = bcrypto.hash256(tbuffer); } - else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { + else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length) { const output = this.outs[inIndex]; tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); toffset = 0; @@ -369,13 +373,13 @@ class Transaction { offset += slice.copy(buffer, offset); } function writeUInt8(i) { - offset = (buffer).writeUInt8(i, offset); + offset = buffer.writeUInt8(i, offset); } function writeUInt32(i) { - offset = (buffer).writeUInt32LE(i, offset); + offset = buffer.writeUInt32LE(i, offset); } function writeInt32(i) { - offset = (buffer).writeInt32LE(i, offset); + offset = buffer.writeInt32LE(i, offset); } function writeUInt64(i) { offset = bufferutils.writeUInt64LE(buffer, i, offset); @@ -399,14 +403,14 @@ class Transaction { writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); } writeVarInt(this.ins.length); - this.ins.forEach((txIn) => { + this.ins.forEach(txIn => { writeSlice(txIn.hash); writeUInt32(txIn.index); writeVarSlice(txIn.script); writeUInt32(txIn.sequence); }); writeVarInt(this.outs.length); - this.outs.forEach((txOut) => { + this.outs.forEach(txOut => { if (isOutput(txOut)) { writeUInt64(txOut.value); } @@ -416,7 +420,7 @@ class Transaction { writeVarSlice(txOut.script); }); if (hasWitnesses) { - this.ins.forEach((input) => { + this.ins.forEach(input => { writeVector(input.witness); }); } diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 1cdc6bf..540a17a 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -43,7 +43,7 @@ class TransactionBuilder { txb.__addInputUnsafe(txIn.hash, txIn.index, { sequence: txIn.sequence, script: txIn.script, - witness: txIn.witness + witness: txIn.witness, }); }); // fix some things not possible through the public API @@ -89,7 +89,7 @@ class TransactionBuilder { return this.__addInputUnsafe(txHash, vout, { sequence: sequence, prevOutScript: prevOutScript, - value: value + value: value, }); } __addInputUnsafe(txHash, vout, options) { @@ -194,7 +194,7 @@ class TransactionBuilder { if (!canSign(input)) { if (witnessValue !== undefined) { if (input.value !== undefined && input.value !== witnessValue) - throw new Error('Input didn\'t match witnessValue'); + throw new Error("Input didn't match witnessValue"); typeforce(types.Satoshi, witnessValue); input.value = witnessValue; } @@ -251,18 +251,19 @@ class TransactionBuilder { } // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // .build() will fail, but .buildIncomplete() is OK - return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { - if (!input.signatures) - return false; - return input.signatures.some((signature) => { - if (!signature) - return false; // no signature, no issue - const hashType = signatureHashType(signature); - if (hashType & transaction_1.Transaction.SIGHASH_NONE) - return false; // SIGHASH_NONE doesn't care about outputs - return true; // SIGHASH_* does care - }); - }); + return (this.__tx.outs.length === 0 && + this.__inputs.some(input => { + if (!input.signatures) + return false; + return input.signatures.some(signature => { + if (!signature) + return false; // no signature, no issue + const hashType = signatureHashType(signature); + if (hashType & transaction_1.Transaction.SIGHASH_NONE) + return false; // SIGHASH_NONE doesn't care about outputs + return true; // SIGHASH_* does care + }); + })); } __canModifyOutputs() { const nInputs = this.__tx.ins.length; @@ -313,21 +314,25 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) { } switch (type) { case SCRIPT_TYPES.P2WPKH: { - const { output, pubkey, signature } = payments.p2wpkh({ witness: witnessStack }); + const { output, pubkey, signature } = payments.p2wpkh({ + witness: witnessStack, + }); return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2WPKH, pubkeys: [pubkey], - signatures: [signature] + signatures: [signature], }; } case SCRIPT_TYPES.P2PKH: { - const { output, pubkey, signature } = payments.p2pkh({ input: scriptSig }); + const { output, pubkey, signature } = payments.p2pkh({ + input: scriptSig, + }); return { prevOutScript: output, prevOutType: SCRIPT_TYPES.P2PKH, pubkeys: [pubkey], - signatures: [signature] + signatures: [signature], }; } case SCRIPT_TYPES.P2PK: { @@ -335,26 +340,26 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) { return { prevOutType: SCRIPT_TYPES.P2PK, pubkeys: [undefined], - signatures: [signature] + signatures: [signature], }; } case SCRIPT_TYPES.P2MS: { const { m, pubkeys, signatures } = payments.p2ms({ input: scriptSig, - output: scriptPubKey + output: scriptPubKey, }, { allowIncomplete: true }); return { prevOutType: SCRIPT_TYPES.P2MS, pubkeys: pubkeys, signatures: signatures, - maxSignatures: m + maxSignatures: m, }; } } if (type === SCRIPT_TYPES.P2SH) { const { output, redeem } = payments.p2sh({ input: scriptSig, - witness: witnessStack + witness: witnessStack, }); const outputType = classify.output(redeem.output); const expanded = expandInput(redeem.input, redeem.witness, outputType, redeem.output); @@ -368,13 +373,13 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) { witnessScript: expanded.witnessScript, witnessScriptType: expanded.witnessScriptType, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, }; } if (type === SCRIPT_TYPES.P2WSH) { const { output, redeem } = payments.p2wsh({ input: scriptSig, - witness: witnessStack + witness: witnessStack, }); const outputType = classify.output(redeem.output); let expanded; @@ -392,12 +397,12 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) { witnessScript: redeem.output, witnessScriptType: expanded.prevOutType, pubkeys: expanded.pubkeys, - signatures: expanded.signatures + signatures: expanded.signatures, }; } return { prevOutType: SCRIPT_TYPES.NONSTANDARD, - prevOutScript: scriptSig + prevOutScript: scriptSig, }; } // could be done in expandInput, but requires the original Transaction for hashForSignature @@ -444,7 +449,7 @@ function expandOutput(script, ourPubKey) { return { type, pubkeys: [ourPubKey], - signatures: [undefined] + signatures: [undefined], }; } case SCRIPT_TYPES.P2WPKH: { @@ -458,7 +463,7 @@ function expandOutput(script, ourPubKey) { return { type, pubkeys: [ourPubKey], - signatures: [undefined] + signatures: [undefined], }; } case SCRIPT_TYPES.P2PK: { @@ -466,7 +471,7 @@ function expandOutput(script, ourPubKey) { return { type, pubkeys: [p2pk.pubkey], - signatures: [undefined] + signatures: [undefined], }; } case SCRIPT_TYPES.P2MS: { @@ -475,7 +480,7 @@ function expandOutput(script, ourPubKey) { type, pubkeys: p2ms.pubkeys, signatures: p2ms.pubkeys.map(() => undefined), - maxSignatures: p2ms.m + maxSignatures: p2ms.m, }; } } @@ -483,7 +488,7 @@ function expandOutput(script, ourPubKey) { } function prepareInput(input, ourPubKey, redeemScript, witnessScript) { if (redeemScript && witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); + const p2wsh = (payments.p2wsh({ redeem: { output: witnessScript } })); const p2wshAlt = payments.p2wsh({ output: redeemScript }); const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); const p2shAlt = payments.p2sh({ redeem: p2wsh }); @@ -494,7 +499,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { throw new Error('Redeem script inconsistent with prevOutScript'); const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); if (!expanded.pubkeys) - throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')'); + throw new Error(expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')'); if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } @@ -513,7 +521,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { signType: expanded.type, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures + maxSignatures: expanded.maxSignatures, }; } if (redeemScript) { @@ -531,7 +539,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { } const expanded = expandOutput(p2sh.redeem.output, ourPubKey); if (!expanded.pubkeys) - throw new Error(expanded.type + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')'); + throw new Error(expanded.type + + ' not supported as redeemScript (' + + bscript.toASM(redeemScript) + + ')'); if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } @@ -549,7 +560,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { signType: expanded.type, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures + maxSignatures: expanded.maxSignatures, }; } if (witnessScript) { @@ -561,7 +572,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { } const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); if (!expanded.pubkeys) - throw new Error(expanded.type + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')'); + throw new Error(expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')'); if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } @@ -578,7 +592,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { signType: expanded.type, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures + maxSignatures: expanded.maxSignatures, }; } if (input.prevOutType && input.prevOutScript) { @@ -591,13 +605,16 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { throw new Error('PrevOutScript is missing'); const expanded = expandOutput(input.prevOutScript, ourPubKey); if (!expanded.pubkeys) - throw new Error(expanded.type + ' not supported (' + bscript.toASM(input.prevOutScript) + ')'); + throw new Error(expanded.type + + ' not supported (' + + bscript.toASM(input.prevOutScript) + + ')'); if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } let signScript = input.prevOutScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; + signScript = (payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output); } return { prevOutType: expanded.type, @@ -607,7 +624,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { signType: expanded.type, pubkeys: expanded.pubkeys, signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures + maxSignatures: expanded.maxSignatures, }; } const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; @@ -618,7 +635,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { signScript: prevOutScript, signType: SCRIPT_TYPES.P2PKH, pubkeys: [ourPubKey], - signatures: [undefined] + signatures: [undefined], }; } function build(type, input, allowIncomplete) { @@ -656,7 +673,7 @@ function build(type, input, allowIncomplete) { } // if the transaction is not not complete (complete), or if signatures.length === m, validate // otherwise, the number of OP_0's may be >= m, so don't validate (boo) - const validate = !allowIncomplete || (m === signatures.length); + const validate = !allowIncomplete || m === signatures.length; return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }); } case SCRIPT_TYPES.P2SH: { @@ -667,8 +684,8 @@ function build(type, input, allowIncomplete) { redeem: { output: redeem.output || input.redeemScript, input: redeem.input, - witness: redeem.witness - } + witness: redeem.witness, + }, }); } case SCRIPT_TYPES.P2WSH: { @@ -679,21 +696,20 @@ function build(type, input, allowIncomplete) { redeem: { output: input.witnessScript, input: redeem.input, - witness: redeem.witness - } + witness: redeem.witness, + }, }); } } } function canSign(input) { - return input.signScript !== undefined && + return (input.signScript !== undefined && input.signType !== undefined && input.pubkeys !== undefined && input.signatures !== undefined && input.signatures.length === input.pubkeys.length && input.pubkeys.length > 0 && - (input.hasWitness === false || - input.value !== undefined); + (input.hasWitness === false || input.value !== undefined)); } function signatureHashType(buffer) { return buffer.readUInt8(buffer.length - 1); diff --git a/src/types.js b/src/types.js index 13d1bc8..76b98cf 100644 --- a/src/types.js +++ b/src/types.js @@ -10,7 +10,9 @@ function BIP32Path(value) { return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } exports.BIP32Path = BIP32Path; -BIP32Path.toJSON = function () { return 'BIP32 derivation path'; }; +BIP32Path.toJSON = function () { + return 'BIP32 derivation path'; +}; const SATOSHI_MAX = 21 * 1e14; function Satoshi(value) { return typeforce.UInt53(value) && value <= SATOSHI_MAX; @@ -23,11 +25,11 @@ exports.Network = typeforce.compile({ messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), bip32: { public: typeforce.UInt32, - private: typeforce.UInt32 + private: typeforce.UInt32, }, pubKeyHash: typeforce.UInt8, scriptHash: typeforce.UInt8, - wif: typeforce.UInt8 + wif: typeforce.UInt8, }); exports.Buffer256bit = typeforce.BufferN(32); exports.Hash160bit = typeforce.BufferN(20); diff --git a/types/index.d.ts b/types/index.d.ts index 9682271..3512872 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -5,7 +5,7 @@ import * as crypto from './crypto'; import * as networks from './networks'; import * as payments from './payments'; import * as script from './script'; -export { ECPair, address, bip32, crypto, networks, payments, script, }; +export { ECPair, address, bip32, crypto, networks, payments, script }; export { Block } from './block'; export { Transaction } from './transaction'; export { TransactionBuilder } from './transaction_builder'; From 8329e7456659807ef6acb80c4a39880866c05ef0 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Mon, 4 Mar 2019 00:27:08 +0900 Subject: [PATCH 118/183] ci: check formats --- .travis.yml | 2 +- package.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 397dc23..90088bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ node_js: matrix: include: - node_js: "lts/*" - env: TEST_SUITE=standard + env: TEST_SUITE=format:ci - node_js: "lts/*" env: TEST_SUITE=coverage env: diff --git a/package.json b/package.json index b9eb8d8..d615efa 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", - "format": "prettier ts_src/*.ts ts_src/**/*.ts --ignore-path ./.prettierignore --write", + "format": "npm run prettier -- --write", + "format:ci": "npm run prettier -- --check", "integration": "npm run build && npm run nobuild:integration", "nobuild:coverage-report": "nyc report --reporter=lcov", "nobuild:coverage-html": "nyc report --reporter=html", @@ -27,6 +28,7 @@ "nobuild:integration": "mocha --timeout 50000 test/integration/", "nobuild:unit": "mocha", "prepare": "npm run build", + "prettier": "prettier ts_src/*.ts ts_src/**/*.ts --ignore-path ./.prettierignore", "test": "npm run build && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, From 070a782149bfead9d1b3039b38d5d42f01138bb4 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Mon, 4 Mar 2019 22:17:29 +0900 Subject: [PATCH 119/183] style: apply format --- ts_src/payments/p2sh.ts | 32 ++++++++++++++++---------------- ts_src/payments/p2wsh.ts | 14 +++++++------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index 281e3df..b2e6bdf 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -1,19 +1,19 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import { bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line -import * as bscript from '../script' -import * as bcrypto from '../crypto' -import * as lazy from './lazy' -const typef = require('typeforce') -const OPS = bscript.OPS - -const bs58check = require('bs58check') - -function stacksEqual (a: Array, b: Array): boolean { - if (a.length !== b.length) return false - - return a.every(function (x, i) { - return x.equals(b[i]) - }) +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { bitcoin as BITCOIN_NETWORK } from '../networks'; // eslint-disable-line +import * as bscript from '../script'; +import * as bcrypto from '../crypto'; +import * as lazy from './lazy'; +const typef = require('typeforce'); +const OPS = bscript.OPS; + +const bs58check = require('bs58check'); + +function stacksEqual(a: Array, b: Array): boolean { + if (a.length !== b.length) return false; + + return a.every(function(x, i) { + return x.equals(b[i]); + }); } // input: [redeemScriptSig ...] {redeemScript} diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 5f9b02d..78e842d 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -1,10 +1,10 @@ -import { Payment, PaymentOpts } from './index' // eslint-disable-line -import { bitcoin as BITCOIN_NETWORK } from '../networks' // eslint-disable-line -import * as bscript from '../script' -import * as bcrypto from '../crypto' -import * as lazy from './lazy' -const typef = require('typeforce') -const OPS = bscript.OPS +import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { bitcoin as BITCOIN_NETWORK } from '../networks'; // eslint-disable-line +import * as bscript from '../script'; +import * as bcrypto from '../crypto'; +import * as lazy from './lazy'; +const typef = require('typeforce'); +const OPS = bscript.OPS; const bech32 = require('bech32'); From 763cb8b92312b817b657489b34d1dc3398932502 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Mon, 4 Mar 2019 22:17:54 +0900 Subject: [PATCH 120/183] ci: check formats in npm test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d615efa..8e40c29 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "nobuild:unit": "mocha", "prepare": "npm run build", "prettier": "prettier ts_src/*.ts ts_src/**/*.ts --ignore-path ./.prettierignore", - "test": "npm run build && npm run nobuild:coverage", + "test": "npm run build && npm run format:ci && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, "repository": { From 0729fde36fc13250083c1a085c8dde828607fc02 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 5 Mar 2019 15:11:20 +0900 Subject: [PATCH 121/183] Remove eslint comments. --- src/payments/p2ms.js | 11 ++++------- src/payments/p2sh.js | 2 +- src/payments/p2wsh.js | 2 +- test/ecpair.js | 2 -- ts_src/payments/embed.ts | 2 +- ts_src/payments/index.ts | 2 +- ts_src/payments/p2ms.ts | 15 +++++---------- ts_src/payments/p2pk.ts | 2 +- ts_src/payments/p2pkh.ts | 2 +- ts_src/payments/p2sh.ts | 4 ++-- ts_src/payments/p2wpkh.ts | 2 +- ts_src/payments/p2wsh.ts | 4 ++-- 12 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index 4e3c115..1e51faa 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -25,7 +25,7 @@ function p2ms(a, opts) { opts = Object.assign({ validate: true }, opts || {}); function isAcceptableSignature(x) { return (bscript.isCanonicalScriptSignature(x) || - (opts.allowIncomplete && x === OPS.OP_0) !== undefined); // eslint-disable-line + (opts.allowIncomplete && x === OPS.OP_0) !== undefined); } typef({ network: typef.maybe(typef.Object), @@ -45,8 +45,8 @@ function p2ms(a, opts) { return; decoded = true; chunks = bscript.decompile(output); - o.m = chunks[0] - OP_INT_BASE; // eslint-disable-line - o.n = chunks[chunks.length - 2] - OP_INT_BASE; // eslint-disable-line + o.m = chunks[0] - OP_INT_BASE; + o.n = chunks[chunks.length - 2] - OP_INT_BASE; o.pubkeys = chunks.slice(1, -2); } lazy.prop(o, 'output', function () { @@ -100,10 +100,7 @@ function p2ms(a, opts) { throw new TypeError('Output is invalid'); if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid'); - if (o.m <= 0 || // eslint-disable-line - o.n > 16 || // eslint-disable-line - o.m > o.n || // eslint-disable-line - o.n !== chunks.length - 3) + if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) throw new TypeError('Output is invalid'); if (!o.pubkeys.every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid'); diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index bb8f0a0..f98ef71 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const networks_1 = require("../networks"); // eslint-disable-line +const networks_1 = require("../networks"); const bscript = require("../script"); const bcrypto = require("../crypto"); const lazy = require("./lazy"); diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index c5eb067..7c71ac3 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const networks_1 = require("../networks"); // eslint-disable-line +const networks_1 = require("../networks"); const bscript = require("../script"); const bcrypto = require("../crypto"); const lazy = require("./lazy"); diff --git a/test/ecpair.js b/test/ecpair.js index 4299470..0ff0e8b 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -1,5 +1,3 @@ -/* eslint-disable no-new */ - const { describe, it, beforeEach } = require('mocha') const assert = require('assert') const proxyquire = require('proxyquire') diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index f7225a7..d7a2b0f 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; import * as bscript from '../script'; import * as lazy from './lazy'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 9791661..6727eeb 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -1,4 +1,4 @@ -import { Network } from '../networks'; // eslint-disable-line +import { Network } from '../networks'; import { p2data as embed } from './embed'; import { p2ms } from './p2ms'; import { p2pk } from './p2pk'; diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index fce7616..766f341 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; import * as bscript from '../script'; import * as lazy from './lazy'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; @@ -32,7 +32,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { return ( bscript.isCanonicalScriptSignature(x) || (opts!.allowIncomplete && x === OPS.OP_0) !== undefined - ); // eslint-disable-line + ); } typef( @@ -58,8 +58,8 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { if (decoded) return; decoded = true; chunks = >bscript.decompile(output); - o.m = chunks[0] - OP_INT_BASE; // eslint-disable-line - o.n = chunks[chunks.length - 2] - OP_INT_BASE; // eslint-disable-line + o.m = chunks[0] - OP_INT_BASE; + o.n = chunks[chunks.length - 2] - OP_INT_BASE; o.pubkeys = >chunks.slice(1, -2); } @@ -115,12 +115,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid'); - if ( - o.m! <= 0 || // eslint-disable-line - o.n! > 16 || // eslint-disable-line - o.m! > o.n! || // eslint-disable-line - o.n !== chunks.length - 3 - ) + if (o.m! <= 0 || o.n! > 16 || o.m! > o.n! || o.n !== chunks.length - 3) throw new TypeError('Output is invalid'); if (!o.pubkeys!.every(x => ecc.isPoint(x))) throw new TypeError('Output is invalid'); diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index e17a8f2..69fb404 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; import * as bscript from '../script'; import * as lazy from './lazy'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index ccac25d..63594ad 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; import * as bscript from '../script'; import * as bcrypto from '../crypto'; import * as lazy from './lazy'; diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index b2e6bdf..b7df1dc 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -1,5 +1,5 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line -import { bitcoin as BITCOIN_NETWORK } from '../networks'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; import * as bcrypto from '../crypto'; import * as lazy from './lazy'; diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index ec7ed40..04f0e92 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; import * as bscript from '../script'; import * as bcrypto from '../crypto'; import * as lazy from './lazy'; diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 78e842d..28a235c 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -1,5 +1,5 @@ -import { Payment, PaymentOpts } from './index'; // eslint-disable-line -import { bitcoin as BITCOIN_NETWORK } from '../networks'; // eslint-disable-line +import { Payment, PaymentOpts } from './index'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; import * as bcrypto from '../crypto'; import * as lazy from './lazy'; From e8857d3a8499b1cc51f89c32db8a594752e57884 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 5 Mar 2019 15:32:25 +0900 Subject: [PATCH 122/183] Update package-lock.json --- package-lock.json | 1574 ++------------------------------------------- 1 file changed, 69 insertions(+), 1505 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3009813..4af2f69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,124 +4,10 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true - }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } + "@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, "balanced-match": { "version": "1.0.0", @@ -143,14 +29,16 @@ "integrity": "sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg==" }, "bindings": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", - "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } }, "bip32": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-1.0.2.tgz", - "integrity": "sha512-kedLYj8yvYzND+EfzeoMSlGiN7ImiRBF/MClJSZPkMfcU+OQO7ZpL5L/Yg+TunebBZIHhunstiQF//KLKSF5rg==", + "version": "git+https://github.com/junderw/bip32.git#0df550ad047210fe5cfcc189bb78db645f2f1a89", + "from": "git+https://github.com/junderw/bip32.git#typeScript", "requires": { "bs58check": "^2.1.1", "create-hash": "^1.2.0", @@ -242,61 +130,6 @@ "safe-buffer": "^5.1.2" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -306,48 +139,6 @@ "safe-buffer": "^5.0.1" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", @@ -360,30 +151,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -409,17 +176,6 @@ "sha.js": "^2.4.8" } }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -429,41 +185,6 @@ "ms": "2.0.0" } }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", - "dev": true, - "requires": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^3.0.9", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" - } - }, "dhttp": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz", @@ -479,15 +200,6 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, "elliptic": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", @@ -502,224 +214,25 @@ "minimalistic-crypto-utils": "^1.0.0" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "eslint": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", - "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", - "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.2", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - } - }, - "eslint-config-standard": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz", - "integrity": "sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw==", - "dev": true - }, - "eslint-config-standard-jsx": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz", - "integrity": "sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg==", - "dev": true - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", - "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz", - "integrity": "sha1-JgAu+/ylmJtyiKwEdQi9JPIXsWk=", - "dev": true, - "requires": { - "builtin-modules": "^1.1.1", - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.1.1", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - } - } - }, - "eslint-plugin-node": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", - "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", - "dev": true, - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "^5.4.1" - } - }, - "eslint-plugin-promise": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", - "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", - "dev": true - }, - "eslint-plugin-react": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz", - "integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==", + "eslint-plugin-typescript": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-0.14.0.tgz", + "integrity": "sha512-2u1WnnDF2mkWWgU1lFQ2RjypUlmRoBEvQN02y9u+IL12mjWlkKFGEBnVsjs9Y8190bfPQCvWly1c2rYYUSOxWw==", "dev": true, "requires": { - "doctrine": "^2.0.2", - "has": "^1.0.1", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.0" + "requireindex": "~1.1.0" } }, - "eslint-plugin-standard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", - "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", - "dev": true - }, "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.2.tgz", + "integrity": "sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -732,31 +245,6 @@ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.0.0" - } - }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", @@ -772,59 +260,10 @@ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "fill-keys": { "version": "1.0.2", @@ -836,57 +275,12 @@ "merge-descriptors": "~1.0.0" } }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -901,54 +295,18 @@ "path-is-absolute": "^1.0.0" } }, - "globals": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.10.0.tgz", - "integrity": "sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ==", - "dev": true - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true - }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, "hash-base": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", @@ -989,33 +347,6 @@ "integrity": "sha512-j1jog3tDfhpWlqbVbh29qc7FG7w+NT4ed+QQFGqvww83+50AzzretB7wykZGOe28mBdvCYH3GdHaVWJQ2lJ/4w==", "dev": true }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1031,209 +362,18 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, "is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", "dev": true }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "jsx-ast-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", - "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", - "dev": true, - "requires": { - "array-includes": "^3.0.3" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", "dev": true }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -1255,12 +395,6 @@ "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, "minimaldata": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz", @@ -1336,35 +470,11 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, "nan": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, "nyc": { "version": "11.9.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz", @@ -3997,18 +3107,6 @@ } } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "dev": true - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4018,101 +3116,18 @@ "wrappy": "1" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -4126,106 +3141,12 @@ "sha.js": "^2.4.8" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "pkg-config": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", - "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", - "dev": true, - "requires": { - "debug-log": "^1.0.0", - "find-root": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "prettier": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prop-types": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", - "dev": true, - "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, "proxyquire": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz", @@ -4237,12 +3158,6 @@ "resolve": "~1.8.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "pushdata-bitcoin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", @@ -4252,58 +3167,18 @@ } }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" } }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } + "requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", + "dev": true }, "resolve": { "version": "1.8.1", @@ -4314,47 +3189,6 @@ "path-parse": "^1.0.5" } }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -4364,51 +3198,15 @@ "inherits": "^2.0.1" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "*" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, "sha.js": { @@ -4420,165 +3218,12 @@ "safe-buffer": "^5.0.1" } }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "standard": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/standard/-/standard-11.0.1.tgz", - "integrity": "sha512-nu0jAcHiSc8H+gJCXeiziMVZNDYi8MuqrYJKxTgjP4xKXZMKm311boqQIzDrYI/ktosltxt2CbDjYQs9ANC8IA==", - "dev": true, - "requires": { - "eslint": "~4.18.0", - "eslint-config-standard": "11.0.0", - "eslint-config-standard-jsx": "5.0.0", - "eslint-plugin-import": "~2.9.0", - "eslint-plugin-node": "~6.0.0", - "eslint-plugin-promise": "~3.7.0", - "eslint-plugin-react": "~7.7.0", - "eslint-plugin-standard": "~3.0.1", - "standard-engine": "~8.0.0" - } - }, - "standard-engine": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-8.0.1.tgz", - "integrity": "sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw==", - "dev": true, - "requires": { - "deglob": "^2.1.0", - "get-stdin": "^6.0.0", - "minimist": "^1.1.0", - "pkg-conf": "^2.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -4588,32 +3233,6 @@ "has-flag": "^3.0.0" } }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, "tiny-secp256k1": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.0.1.tgz", @@ -4626,63 +3245,44 @@ "nan": "^2.10.0" } }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, "typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "typescript": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", + "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", "dev": true }, - "unorm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", - "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "typescript-eslint-parser": { + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-21.0.2.tgz", + "integrity": "sha512-u+pj4RVJBr4eTzj0n5npoXD/oRthvfUCjSKndhNI714MG0mQq2DJw5WP7qmonRNIFgmZuvdDOH3BHm9iOjIAfg==", + "dev": true, + "requires": { + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0", + "typescript-estree": "5.3.0" + } }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "typescript-estree": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/typescript-estree/-/typescript-estree-5.3.0.tgz", + "integrity": "sha512-Vu0KmYdSCkpae+J48wsFC1ti19Hq3Wi/lODUaE+uesc3gzqhWbZ5itWbsjylLVbjNW4K41RqDzSfnaYNbmEiMQ==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "lodash.unescape": "4.0.1", + "semver": "5.5.0" } }, + "unorm": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.5.0.tgz", + "integrity": "sha512-sMfSWoiRaXXeDZSXC+YRZ23H4xchQpwxjpw1tmfR+kgbBCaOgln4NI0LXejJIhnBuKINrB3WRn+ZI8IWssirVw==", + "dev": true + }, "varuint-bitcoin": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz", @@ -4691,15 +3291,6 @@ "safe-buffer": "^5.1.1" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, "wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", @@ -4708,38 +3299,11 @@ "bs58check": "<3.0.0" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true } } } From a567a978776465ed9240cac35b753e5da52b9355 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Wed, 6 Mar 2019 21:38:36 +0900 Subject: [PATCH 123/183] style: fix glob pattern for prettier --- package.json | 2 +- ts_src/templates/multisig/index.ts | 9 +-- ts_src/templates/multisig/input.ts | 31 +++++--- ts_src/templates/multisig/output.ts | 45 ++++++----- ts_src/templates/pubkey/index.ts | 9 +-- ts_src/templates/pubkey/input.ts | 15 ++-- ts_src/templates/pubkey/output.ts | 16 ++-- ts_src/templates/pubkeyhash/index.ts | 9 +-- ts_src/templates/pubkeyhash/input.ts | 14 ++-- ts_src/templates/pubkeyhash/output.ts | 16 ++-- ts_src/templates/scripthash/index.ts | 9 +-- ts_src/templates/scripthash/input.ts | 81 ++++++++++++-------- ts_src/templates/scripthash/output.ts | 16 ++-- ts_src/templates/witnesscommitment/index.ts | 6 +- ts_src/templates/witnesscommitment/output.ts | 40 +++++----- ts_src/templates/witnesspubkeyhash/index.ts | 9 +-- ts_src/templates/witnesspubkeyhash/input.ts | 18 +++-- ts_src/templates/witnesspubkeyhash/output.ts | 16 ++-- ts_src/templates/witnessscripthash/index.ts | 9 +-- ts_src/templates/witnessscripthash/input.ts | 62 +++++++++------ ts_src/templates/witnessscripthash/output.ts | 16 ++-- 21 files changed, 249 insertions(+), 199 deletions(-) diff --git a/package.json b/package.json index e60b6a9..b98f412 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "nobuild:integration": "mocha --timeout 50000 test/integration/", "nobuild:unit": "mocha", "prepare": "npm run build", - "prettier": "prettier ts_src/*.ts ts_src/**/*.ts --ignore-path ./.prettierignore", + "prettier": "prettier 'ts_src/**/*.ts' --ignore-path ./.prettierignore", "test": "npm run build && npm run format:ci && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, diff --git a/ts_src/templates/multisig/index.ts b/ts_src/templates/multisig/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/multisig/index.ts +++ b/ts_src/templates/multisig/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/multisig/input.ts b/ts_src/templates/multisig/input.ts index 1ec2874..222ff10 100644 --- a/ts_src/templates/multisig/input.ts +++ b/ts_src/templates/multisig/input.ts @@ -1,21 +1,30 @@ // OP_0 [signatures ...] -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -function partialSignature (value: number | Buffer): boolean { - return value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) +function partialSignature(value: number | Buffer): boolean { + return ( + value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) + ); } -export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = >bscript.decompile(script) - if (chunks.length < 2) return false - if (chunks[0] !== OPS.OP_0) return false +export function check( + script: Buffer | Array, + allowIncomplete?: boolean, +): boolean { + const chunks = >bscript.decompile(script); + if (chunks.length < 2) return false; + if (chunks[0] !== OPS.OP_0) return false; if (allowIncomplete) { - return chunks.slice(1).every(partialSignature) + return chunks.slice(1).every(partialSignature); } - return (>chunks.slice(1)).every(bscript.isCanonicalScriptSignature) + return (>chunks.slice(1)).every( + bscript.isCanonicalScriptSignature, + ); } -check.toJSON = function () { return 'multisig input' } +check.toJSON = function() { + return 'multisig input'; +}; diff --git a/ts_src/templates/multisig/output.ts b/ts_src/templates/multisig/output.ts index e46fa78..040649b 100644 --- a/ts_src/templates/multisig/output.ts +++ b/ts_src/templates/multisig/output.ts @@ -1,27 +1,32 @@ // m [pubKeys ...] n OP_CHECKMULTISIG -import * as bscript from '../../script' -import * as types from '../../types' -import { OPS } from '../../script' -const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 +import * as bscript from '../../script'; +import * as types from '../../types'; +import { OPS } from '../../script'; +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 -export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = >bscript.decompile(script) +export function check( + script: Buffer | Array, + allowIncomplete?: boolean, +): boolean { + const chunks = >bscript.decompile(script); - if (chunks.length < 4) return false - if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false - if (!types.Number(chunks[0])) return false - if (!types.Number(chunks[chunks.length - 2])) return false - const m = chunks[0] - OP_INT_BASE - const n = chunks[chunks.length - 2] - OP_INT_BASE + if (chunks.length < 4) return false; + if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false; + if (!types.Number(chunks[0])) return false; + if (!types.Number(chunks[chunks.length - 2])) return false; + const m = chunks[0] - OP_INT_BASE; + const n = chunks[chunks.length - 2] - OP_INT_BASE; - if (m <= 0) return false - if (n > 16) return false - if (m > n) return false - if (n !== chunks.length - 3) return false - if (allowIncomplete) return true + if (m <= 0) return false; + if (n > 16) return false; + if (m > n) return false; + if (n !== chunks.length - 3) return false; + if (allowIncomplete) return true; - const keys = > chunks.slice(1, -2) - return keys.every(bscript.isCanonicalPubKey) + const keys = >chunks.slice(1, -2); + return keys.every(bscript.isCanonicalPubKey); } -check.toJSON = function () { return 'multi-sig output' } +check.toJSON = function() { + return 'multi-sig output'; +}; diff --git a/ts_src/templates/pubkey/index.ts b/ts_src/templates/pubkey/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/pubkey/index.ts +++ b/ts_src/templates/pubkey/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/pubkey/input.ts b/ts_src/templates/pubkey/input.ts index f9245e4..e9ea1be 100644 --- a/ts_src/templates/pubkey/input.ts +++ b/ts_src/templates/pubkey/input.ts @@ -1,11 +1,14 @@ // {signature} -import * as bscript from '../../script' +import * as bscript from '../../script'; -export function check (script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script) +export function check(script: Buffer | Array): boolean { + const chunks = >bscript.decompile(script); - return chunks.length === 1 && - bscript.isCanonicalScriptSignature(chunks[0]) + return ( + chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]) + ); } -check.toJSON = function () { return 'pubKey input' } +check.toJSON = function() { + return 'pubKey input'; +}; diff --git a/ts_src/templates/pubkey/output.ts b/ts_src/templates/pubkey/output.ts index aa321b3..8378870 100644 --- a/ts_src/templates/pubkey/output.ts +++ b/ts_src/templates/pubkey/output.ts @@ -1,13 +1,17 @@ // {pubKey} OP_CHECKSIG -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -export function check (script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script) +export function check(script: Buffer | Array): boolean { + const chunks = >bscript.decompile(script); - return chunks.length === 2 && + return ( + chunks.length === 2 && bscript.isCanonicalPubKey(chunks[0]) && chunks[1] === OPS.OP_CHECKSIG + ); } -check.toJSON = function () { return 'pubKey output' } +check.toJSON = function() { + return 'pubKey output'; +}; diff --git a/ts_src/templates/pubkeyhash/index.ts b/ts_src/templates/pubkeyhash/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/pubkeyhash/index.ts +++ b/ts_src/templates/pubkeyhash/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/pubkeyhash/input.ts b/ts_src/templates/pubkeyhash/input.ts index f27f809..c091764 100644 --- a/ts_src/templates/pubkeyhash/input.ts +++ b/ts_src/templates/pubkeyhash/input.ts @@ -1,12 +1,16 @@ // {signature} {pubKey} -import * as bscript from '../../script' +import * as bscript from '../../script'; -export function check (script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script) +export function check(script: Buffer | Array): boolean { + const chunks = >bscript.decompile(script); - return chunks.length === 2 && + return ( + chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && bscript.isCanonicalPubKey(chunks[1]) + ); } -check.toJSON = function () { return 'pubKeyHash input' } +check.toJSON = function() { + return 'pubKeyHash input'; +}; diff --git a/ts_src/templates/pubkeyhash/output.ts b/ts_src/templates/pubkeyhash/output.ts index 242cb0e..a5c5c9b 100644 --- a/ts_src/templates/pubkeyhash/output.ts +++ b/ts_src/templates/pubkeyhash/output.ts @@ -1,16 +1,20 @@ // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length === 25 && + return ( + buffer.length === 25 && buffer[0] === OPS.OP_DUP && buffer[1] === OPS.OP_HASH160 && buffer[2] === 0x14 && buffer[23] === OPS.OP_EQUALVERIFY && buffer[24] === OPS.OP_CHECKSIG + ); } -check.toJSON = function () { return 'pubKeyHash output' } +check.toJSON = function() { + return 'pubKeyHash output'; +}; diff --git a/ts_src/templates/scripthash/index.ts b/ts_src/templates/scripthash/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/scripthash/index.ts +++ b/ts_src/templates/scripthash/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/scripthash/input.ts b/ts_src/templates/scripthash/input.ts index 7b3107d..0b86d63 100644 --- a/ts_src/templates/scripthash/input.ts +++ b/ts_src/templates/scripthash/input.ts @@ -1,46 +1,61 @@ // {serialized scriptPubKey script} -import * as bscript from '../../script' -import * as p2ms from '../multisig' -import * as p2pk from '../pubkey' -import * as p2pkh from '../pubkeyhash' -import * as p2wpkho from '../witnesspubkeyhash/output' -import * as p2wsho from '../witnessscripthash/output' - - - -export function check (script: Buffer | Array, allowIncomplete?: boolean): boolean { - const chunks = bscript.decompile(script)! - if (chunks.length < 1) return false - - const lastChunk = chunks[chunks.length - 1] - if (!Buffer.isBuffer(lastChunk)) return false - - const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1)))! - const redeemScriptChunks = bscript.decompile(lastChunk) +import * as bscript from '../../script'; +import * as p2ms from '../multisig'; +import * as p2pk from '../pubkey'; +import * as p2pkh from '../pubkeyhash'; +import * as p2wpkho from '../witnesspubkeyhash/output'; +import * as p2wsho from '../witnessscripthash/output'; + +export function check( + script: Buffer | Array, + allowIncomplete?: boolean, +): boolean { + const chunks = bscript.decompile(script)!; + if (chunks.length < 1) return false; + + const lastChunk = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(lastChunk)) return false; + + const scriptSigChunks = bscript.decompile( + bscript.compile(chunks.slice(0, -1)), + )!; + const redeemScriptChunks = bscript.decompile(lastChunk); // is redeemScript a valid script? - if (!redeemScriptChunks) return false + if (!redeemScriptChunks) return false; // is redeemScriptSig push only? - if (!bscript.isPushOnly(scriptSigChunks)) return false + if (!bscript.isPushOnly(scriptSigChunks)) return false; // is witness? if (chunks.length === 1) { - return p2wsho.check(redeemScriptChunks) || - p2wpkho.check(redeemScriptChunks) + return ( + p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks) + ); } // match types - if (p2pkh.input.check(scriptSigChunks) && - p2pkh.output.check(redeemScriptChunks)) return true - - if (p2ms.input.check(scriptSigChunks, allowIncomplete) && - p2ms.output.check(redeemScriptChunks)) return true - - if (p2pk.input.check(scriptSigChunks) && - p2pk.output.check(redeemScriptChunks)) return true - - return false + if ( + p2pkh.input.check(scriptSigChunks) && + p2pkh.output.check(redeemScriptChunks) + ) + return true; + + if ( + p2ms.input.check(scriptSigChunks, allowIncomplete) && + p2ms.output.check(redeemScriptChunks) + ) + return true; + + if ( + p2pk.input.check(scriptSigChunks) && + p2pk.output.check(redeemScriptChunks) + ) + return true; + + return false; } -check.toJSON = function () { return 'scriptHash input' } +check.toJSON = function() { + return 'scriptHash input'; +}; diff --git a/ts_src/templates/scripthash/output.ts b/ts_src/templates/scripthash/output.ts index 0b968bf..6ff138a 100644 --- a/ts_src/templates/scripthash/output.ts +++ b/ts_src/templates/scripthash/output.ts @@ -1,14 +1,18 @@ // OP_HASH160 {scriptHash} OP_EQUAL -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length === 23 && + return ( + buffer.length === 23 && buffer[0] === OPS.OP_HASH160 && buffer[1] === 0x14 && buffer[22] === OPS.OP_EQUAL + ); } -check.toJSON = function () { return 'scriptHash output' } +check.toJSON = function() { + return 'scriptHash output'; +}; diff --git a/ts_src/templates/witnesscommitment/index.ts b/ts_src/templates/witnesscommitment/index.ts index c36a2b8..d5c166d 100644 --- a/ts_src/templates/witnesscommitment/index.ts +++ b/ts_src/templates/witnesscommitment/index.ts @@ -1,5 +1,3 @@ -import * as output from './output' +import * as output from './output'; -export { - output, -} +export { output }; diff --git a/ts_src/templates/witnesscommitment/output.ts b/ts_src/templates/witnesscommitment/output.ts index 0bdf11c..29beb39 100644 --- a/ts_src/templates/witnesscommitment/output.ts +++ b/ts_src/templates/witnesscommitment/output.ts @@ -1,36 +1,40 @@ // OP_RETURN {aa21a9ed} {commitment} -import * as bscript from '../../script' -import * as types from '../../types' +import * as bscript from '../../script'; +import * as types from '../../types'; -const typeforce = require('typeforce') -import { OPS } from '../../script' +const typeforce = require('typeforce'); +import { OPS } from '../../script'; -const HEADER: Buffer = Buffer.from('aa21a9ed', 'hex') +const HEADER: Buffer = Buffer.from('aa21a9ed', 'hex'); -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length > 37 && + return ( + buffer.length > 37 && buffer[0] === OPS.OP_RETURN && buffer[1] === 0x24 && buffer.slice(2, 6).equals(HEADER) + ); } -check.toJSON = function () { return 'Witness commitment output' } +check.toJSON = function() { + return 'Witness commitment output'; +}; -export function encode (commitment: Buffer): Buffer { - typeforce(types.Hash256bit, commitment) +export function encode(commitment: Buffer): Buffer { + typeforce(types.Hash256bit, commitment); - const buffer = Buffer.allocUnsafe(36) - HEADER.copy(buffer, 0) - commitment.copy(buffer, 4) + const buffer = Buffer.allocUnsafe(36); + HEADER.copy(buffer, 0); + commitment.copy(buffer, 4); - return bscript.compile([OPS.OP_RETURN, buffer]) + return bscript.compile([OPS.OP_RETURN, buffer]); } -export function decode (buffer: Buffer): Buffer { - typeforce(check, buffer) +export function decode(buffer: Buffer): Buffer { + typeforce(check, buffer); - return (bscript.decompile(buffer)![1]).slice(4, 36) + return (bscript.decompile(buffer)![1]).slice(4, 36); } diff --git a/ts_src/templates/witnesspubkeyhash/index.ts b/ts_src/templates/witnesspubkeyhash/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/witnesspubkeyhash/index.ts +++ b/ts_src/templates/witnesspubkeyhash/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/witnesspubkeyhash/input.ts b/ts_src/templates/witnesspubkeyhash/input.ts index 91b8357..22fc2cf 100644 --- a/ts_src/templates/witnesspubkeyhash/input.ts +++ b/ts_src/templates/witnesspubkeyhash/input.ts @@ -1,16 +1,20 @@ // {signature} {pubKey} -import * as bscript from '../../script' +import * as bscript from '../../script'; -function isCompressedCanonicalPubKey (pubKey: Buffer): boolean { - return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33 +function isCompressedCanonicalPubKey(pubKey: Buffer): boolean { + return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; } -export function check (script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script) +export function check(script: Buffer | Array): boolean { + const chunks = >bscript.decompile(script); - return chunks.length === 2 && + return ( + chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && isCompressedCanonicalPubKey(chunks[1]) + ); } -check.toJSON = function () { return 'witnessPubKeyHash input' } +check.toJSON = function() { + return 'witnessPubKeyHash input'; +}; diff --git a/ts_src/templates/witnesspubkeyhash/output.ts b/ts_src/templates/witnesspubkeyhash/output.ts index bc7a3a0..09c49d0 100644 --- a/ts_src/templates/witnesspubkeyhash/output.ts +++ b/ts_src/templates/witnesspubkeyhash/output.ts @@ -1,13 +1,13 @@ // OP_0 {pubKeyHash} -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length === 22 && - buffer[0] === OPS.OP_0 && - buffer[1] === 0x14 + return buffer.length === 22 && buffer[0] === OPS.OP_0 && buffer[1] === 0x14; } -check.toJSON = function () { return 'Witness pubKeyHash output' } +check.toJSON = function() { + return 'Witness pubKeyHash output'; +}; diff --git a/ts_src/templates/witnessscripthash/index.ts b/ts_src/templates/witnessscripthash/index.ts index 42aeb7b..aa2bdcb 100644 --- a/ts_src/templates/witnessscripthash/index.ts +++ b/ts_src/templates/witnessscripthash/index.ts @@ -1,7 +1,4 @@ -import * as input from './input' -import * as output from './output' +import * as input from './input'; +import * as output from './output'; -export { - input, - output, -} +export { input, output }; diff --git a/ts_src/templates/witnessscripthash/input.ts b/ts_src/templates/witnessscripthash/input.ts index 7f7e415..6cf35bf 100644 --- a/ts_src/templates/witnessscripthash/input.ts +++ b/ts_src/templates/witnessscripthash/input.ts @@ -1,36 +1,50 @@ // {serialized scriptPubKey script} -import * as bscript from '../../script' -const typeforce = require('typeforce') +import * as bscript from '../../script'; +const typeforce = require('typeforce'); -import * as p2ms from '../multisig' -import * as p2pk from '../pubkey' -import * as p2pkh from '../pubkeyhash' +import * as p2ms from '../multisig'; +import * as p2pk from '../pubkey'; +import * as p2pkh from '../pubkeyhash'; -export function check (chunks: Array, allowIncomplete?: boolean): boolean { - typeforce(typeforce.Array, chunks) - if (chunks.length < 1) return false +export function check( + chunks: Array, + allowIncomplete?: boolean, +): boolean { + typeforce(typeforce.Array, chunks); + if (chunks.length < 1) return false; - const witnessScript = chunks[chunks.length - 1] - if (!Buffer.isBuffer(witnessScript)) return false + const witnessScript = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(witnessScript)) return false; - const witnessScriptChunks = bscript.decompile(witnessScript) + const witnessScriptChunks = bscript.decompile(witnessScript); // is witnessScript a valid script? - if (!witnessScriptChunks || witnessScriptChunks.length === 0) return false + if (!witnessScriptChunks || witnessScriptChunks.length === 0) return false; - const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)) + const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); // match types - if (p2pkh.input.check(witnessRawScriptSig) && - p2pkh.output.check(witnessScriptChunks)) return true - - if (p2ms.input.check(witnessRawScriptSig, allowIncomplete) && - p2ms.output.check(witnessScriptChunks)) return true - - if (p2pk.input.check(witnessRawScriptSig) && - p2pk.output.check(witnessScriptChunks)) return true - - return false + if ( + p2pkh.input.check(witnessRawScriptSig) && + p2pkh.output.check(witnessScriptChunks) + ) + return true; + + if ( + p2ms.input.check(witnessRawScriptSig, allowIncomplete) && + p2ms.output.check(witnessScriptChunks) + ) + return true; + + if ( + p2pk.input.check(witnessRawScriptSig) && + p2pk.output.check(witnessScriptChunks) + ) + return true; + + return false; } -check.toJSON = function () { return 'witnessScriptHash input' } +check.toJSON = function() { + return 'witnessScriptHash input'; +}; diff --git a/ts_src/templates/witnessscripthash/output.ts b/ts_src/templates/witnessscripthash/output.ts index deffe1f..430cc4f 100644 --- a/ts_src/templates/witnessscripthash/output.ts +++ b/ts_src/templates/witnessscripthash/output.ts @@ -1,13 +1,13 @@ // OP_0 {scriptHash} -import * as bscript from '../../script' -import { OPS } from '../../script' +import * as bscript from '../../script'; +import { OPS } from '../../script'; -export function check (script: Buffer | Array): boolean { - const buffer = bscript.compile(script) +export function check(script: Buffer | Array): boolean { + const buffer = bscript.compile(script); - return buffer.length === 34 && - buffer[0] === OPS.OP_0 && - buffer[1] === 0x20 + return buffer.length === 34 && buffer[0] === OPS.OP_0 && buffer[1] === 0x20; } -check.toJSON = function () { return 'Witness scriptHash output' } +check.toJSON = function() { + return 'Witness scriptHash output'; +}; From ee60862df6e6a63d390df9ab523eacd60f5536cf Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 11:20:28 +0900 Subject: [PATCH 124/183] Add JS for prettier glob fix --- src/templates/multisig/input.js | 6 ++++-- src/templates/multisig/output.js | 4 +++- src/templates/pubkey/input.js | 7 ++++--- src/templates/pubkey/output.js | 8 +++++--- src/templates/pubkeyhash/input.js | 8 +++++--- src/templates/pubkeyhash/output.js | 8 +++++--- src/templates/scripthash/input.js | 7 ++++--- src/templates/scripthash/output.js | 8 +++++--- src/templates/witnesscommitment/output.js | 8 +++++--- src/templates/witnesspubkeyhash/input.js | 8 +++++--- src/templates/witnesspubkeyhash/output.js | 8 ++++---- src/templates/witnessscripthash/input.js | 4 +++- src/templates/witnessscripthash/output.js | 8 ++++---- types/templates/multisig/index.d.ts | 2 +- types/templates/pubkey/index.d.ts | 2 +- types/templates/pubkeyhash/index.d.ts | 2 +- types/templates/scripthash/index.d.ts | 2 +- types/templates/witnesscommitment/index.d.ts | 2 +- types/templates/witnesspubkeyhash/index.d.ts | 2 +- types/templates/witnessscripthash/index.d.ts | 2 +- 20 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.js index f8dd3d3..24a9710 100644 --- a/src/templates/multisig/input.js +++ b/src/templates/multisig/input.js @@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); const script_1 = require("../../script"); function partialSignature(value) { - return value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value); + return (value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value)); } function check(script, allowIncomplete) { const chunks = bscript.decompile(script); @@ -18,4 +18,6 @@ function check(script, allowIncomplete) { return chunks.slice(1).every(bscript.isCanonicalScriptSignature); } exports.check = check; -check.toJSON = function () { return 'multisig input'; }; +check.toJSON = function () { + return 'multisig input'; +}; diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.js index 811ed12..64d07bc 100644 --- a/src/templates/multisig/output.js +++ b/src/templates/multisig/output.js @@ -31,4 +31,6 @@ function check(script, allowIncomplete) { return keys.every(bscript.isCanonicalPubKey); } exports.check = check; -check.toJSON = function () { return 'multi-sig output'; }; +check.toJSON = function () { + return 'multi-sig output'; +}; diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.js index bc5e566..10d3c07 100644 --- a/src/templates/pubkey/input.js +++ b/src/templates/pubkey/input.js @@ -4,8 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); function check(script) { const chunks = bscript.decompile(script); - return chunks.length === 1 && - bscript.isCanonicalScriptSignature(chunks[0]); + return (chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0])); } exports.check = check; -check.toJSON = function () { return 'pubKey input'; }; +check.toJSON = function () { + return 'pubKey input'; +}; diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.js index 043150e..e2f87c2 100644 --- a/src/templates/pubkey/output.js +++ b/src/templates/pubkey/output.js @@ -5,9 +5,11 @@ const bscript = require("../../script"); const script_1 = require("../../script"); function check(script) { const chunks = bscript.decompile(script); - return chunks.length === 2 && + return (chunks.length === 2 && bscript.isCanonicalPubKey(chunks[0]) && - chunks[1] === script_1.OPS.OP_CHECKSIG; + chunks[1] === script_1.OPS.OP_CHECKSIG); } exports.check = check; -check.toJSON = function () { return 'pubKey output'; }; +check.toJSON = function () { + return 'pubKey output'; +}; diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.js index 29a684e..f03d391 100644 --- a/src/templates/pubkeyhash/input.js +++ b/src/templates/pubkeyhash/input.js @@ -4,9 +4,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); function check(script) { const chunks = bscript.decompile(script); - return chunks.length === 2 && + return (chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && - bscript.isCanonicalPubKey(chunks[1]); + bscript.isCanonicalPubKey(chunks[1])); } exports.check = check; -check.toJSON = function () { return 'pubKeyHash input'; }; +check.toJSON = function () { + return 'pubKeyHash input'; +}; diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.js index 9016c6a..222244b 100644 --- a/src/templates/pubkeyhash/output.js +++ b/src/templates/pubkeyhash/output.js @@ -5,12 +5,14 @@ const bscript = require("../../script"); const script_1 = require("../../script"); function check(script) { const buffer = bscript.compile(script); - return buffer.length === 25 && + return (buffer.length === 25 && buffer[0] === script_1.OPS.OP_DUP && buffer[1] === script_1.OPS.OP_HASH160 && buffer[2] === 0x14 && buffer[23] === script_1.OPS.OP_EQUALVERIFY && - buffer[24] === script_1.OPS.OP_CHECKSIG; + buffer[24] === script_1.OPS.OP_CHECKSIG); } exports.check = check; -check.toJSON = function () { return 'pubKeyHash output'; }; +check.toJSON = function () { + return 'pubKeyHash output'; +}; diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.js index c40bc26..5d2b576 100644 --- a/src/templates/scripthash/input.js +++ b/src/templates/scripthash/input.js @@ -24,8 +24,7 @@ function check(script, allowIncomplete) { return false; // is witness? if (chunks.length === 1) { - return p2wsho.check(redeemScriptChunks) || - p2wpkho.check(redeemScriptChunks); + return (p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks)); } // match types if (p2pkh.input.check(scriptSigChunks) && @@ -40,4 +39,6 @@ function check(script, allowIncomplete) { return false; } exports.check = check; -check.toJSON = function () { return 'scriptHash input'; }; +check.toJSON = function () { + return 'scriptHash input'; +}; diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.js index bd38d5a..5fd2f65 100644 --- a/src/templates/scripthash/output.js +++ b/src/templates/scripthash/output.js @@ -5,10 +5,12 @@ const bscript = require("../../script"); const script_1 = require("../../script"); function check(script) { const buffer = bscript.compile(script); - return buffer.length === 23 && + return (buffer.length === 23 && buffer[0] === script_1.OPS.OP_HASH160 && buffer[1] === 0x14 && - buffer[22] === script_1.OPS.OP_EQUAL; + buffer[22] === script_1.OPS.OP_EQUAL); } exports.check = check; -check.toJSON = function () { return 'scriptHash output'; }; +check.toJSON = function () { + return 'scriptHash output'; +}; diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.js index 95a8bc1..38f622a 100644 --- a/src/templates/witnesscommitment/output.js +++ b/src/templates/witnesscommitment/output.js @@ -8,13 +8,15 @@ const script_1 = require("../../script"); const HEADER = Buffer.from('aa21a9ed', 'hex'); function check(script) { const buffer = bscript.compile(script); - return buffer.length > 37 && + return (buffer.length > 37 && buffer[0] === script_1.OPS.OP_RETURN && buffer[1] === 0x24 && - buffer.slice(2, 6).equals(HEADER); + buffer.slice(2, 6).equals(HEADER)); } exports.check = check; -check.toJSON = function () { return 'Witness commitment output'; }; +check.toJSON = function () { + return 'Witness commitment output'; +}; function encode(commitment) { typeforce(types.Hash256bit, commitment); const buffer = Buffer.allocUnsafe(36); diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.js index 131a49e..4585623 100644 --- a/src/templates/witnesspubkeyhash/input.js +++ b/src/templates/witnesspubkeyhash/input.js @@ -7,9 +7,11 @@ function isCompressedCanonicalPubKey(pubKey) { } function check(script) { const chunks = bscript.decompile(script); - return chunks.length === 2 && + return (chunks.length === 2 && bscript.isCanonicalScriptSignature(chunks[0]) && - isCompressedCanonicalPubKey(chunks[1]); + isCompressedCanonicalPubKey(chunks[1])); } exports.check = check; -check.toJSON = function () { return 'witnessPubKeyHash input'; }; +check.toJSON = function () { + return 'witnessPubKeyHash input'; +}; diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.js index 2fb6e15..9c508a0 100644 --- a/src/templates/witnesspubkeyhash/output.js +++ b/src/templates/witnesspubkeyhash/output.js @@ -5,9 +5,9 @@ const bscript = require("../../script"); const script_1 = require("../../script"); function check(script) { const buffer = bscript.compile(script); - return buffer.length === 22 && - buffer[0] === script_1.OPS.OP_0 && - buffer[1] === 0x14; + return buffer.length === 22 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x14; } exports.check = check; -check.toJSON = function () { return 'Witness pubKeyHash output'; }; +check.toJSON = function () { + return 'Witness pubKeyHash output'; +}; diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.js index 255ea86..ca8c8b6 100644 --- a/src/templates/witnessscripthash/input.js +++ b/src/templates/witnessscripthash/input.js @@ -31,4 +31,6 @@ function check(chunks, allowIncomplete) { return false; } exports.check = check; -check.toJSON = function () { return 'witnessScriptHash input'; }; +check.toJSON = function () { + return 'witnessScriptHash input'; +}; diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.js index 994a75a..f283b86 100644 --- a/src/templates/witnessscripthash/output.js +++ b/src/templates/witnessscripthash/output.js @@ -5,9 +5,9 @@ const bscript = require("../../script"); const script_1 = require("../../script"); function check(script) { const buffer = bscript.compile(script); - return buffer.length === 34 && - buffer[0] === script_1.OPS.OP_0 && - buffer[1] === 0x20; + return buffer.length === 34 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x20; } exports.check = check; -check.toJSON = function () { return 'Witness scriptHash output'; }; +check.toJSON = function () { + return 'Witness scriptHash output'; +}; diff --git a/types/templates/multisig/index.d.ts b/types/templates/multisig/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/multisig/index.d.ts +++ b/types/templates/multisig/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; diff --git a/types/templates/pubkey/index.d.ts b/types/templates/pubkey/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/pubkey/index.d.ts +++ b/types/templates/pubkey/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; diff --git a/types/templates/pubkeyhash/index.d.ts b/types/templates/pubkeyhash/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/pubkeyhash/index.d.ts +++ b/types/templates/pubkeyhash/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; diff --git a/types/templates/scripthash/index.d.ts b/types/templates/scripthash/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/scripthash/index.d.ts +++ b/types/templates/scripthash/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; diff --git a/types/templates/witnesscommitment/index.d.ts b/types/templates/witnesscommitment/index.d.ts index a072ea9..c37ee7c 100644 --- a/types/templates/witnesscommitment/index.d.ts +++ b/types/templates/witnesscommitment/index.d.ts @@ -1,2 +1,2 @@ import * as output from './output'; -export { output, }; +export { output }; diff --git a/types/templates/witnesspubkeyhash/index.d.ts b/types/templates/witnesspubkeyhash/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/witnesspubkeyhash/index.d.ts +++ b/types/templates/witnesspubkeyhash/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; diff --git a/types/templates/witnessscripthash/index.d.ts b/types/templates/witnessscripthash/index.d.ts index cff90ee..f6288e2 100644 --- a/types/templates/witnessscripthash/index.d.ts +++ b/types/templates/witnessscripthash/index.d.ts @@ -1,3 +1,3 @@ import * as input from './input'; import * as output from './output'; -export { input, output, }; +export { input, output }; From f084439054543ee058f1e3c839daa121a20b6bb9 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Tue, 5 Mar 2019 23:51:45 +0900 Subject: [PATCH 125/183] ci: add tslint --- package-lock.json | 249 +++++++++++++++++++++++++++++++++------------- package.json | 8 +- tslint.json | 31 ++++++ 3 files changed, 214 insertions(+), 74 deletions(-) create mode 100644 tslint.json diff --git a/package-lock.json b/package-lock.json index 4af2f69..cbbf172 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,59 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -130,6 +183,34 @@ "safe-buffer": "^5.1.2" } }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -139,6 +220,21 @@ "safe-buffer": "^5.0.1" } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", @@ -220,44 +316,16 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "eslint-plugin-typescript": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-0.14.0.tgz", - "integrity": "sha512-2u1WnnDF2mkWWgU1lFQ2RjypUlmRoBEvQN02y9u+IL12mjWlkKFGEBnVsjs9Y8190bfPQCvWly1c2rYYUSOxWw==", - "dev": true, - "requires": { - "requireindex": "~1.1.0" - } - }, - "eslint-scope": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.2.tgz", - "integrity": "sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "file-uri-to-path": { @@ -301,6 +369,15 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -368,12 +445,22 @@ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", "dev": true }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, + "js-yaml": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", + "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -514,7 +601,6 @@ "version": "0.1.4", "bundled": true, "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -1697,8 +1783,7 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "loose-envify": { "version": "1.3.1", @@ -3174,12 +3259,6 @@ "safe-buffer": "^5.1.0" } }, - "requireindex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", - "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", - "dev": true - }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -3218,12 +3297,27 @@ "safe-buffer": "^5.0.1" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -3245,6 +3339,42 @@ "nan": "^2.10.0" } }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "tslint": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.1.tgz", + "integrity": "sha512-fplQqb2miLbcPhyHoMV4FU9PtNRbgmm/zI5d3SZwwmJQM6V0eodju+hplpyfhLWpmwrDNfNYU57uYRb8s0zZoQ==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", @@ -3256,27 +3386,6 @@ "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", "dev": true }, - "typescript-eslint-parser": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-21.0.2.tgz", - "integrity": "sha512-u+pj4RVJBr4eTzj0n5npoXD/oRthvfUCjSKndhNI714MG0mQq2DJw5WP7qmonRNIFgmZuvdDOH3BHm9iOjIAfg==", - "dev": true, - "requires": { - "eslint-scope": "^4.0.0", - "eslint-visitor-keys": "^1.0.0", - "typescript-estree": "5.3.0" - } - }, - "typescript-estree": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/typescript-estree/-/typescript-estree-5.3.0.tgz", - "integrity": "sha512-Vu0KmYdSCkpae+J48wsFC1ti19Hq3Wi/lODUaE+uesc3gzqhWbZ5itWbsjylLVbjNW4K41RqDzSfnaYNbmEiMQ==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - } - }, "unorm": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.5.0.tgz", diff --git a/package.json b/package.json index b98f412..898fac8 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "format": "npm run prettier -- --write", "format:ci": "npm run prettier -- --check", "integration": "npm run build && npm run nobuild:integration", + "lint": "tslint -p tsconfig.json -c tslint.json", "nobuild:coverage-report": "nyc report --reporter=lcov", "nobuild:coverage-html": "nyc report --reporter=html", "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", @@ -29,7 +30,7 @@ "nobuild:unit": "mocha", "prepare": "npm run build", "prettier": "prettier 'ts_src/**/*.ts' --ignore-path ./.prettierignore", - "test": "npm run build && npm run format:ci && npm run nobuild:coverage", + "test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, "repository": { @@ -64,15 +65,14 @@ "bn.js": "^4.11.8", "bs58": "^4.0.0", "dhttp": "^3.0.0", - "eslint-plugin-typescript": "^0.14.0", "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", "nyc": "^11.8.0", "prettier": "^1.16.4", "proxyquire": "^2.0.1", - "typescript": "3.2.2", - "typescript-eslint-parser": "^21.0.2" + "tslint": "^5.13.1", + "typescript": "3.2.2" }, "license": "MIT" } diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..18bf61d --- /dev/null +++ b/tslint.json @@ -0,0 +1,31 @@ +{ + "defaultSeverity": "error", + "extends": ["tslint:recommended"], + "rules": { + "curly": false, + "indent": [ + true, + "spaces", + 2 + ], + "interface-name": [false], + "match-default-export-name": true, + "max-classes-per-file": [false], + "member-access": [true, "no-public"], + "no-empty": [true, "allow-empty-catch"], + "no-implicit-dependencies": true, + "no-return-await": true, + "no-var-requires": false, + "no-unused-expression": false, + "object-literal-sort-keys": false, + "quotemark": [true, "single"], + "variable-name": [ + true, + "ban-keywords", + "check-format", + "allow-leading-underscore", + "allow-pascal-case" + ] + }, + "rulesDirectory": [] +} From 99d0de8b3d9bff5c0ba57af9b98c299b2f602c4f Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 11:22:04 +0900 Subject: [PATCH 126/183] update package-lock --- package-lock.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index cbbf172..9de2ff5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -601,6 +601,7 @@ "version": "0.1.4", "bundled": true, "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -1783,7 +1784,8 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "loose-envify": { "version": "1.3.1", From d9cba6f176931833a8a3fd8cc26af3a160c820e7 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 11:32:06 +0900 Subject: [PATCH 127/183] Fixed address.ts lint --- src/address.js | 12 ++++++------ ts_src/address.ts | 36 ++++++++++++++++++------------------ types/address.d.ts | 8 ++++---- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/address.js b/src/address.js index f12cd8d..b0be0e1 100644 --- a/src/address.js +++ b/src/address.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const types = require("./types"); -const bscript = require("./script"); const networks = require("./networks"); const payments = require("./payments"); +const bscript = require("./script"); +const types = require("./types"); const bech32 = require('bech32'); const bs58check = require('bs58check'); const typeforce = require('typeforce'); @@ -16,7 +16,7 @@ function fromBase58Check(address) { throw new TypeError(address + ' is too long'); const version = payload.readUInt8(0); const hash = payload.slice(1); - return { version: version, hash: hash }; + return { version, hash }; } exports.fromBase58Check = fromBase58Check; function fromBech32(address) { @@ -44,7 +44,7 @@ function toBech32(data, version, prefix) { } exports.toBech32 = toBech32; function fromOutputScript(output, network) { - //TODO: Network + // TODO: Network network = network || networks.bitcoin; try { return payments.p2pkh({ output, network }).address; @@ -67,8 +67,8 @@ function fromOutputScript(output, network) { exports.fromOutputScript = fromOutputScript; function toOutputScript(address, network) { network = network || networks.bitcoin; - let decodeBase58 = undefined; - let decodeBech32 = undefined; + let decodeBase58; + let decodeBech32; try { decodeBase58 = fromBase58Check(address); } diff --git a/ts_src/address.ts b/ts_src/address.ts index d547e78..0c0cda5 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -1,23 +1,23 @@ import { Network } from './networks'; -import * as types from './types'; -import * as bscript from './script'; import * as networks from './networks'; import * as payments from './payments'; +import * as bscript from './script'; +import * as types from './types'; const bech32 = require('bech32'); const bs58check = require('bs58check'); const typeforce = require('typeforce'); -export type Base58CheckResult = { +export interface Base58CheckResult { hash: Buffer; version: number; -}; +} -export type Bech32Result = { +export interface Bech32Result { version: number; prefix: string; data: Buffer; -}; +} export function fromBase58Check(address: string): Base58CheckResult { const payload = bs58check.decode(address); @@ -29,7 +29,7 @@ export function fromBase58Check(address: string): Base58CheckResult { const version = payload.readUInt8(0); const hash = payload.slice(1); - return { version: version, hash: hash }; + return { version, hash }; } export function fromBech32(address: string): Bech32Result { @@ -65,20 +65,20 @@ export function toBech32( } export function fromOutputScript(output: Buffer, network: Network): string { - //TODO: Network + // TODO: Network network = network || networks.bitcoin; try { - return payments.p2pkh({ output, network }).address; + return payments.p2pkh({ output, network }).address as string; } catch (e) {} try { - return payments.p2sh({ output, network }).address; + return payments.p2sh({ output, network }).address as string; } catch (e) {} try { - return payments.p2wpkh({ output, network }).address; + return payments.p2wpkh({ output, network }).address as string; } catch (e) {} try { - return payments.p2wsh({ output, network }).address; + return payments.p2wsh({ output, network }).address as string; } catch (e) {} throw new Error(bscript.toASM(output) + ' has no matching Address'); @@ -87,17 +87,17 @@ export function fromOutputScript(output: Buffer, network: Network): string { export function toOutputScript(address: string, network: Network): Buffer { network = network || networks.bitcoin; - let decodeBase58: Base58CheckResult | undefined = undefined; - let decodeBech32: Bech32Result | undefined = undefined; + let decodeBase58: Base58CheckResult | undefined; + let decodeBech32: Bech32Result | undefined; try { decodeBase58 = fromBase58Check(address); } catch (e) {} if (decodeBase58) { if (decodeBase58.version === network.pubKeyHash) - return payments.p2pkh({ hash: decodeBase58.hash }).output; + return payments.p2pkh({ hash: decodeBase58.hash }).output as Buffer; if (decodeBase58.version === network.scriptHash) - return payments.p2sh({ hash: decodeBase58.hash }).output; + return payments.p2sh({ hash: decodeBase58.hash }).output as Buffer; } else { try { decodeBech32 = fromBech32(address); @@ -108,9 +108,9 @@ export function toOutputScript(address: string, network: Network): Buffer { throw new Error(address + ' has an invalid prefix'); if (decodeBech32.version === 0) { if (decodeBech32.data.length === 20) - return payments.p2wpkh({ hash: decodeBech32.data }).output; + return payments.p2wpkh({ hash: decodeBech32.data }).output as Buffer; if (decodeBech32.data.length === 32) - return payments.p2wsh({ hash: decodeBech32.data }).output; + return payments.p2wsh({ hash: decodeBech32.data }).output as Buffer; } } } diff --git a/types/address.d.ts b/types/address.d.ts index 68fbedd..1da68ac 100644 --- a/types/address.d.ts +++ b/types/address.d.ts @@ -1,14 +1,14 @@ /// import { Network } from './networks'; -export declare type Base58CheckResult = { +export interface Base58CheckResult { hash: Buffer; version: number; -}; -export declare type Bech32Result = { +} +export interface Bech32Result { version: number; prefix: string; data: Buffer; -}; +} export declare function fromBase58Check(address: string): Base58CheckResult; export declare function fromBech32(address: string): Bech32Result; export declare function toBase58Check(hash: Buffer, version: number): string; From 51d078cbcedd378e02870c65b51b9bcb4aee5924 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 11:47:00 +0900 Subject: [PATCH 128/183] Fix block.ts lint --- src/block.js | 44 +++++++++++++-------------- ts_src/block.ts | 78 ++++++++++++++++++++++++------------------------ tslint.json | 3 ++ types/block.d.ts | 14 ++++----- 4 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/block.js b/src/block.js index eb3fb8b..9419989 100644 --- a/src/block.js +++ b/src/block.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const bufferutils_1 = require("./bufferutils"); +const bcrypto = require("./crypto"); const transaction_1 = require("./transaction"); const types = require("./types"); -const bcrypto = require("./crypto"); -const bufferutils_1 = require("./bufferutils"); const fastMerkleRoot = require('merkle-lib/fastRoot'); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); @@ -28,16 +28,6 @@ function anyTxHasWitness(transactions) { input.witness.length > 0))); } class Block { - constructor() { - this.version = 1; - this.timestamp = 0; - this.bits = 0; - this.nonce = 0; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.witnessCommit = undefined; - this.transactions = undefined; - } static fromBuffer(buffer) { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); @@ -77,11 +67,11 @@ class Block { }; const nTransactions = readVarInt(); block.transactions = []; - for (var i = 0; i < nTransactions; ++i) { + for (let i = 0; i < nTransactions; ++i) { const tx = readTransaction(); block.transactions.push(tx); } - let witnessCommit = block.getWitnessCommit(); + const witnessCommit = block.getWitnessCommit(); // This Block contains a witness commit if (witnessCommit) block.witnessCommit = witnessCommit; @@ -109,6 +99,16 @@ class Block { ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) : rootHash; } + constructor() { + this.version = 1; + this.timestamp = 0; + this.bits = 0; + this.nonce = 0; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.witnessCommit = undefined; + this.transactions = undefined; + } getWitnessCommit() { if (!txesHaveWitnessCommit(this.transactions)) return null; @@ -116,11 +116,11 @@ class Block { // There is no rule for the index of the output, so use filter to find it. // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = this.transactions[0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))).map(out => out.script.slice(6, 38)); + const witnessCommits = this.transactions[0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))).map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) - let result = witnessCommits[witnessCommits.length - 1]; + const result = witnessCommits[witnessCommits.length - 1]; if (!(result instanceof Buffer && result.length === 32)) return null; return result; @@ -193,7 +193,7 @@ class Block { checkTxRoots() { // If the Block has segwit transactions but no witness commit, // there's no way it can be valid, so fail the check. - let hasWitnessCommit = this.hasWitnessCommit(); + const hasWitnessCommit = this.hasWitnessCommit(); if (!hasWitnessCommit && this.hasWitness()) return false; return (this.__checkMerkleRoot() && @@ -204,6 +204,11 @@ class Block { 'deprecated in v5. Please use checkTxRoots instead.'); return this.checkTxRoots(); } + checkProofOfWork() { + const hash = bufferutils_1.reverseBuffer(this.getHash()); + const target = Block.calculateTarget(this.bits); + return hash.compare(target) <= 0; + } __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; @@ -218,10 +223,5 @@ class Block { const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true); return this.witnessCommit.compare(actualWitnessCommit) === 0; } - checkProofOfWork() { - const hash = bufferutils_1.reverseBuffer(this.getHash()); - const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0; - } } exports.Block = Block; diff --git a/ts_src/block.ts b/ts_src/block.ts index feb141e..888337d 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -1,7 +1,7 @@ +import { reverseBuffer } from './bufferutils'; +import * as bcrypto from './crypto'; import { Transaction } from './transaction'; import * as types from './types'; -import * as bcrypto from './crypto'; -import { reverseBuffer } from './bufferutils'; const fastMerkleRoot = require('merkle-lib/fastRoot'); const typeforce = require('typeforce'); @@ -14,7 +14,7 @@ const errorWitnessNotSegwit = new TypeError( 'Cannot compute witness commit for non-segwit block', ); -function txesHaveWitnessCommit(transactions: Array): boolean { +function txesHaveWitnessCommit(transactions: Transaction[]): boolean { return ( transactions instanceof Array && transactions[0] && @@ -27,7 +27,7 @@ function txesHaveWitnessCommit(transactions: Array): boolean { ); } -function anyTxHasWitness(transactions: Array): boolean { +function anyTxHasWitness(transactions: Transaction[]): boolean { return ( transactions instanceof Array && transactions.some( @@ -45,26 +45,6 @@ function anyTxHasWitness(transactions: Array): boolean { } export class Block { - version: number; - prevHash?: Buffer; - merkleRoot?: Buffer; - timestamp: number; - witnessCommit?: Buffer; - bits: number; - nonce: number; - transactions?: Array; - - constructor() { - this.version = 1; - this.timestamp = 0; - this.bits = 0; - this.nonce = 0; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.witnessCommit = undefined; - this.transactions = undefined; - } - static fromBuffer(buffer: Buffer): Block { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); @@ -111,12 +91,12 @@ export class Block { const nTransactions = readVarInt(); block.transactions = []; - for (var i = 0; i < nTransactions; ++i) { + for (let i = 0; i < nTransactions; ++i) { const tx = readTransaction(); block.transactions.push(tx); } - let witnessCommit = block.getWitnessCommit(); + const witnessCommit = block.getWitnessCommit(); // This Block contains a witness commit if (witnessCommit) block.witnessCommit = witnessCommit; @@ -136,7 +116,7 @@ export class Block { } static calculateMerkleRoot( - transactions: Array, + transactions: Transaction[], forWitness?: boolean, ): Buffer { typeforce([{ getHash: types.Function }], transactions); @@ -157,6 +137,26 @@ export class Block { : rootHash; } + version: number; + prevHash?: Buffer; + merkleRoot?: Buffer; + timestamp: number; + witnessCommit?: Buffer; + bits: number; + nonce: number; + transactions?: Transaction[]; + + constructor() { + this.version = 1; + this.timestamp = 0; + this.bits = 0; + this.nonce = 0; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.witnessCommit = undefined; + this.transactions = undefined; + } + getWitnessCommit(): Buffer | null { if (!txesHaveWitnessCommit(this.transactions!)) return null; @@ -164,12 +164,12 @@ export class Block { // There is no rule for the index of the output, so use filter to find it. // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. - let witnessCommits = this.transactions![0].outs.filter(out => + const witnessCommits = this.transactions![0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), ).map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) - let result = witnessCommits[witnessCommits.length - 1]; + const result = witnessCommits[witnessCommits.length - 1]; if (!(result instanceof Buffer && result.length === 32)) return null; return result; @@ -261,7 +261,7 @@ export class Block { checkTxRoots(): boolean { // If the Block has segwit transactions but no witness commit, // there's no way it can be valid, so fail the check. - let hasWitnessCommit = this.hasWitnessCommit(); + const hasWitnessCommit = this.hasWitnessCommit(); if (!hasWitnessCommit && this.hasWitness()) return false; return ( this.__checkMerkleRoot() && @@ -277,14 +277,21 @@ export class Block { return this.checkTxRoots(); } - __checkMerkleRoot(): boolean { + checkProofOfWork(): boolean { + const hash: Buffer = reverseBuffer(this.getHash()); + const target = Block.calculateTarget(this.bits); + + return hash.compare(target) <= 0; + } + + private __checkMerkleRoot(): boolean { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); return this.merkleRoot!.compare(actualMerkleRoot) === 0; } - __checkWitnessCommit(): boolean { + private __checkWitnessCommit(): boolean { if (!this.transactions) throw errorMerkleNoTxes; if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; @@ -294,11 +301,4 @@ export class Block { ); return this.witnessCommit!.compare(actualWitnessCommit) === 0; } - - checkProofOfWork(): boolean { - const hash: Buffer = reverseBuffer(this.getHash()); - const target = Block.calculateTarget(this.bits); - - return hash.compare(target) <= 0; - } } diff --git a/tslint.json b/tslint.json index 18bf61d..9708e8b 100644 --- a/tslint.json +++ b/tslint.json @@ -2,6 +2,7 @@ "defaultSeverity": "error", "extends": ["tslint:recommended"], "rules": { + "arrow-parens": [true, "ban-single-arg-parens"], "curly": false, "indent": [ true, @@ -12,6 +13,8 @@ "match-default-export-name": true, "max-classes-per-file": [false], "member-access": [true, "no-public"], + "no-bitwise": false, + "no-console": false, "no-empty": [true, "allow-empty-catch"], "no-implicit-dependencies": true, "no-return-await": true, diff --git a/types/block.d.ts b/types/block.d.ts index 8b4f2f1..6f2d5b9 100644 --- a/types/block.d.ts +++ b/types/block.d.ts @@ -1,6 +1,10 @@ /// import { Transaction } from './transaction'; export declare class Block { + static fromBuffer(buffer: Buffer): Block; + static fromHex(hex: string): Block; + static calculateTarget(bits: number): Buffer; + static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer; version: number; prevHash?: Buffer; merkleRoot?: Buffer; @@ -8,12 +12,8 @@ export declare class Block { witnessCommit?: Buffer; bits: number; nonce: number; - transactions?: Array; + transactions?: Transaction[]; constructor(); - static fromBuffer(buffer: Buffer): Block; - static fromHex(hex: string): Block; - static calculateTarget(bits: number): Buffer; - static calculateMerkleRoot(transactions: Array, forWitness?: boolean): Buffer; getWitnessCommit(): Buffer | null; hasWitnessCommit(): boolean; hasWitness(): boolean; @@ -25,7 +25,7 @@ export declare class Block { toHex(headersOnly: boolean): string; checkTxRoots(): boolean; checkMerkleRoot(): boolean; - __checkMerkleRoot(): boolean; - __checkWitnessCommit(): boolean; checkProofOfWork(): boolean; + private __checkMerkleRoot; + private __checkWitnessCommit; } From cb5ab7684e04d7add2ecc78d3749089a7f1b53b4 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 11:54:37 +0900 Subject: [PATCH 129/183] Fix classify.ts lint --- src/classify.js | 2 +- ts_src/classify.ts | 27 ++++++++++++--------------- types/classify.d.ts | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/classify.js b/src/classify.js index 0aec5c4..7d8e57d 100644 --- a/src/classify.js +++ b/src/classify.js @@ -6,9 +6,9 @@ const nullData = require("./templates/nulldata"); const pubKey = require("./templates/pubkey"); const pubKeyHash = require("./templates/pubkeyhash"); const scriptHash = require("./templates/scripthash"); +const witnessCommitment = require("./templates/witnesscommitment"); const witnessPubKeyHash = require("./templates/witnesspubkeyhash"); const witnessScriptHash = require("./templates/witnessscripthash"); -const witnessCommitment = require("./templates/witnesscommitment"); const types = { P2MS: 'multisig', NONSTANDARD: 'nonstandard', diff --git a/ts_src/classify.ts b/ts_src/classify.ts index 0de93f9..a7ec68c 100644 --- a/ts_src/classify.ts +++ b/ts_src/classify.ts @@ -4,20 +4,20 @@ import * as nullData from './templates/nulldata'; import * as pubKey from './templates/pubkey'; import * as pubKeyHash from './templates/pubkeyhash'; import * as scriptHash from './templates/scripthash'; +import * as witnessCommitment from './templates/witnesscommitment'; import * as witnessPubKeyHash from './templates/witnesspubkeyhash'; import * as witnessScriptHash from './templates/witnessscripthash'; -import * as witnessCommitment from './templates/witnesscommitment'; const types = { - P2MS: 'multisig', - NONSTANDARD: 'nonstandard', - NULLDATA: 'nulldata', - P2PK: 'pubkey', - P2PKH: 'pubkeyhash', - P2SH: 'scripthash', - P2WPKH: 'witnesspubkeyhash', - P2WSH: 'witnessscripthash', - WITNESS_COMMITMENT: 'witnesscommitment', + P2MS: 'multisig' as string, + NONSTANDARD: 'nonstandard' as string, + NULLDATA: 'nulldata' as string, + P2PK: 'pubkey' as string, + P2PKH: 'pubkeyhash' as string, + P2SH: 'scripthash' as string, + P2WPKH: 'witnesspubkeyhash' as string, + P2WSH: 'witnessscripthash' as string, + WITNESS_COMMITMENT: 'witnesscommitment' as string, }; function classifyOutput(script: Buffer): string { @@ -51,16 +51,13 @@ function classifyInput(script: Buffer, allowIncomplete: boolean): string { return types.NONSTANDARD; } -function classifyWitness( - script: Array, - allowIncomplete: boolean, -): string { +function classifyWitness(script: Buffer[], allowIncomplete: boolean): string { // XXX: optimization, below functions .decompile before use const chunks = decompile(script); if (!chunks) throw new TypeError('Invalid script'); if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH; - if (witnessScriptHash.input.check(>chunks, allowIncomplete)) + if (witnessScriptHash.input.check(chunks as Buffer[], allowIncomplete)) return types.P2WSH; return types.NONSTANDARD; diff --git a/types/classify.d.ts b/types/classify.d.ts index b394c71..67f913b 100644 --- a/types/classify.d.ts +++ b/types/classify.d.ts @@ -12,5 +12,5 @@ declare const types: { }; declare function classifyOutput(script: Buffer): string; declare function classifyInput(script: Buffer, allowIncomplete: boolean): string; -declare function classifyWitness(script: Array, allowIncomplete: boolean): string; +declare function classifyWitness(script: Buffer[], allowIncomplete: boolean): string; export { classifyInput as input, classifyOutput as output, classifyWitness as witness, types, }; From 6a734aef4c0dfc2503ee67ef878f3296291e0397 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:06:12 +0900 Subject: [PATCH 130/183] Fix lint for ecpair.ts --- src/ecpair.js | 22 +++++++++++----------- test/ecpair.js | 2 +- ts_src/ecpair.ts | 36 ++++++++++++++++++------------------ types/ecpair.d.ts | 4 ++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/ecpair.js b/src/ecpair.js index 7d376ac..1335014 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -17,30 +17,30 @@ class ECPair { this.compressed = options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.bitcoin; - this.__d = undefined; + this.__D = undefined; this.__Q = undefined; if (d !== undefined) - this.__d = d; + this.__D = d; if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed); } get privateKey() { - return this.__d; + return this.__D; } get publicKey() { if (!this.__Q) - this.__Q = ecc.pointFromScalar(this.__d, this.compressed); + this.__Q = ecc.pointFromScalar(this.__D, this.compressed); return this.__Q; } toWIF() { - if (!this.__d) + if (!this.__D) throw new Error('Missing private key'); - return wif.encode(this.network.wif, this.__d, this.compressed); + return wif.encode(this.network.wif, this.__D, this.compressed); } sign(hash) { - if (!this.__d) + if (!this.__D) throw new Error('Missing private key'); - return ecc.sign(hash, this.__d); + return ecc.sign(hash, this.__D); } verify(hash, signature) { return ecc.verify(hash, this.publicKey, signature); @@ -60,13 +60,13 @@ function fromPublicKey(buffer, options) { return new ECPair(undefined, buffer, options); } exports.fromPublicKey = fromPublicKey; -function fromWIF(string, network) { - const decoded = wif.decode(string); +function fromWIF(wifString, network) { + const decoded = wif.decode(wifString); const version = decoded.version; // list of networks? if (types.Array(network)) { network = network - .filter(function (x) { + .filter((x) => { return version === x.wif; }) .pop(); diff --git a/test/ecpair.js b/test/ecpair.js index 0ff0e8b..de5c485 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -238,7 +238,7 @@ describe('ECPair', function () { })) it('throws if no private key is found', function () { - delete keyPair.__d + delete keyPair.__D assert.throws(function () { keyPair.sign(hash) diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 15ec00a..ec8dc13 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -33,7 +33,7 @@ export interface ECPairInterface { class ECPair implements ECPairInterface { compressed: boolean; network: Network; - private __d?: Buffer; + private __D?: Buffer; private __Q?: Buffer; constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions) { @@ -42,29 +42,29 @@ class ECPair implements ECPairInterface { options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.bitcoin; - this.__d = undefined; + this.__D = undefined; this.__Q = undefined; - if (d !== undefined) this.__d = d; + if (d !== undefined) this.__D = d; if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed); } get privateKey(): Buffer | undefined { - return this.__d; + return this.__D; } get publicKey(): Buffer | undefined { - if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed); + if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); return this.__Q; } toWIF(): string { - if (!this.__d) throw new Error('Missing private key'); - return wif.encode(this.network.wif, this.__d, this.compressed); + if (!this.__D) throw new Error('Missing private key'); + return wif.encode(this.network.wif, this.__D, this.compressed); } sign(hash: Buffer): Buffer { - if (!this.__d) throw new Error('Missing private key'); - return ecc.sign(hash, this.__d); + if (!this.__D) throw new Error('Missing private key'); + return ecc.sign(hash, this.__D); } verify(hash: Buffer, signature: Buffer): Buffer { @@ -78,26 +78,26 @@ function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair { throw new TypeError('Private key not in range [1, n)'); typeforce(isOptions, options); - return new ECPair(buffer, undefined, options); + return new ECPair(buffer, undefined, options as ECPairOptions); } function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair { typeforce(ecc.isPoint, buffer); typeforce(isOptions, options); - return new ECPair(undefined, buffer, options); + return new ECPair(undefined, buffer, options as ECPairOptions); } -function fromWIF(string: string, network?: Network | Array): ECPair { - const decoded = wif.decode(string); +function fromWIF(wifString: string, network?: Network | Network[]): ECPair { + const decoded = wif.decode(wifString); const version = decoded.version; // list of networks? if (types.Array(network)) { - network = (>network) - .filter(function(x: Network) { + network = (network as Network[]) + .filter((x: Network) => { return version === x.wif; }) - .pop(); + .pop() as Network; if (!network) throw new Error('Unknown network version'); @@ -105,13 +105,13 @@ function fromWIF(string: string, network?: Network | Array): ECPair { } else { network = network || NETWORKS.bitcoin; - if (version !== (network).wif) + if (version !== (network as Network).wif) throw new Error('Invalid network version'); } return fromPrivateKey(decoded.privateKey, { compressed: decoded.compressed, - network: network, + network: network as Network, }); } diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index 58ea4be..674615b 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -18,7 +18,7 @@ export interface ECPairInterface { declare class ECPair implements ECPairInterface { compressed: boolean; network: Network; - private __d?; + private __D?; private __Q?; constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions); readonly privateKey: Buffer | undefined; @@ -29,6 +29,6 @@ declare class ECPair implements ECPairInterface { } declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair; declare function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair; -declare function fromWIF(string: string, network?: Network | Array): ECPair; +declare function fromWIF(wifString: string, network?: Network | Network[]): ECPair; declare function makeRandom(options?: ECPairOptions): ECPair; export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF }; From 3f34fe457abe6d19688416e566b6b340cfa959c8 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:11:15 +0900 Subject: [PATCH 131/183] Fix index.ts networks.ts lint --- src/index.js | 8 ++++---- ts_src/index.ts | 10 +++++----- ts_src/networks.ts | 10 +++++----- types/index.d.ts | 10 +++++----- types/networks.d.ts | 10 +++++----- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/index.js b/src/index.js index 7455d4a..73ac6f4 100644 --- a/src/index.js +++ b/src/index.js @@ -2,12 +2,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); const bip32 = require("bip32"); exports.bip32 = bip32; -const ECPair = require("./ecpair"); -exports.ECPair = ECPair; const address = require("./address"); exports.address = address; const crypto = require("./crypto"); exports.crypto = crypto; +const ECPair = require("./ecpair"); +exports.ECPair = ECPair; const networks = require("./networks"); exports.networks = networks; const payments = require("./payments"); @@ -16,9 +16,9 @@ const script = require("./script"); exports.script = script; var block_1 = require("./block"); exports.Block = block_1.Block; +var script_1 = require("./script"); +exports.opcodes = script_1.OPS; var transaction_1 = require("./transaction"); exports.Transaction = transaction_1.Transaction; var transaction_builder_1 = require("./transaction_builder"); exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; -var script_1 = require("./script"); -exports.opcodes = script_1.OPS; diff --git a/ts_src/index.ts b/ts_src/index.ts index fce7304..4e76c96 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -1,7 +1,7 @@ import * as bip32 from 'bip32'; -import * as ECPair from './ecpair'; import * as address from './address'; import * as crypto from './crypto'; +import * as ECPair from './ecpair'; import * as networks from './networks'; import * as payments from './payments'; import * as script from './script'; @@ -9,12 +9,12 @@ import * as script from './script'; export { ECPair, address, bip32, crypto, networks, payments, script }; export { Block } from './block'; +export { OPS as opcodes } from './script'; export { Transaction } from './transaction'; export { TransactionBuilder } from './transaction_builder'; -export { OPS as opcodes } from './script'; -export { Payment, PaymentOpts } from './payments'; -export { Input as TxInput, Output as TxOutput } from './transaction'; +export { BIP32Interface } from 'bip32'; export { Network } from './networks'; +export { Payment, PaymentOpts } from './payments'; export { OpCode } from './script'; -export { BIP32Interface } from 'bip32'; +export { Input as TxInput, Output as TxOutput } from './transaction'; diff --git a/ts_src/networks.ts b/ts_src/networks.ts index 0212a44..e66b08c 100644 --- a/ts_src/networks.ts +++ b/ts_src/networks.ts @@ -1,18 +1,18 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 -export type Network = { +export interface Network { messagePrefix: string; bech32: string; - bip32: bip32; + bip32: Bip32; pubKeyHash: number; scriptHash: number; wif: number; -}; +} -type bip32 = { +interface Bip32 { public: number; private: number; -}; +} export const bitcoin: Network = { messagePrefix: '\x18Bitcoin Signed Message:\n', diff --git a/types/index.d.ts b/types/index.d.ts index 3512872..d21454a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,17 +1,17 @@ import * as bip32 from 'bip32'; -import * as ECPair from './ecpair'; import * as address from './address'; import * as crypto from './crypto'; +import * as ECPair from './ecpair'; import * as networks from './networks'; import * as payments from './payments'; import * as script from './script'; export { ECPair, address, bip32, crypto, networks, payments, script }; export { Block } from './block'; +export { OPS as opcodes } from './script'; export { Transaction } from './transaction'; export { TransactionBuilder } from './transaction_builder'; -export { OPS as opcodes } from './script'; -export { Payment, PaymentOpts } from './payments'; -export { Input as TxInput, Output as TxOutput } from './transaction'; +export { BIP32Interface } from 'bip32'; export { Network } from './networks'; +export { Payment, PaymentOpts } from './payments'; export { OpCode } from './script'; -export { BIP32Interface } from 'bip32'; +export { Input as TxInput, Output as TxOutput } from './transaction'; diff --git a/types/networks.d.ts b/types/networks.d.ts index e402873..d5590fd 100644 --- a/types/networks.d.ts +++ b/types/networks.d.ts @@ -1,15 +1,15 @@ -export declare type Network = { +export interface Network { messagePrefix: string; bech32: string; - bip32: bip32; + bip32: Bip32; pubKeyHash: number; scriptHash: number; wif: number; -}; -declare type bip32 = { +} +interface Bip32 { public: number; private: number; -}; +} export declare const bitcoin: Network; export declare const regtest: Network; export declare const testnet: Network; From 389ec8cb33710d534d813a90cf7129b2f4e0dad4 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:29:24 +0900 Subject: [PATCH 132/183] Fix embed.ts and index.ts for payments lint --- src/payments/embed.js | 8 ++++---- ts_src/payments/embed.ts | 21 ++++++++++----------- ts_src/payments/index.ts | 11 +++++++---- types/payments/index.d.ts | 10 ++++++---- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/payments/embed.js b/src/payments/embed.js index 0e2a0ae..800c8de 100644 --- a/src/payments/embed.js +++ b/src/payments/embed.js @@ -1,14 +1,14 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const networks_1 = require("../networks"); const bscript = require("../script"); const lazy = require("./lazy"); -const networks_1 = require("../networks"); const typef = require('typeforce'); const OPS = bscript.OPS; function stacksEqual(a, b) { if (a.length !== b.length) return false; - return a.every(function (x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -24,12 +24,12 @@ function p2data(a, opts) { }, a); const network = a.network || networks_1.bitcoin; const o = { network }; - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!a.data) return; return bscript.compile([OPS.OP_RETURN].concat(a.data)); }); - lazy.prop(o, 'data', function () { + lazy.prop(o, 'data', () => { if (!a.output) return; return bscript.decompile(a.output).slice(1); diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index d7a2b0f..38a8162 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -1,14 +1,15 @@ -import { Payment, PaymentOpts } from './index'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; +import { Payment, PaymentOpts, Stack } from './index'; import * as lazy from './lazy'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; + const typef = require('typeforce'); const OPS = bscript.OPS; -function stacksEqual(a: Array, b: Array): boolean { +function stacksEqual(a: Buffer[], b: Buffer[]): boolean { if (a.length !== b.length) return false; - return a.every(function(x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -28,15 +29,13 @@ export function p2data(a: Payment, opts?: PaymentOpts): Payment { ); const network = a.network || BITCOIN_NETWORK; - const o = { network }; + const o = { network } as Payment; - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!a.data) return; - return bscript.compile( - (>[OPS.OP_RETURN]).concat(a.data), - ); + return bscript.compile(([OPS.OP_RETURN] as Stack).concat(a.data)); }); - lazy.prop(o, 'data', function() { + lazy.prop(o, 'data', () => { if (!a.output) return; return bscript.decompile(a.output)!.slice(1); }); @@ -50,7 +49,7 @@ export function p2data(a: Payment, opts?: PaymentOpts): Payment { if (!chunks!.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid'); - if (a.data && !stacksEqual(a.data, >o.data)) + if (a.data && !stacksEqual(a.data, o.data as Buffer[])) throw new TypeError('Data mismatch'); } } diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 6727eeb..4f6eb75 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -10,18 +10,18 @@ import { p2wsh } from './p2wsh'; export interface Payment { network?: Network; output?: Buffer; - data?: Array; + data?: Buffer[]; m?: number; n?: number; - pubkeys?: Array; + pubkeys?: Buffer[]; input?: Buffer; - signatures?: Array; + signatures?: Buffer[]; pubkey?: Buffer; signature?: Buffer; address?: string; hash?: Buffer; redeem?: Payment; - witness?: Array; + witness?: Buffer[]; } export interface PaymentOpts { @@ -29,6 +29,9 @@ export interface PaymentOpts { allowIncomplete?: boolean; } +export type StackElement = Buffer | number; +export type Stack = StackElement[]; + export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; // TODO diff --git a/types/payments/index.d.ts b/types/payments/index.d.ts index 5afc847..3009bef 100644 --- a/types/payments/index.d.ts +++ b/types/payments/index.d.ts @@ -10,21 +10,23 @@ import { p2wsh } from './p2wsh'; export interface Payment { network?: Network; output?: Buffer; - data?: Array; + data?: Buffer[]; m?: number; n?: number; - pubkeys?: Array; + pubkeys?: Buffer[]; input?: Buffer; - signatures?: Array; + signatures?: Buffer[]; pubkey?: Buffer; signature?: Buffer; address?: string; hash?: Buffer; redeem?: Payment; - witness?: Array; + witness?: Buffer[]; } export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; } +export declare type StackElement = Buffer | number; +export declare type Stack = StackElement[]; export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; From db937f8110ad9e9f42a5b53922cb2e2d994719a0 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:33:47 +0900 Subject: [PATCH 133/183] Fix lazy.ts in payments lint --- src/payments/lazy.js | 24 ++++++++++++------------ ts_src/payments/lazy.ts | 24 ++++++++++++------------ types/payments/lazy.d.ts | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/payments/lazy.js b/src/payments/lazy.js index 9eda8e8..d8494fd 100644 --- a/src/payments/lazy.js +++ b/src/payments/lazy.js @@ -4,16 +4,16 @@ function prop(object, name, f) { Object.defineProperty(object, name, { configurable: true, enumerable: true, - get: function () { - let value = f.call(this); - this[name] = value; - return value; + get() { + const _value = f.call(this); + this[name] = _value; + return _value; }, - set: function (value) { + set(_value) { Object.defineProperty(this, name, { configurable: true, enumerable: true, - value: value, + value: _value, writable: true, }); }, @@ -21,12 +21,12 @@ function prop(object, name, f) { } exports.prop = prop; function value(f) { - let value; - return function () { - if (value !== undefined) - return value; - value = f(); - return value; + let _value; + return () => { + if (_value !== undefined) + return _value; + _value = f(); + return _value; }; } exports.value = value; diff --git a/ts_src/payments/lazy.ts b/ts_src/payments/lazy.ts index 474c8e9..fe0fb6d 100644 --- a/ts_src/payments/lazy.ts +++ b/ts_src/payments/lazy.ts @@ -1,17 +1,17 @@ -export function prop(object: Object, name: string, f: () => any): void { +export function prop(object: {}, name: string, f: () => any): void { Object.defineProperty(object, name, { configurable: true, enumerable: true, - get: function() { - let value = f.call(this); - this[name] = value; - return value; + get() { + const _value = f.call(this); + this[name] = _value; + return _value; }, - set: function(value) { + set(_value) { Object.defineProperty(this, name, { configurable: true, enumerable: true, - value: value, + value: _value, writable: true, }); }, @@ -19,10 +19,10 @@ export function prop(object: Object, name: string, f: () => any): void { } export function value(f: () => T): () => T { - let value: T; - return function(): T { - if (value !== undefined) return value; - value = f(); - return value; + let _value: T; + return (): T => { + if (_value !== undefined) return _value; + _value = f(); + return _value; }; } diff --git a/types/payments/lazy.d.ts b/types/payments/lazy.d.ts index 705f530..3463906 100644 --- a/types/payments/lazy.d.ts +++ b/types/payments/lazy.d.ts @@ -1,2 +1,2 @@ -export declare function prop(object: Object, name: string, f: () => any): void; +export declare function prop(object: {}, name: string, f: () => any): void; export declare function value(f: () => T): () => T; From 4054f3ae879a8840933e622410224d7e5b0a868c Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:40:18 +0900 Subject: [PATCH 134/183] Fix lint for p2ms payment --- src/payments/p2ms.js | 18 ++++++++--------- ts_src/payments/p2ms.ts | 44 ++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index 1e51faa..5e48432 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const networks_1 = require("../networks"); const bscript = require("../script"); const lazy = require("./lazy"); -const networks_1 = require("../networks"); const OPS = bscript.OPS; const typef = require('typeforce'); const ecc = require('tiny-secp256k1'); @@ -10,7 +10,7 @@ const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 function stacksEqual(a, b) { if (a.length !== b.length) return false; - return a.every(function (x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -49,7 +49,7 @@ function p2ms(a, opts) { o.n = chunks[chunks.length - 2] - OP_INT_BASE; o.pubkeys = chunks.slice(1, -2); } - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!a.m) return; if (!o.n) @@ -58,34 +58,34 @@ function p2ms(a, opts) { return; return bscript.compile([].concat(OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, OPS.OP_CHECKMULTISIG)); }); - lazy.prop(o, 'm', function () { + lazy.prop(o, 'm', () => { if (!o.output) return; decode(o.output); return o.m; }); - lazy.prop(o, 'n', function () { + lazy.prop(o, 'n', () => { if (!o.pubkeys) return; return o.pubkeys.length; }); - lazy.prop(o, 'pubkeys', function () { + lazy.prop(o, 'pubkeys', () => { if (!a.output) return; decode(a.output); return o.pubkeys; }); - lazy.prop(o, 'signatures', function () { + lazy.prop(o, 'signatures', () => { if (!a.input) return; return bscript.decompile(a.input).slice(1); }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!a.signatures) return; return bscript.compile([OPS.OP_0].concat(a.signatures)); }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index 766f341..b8691c0 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -1,17 +1,17 @@ -import { Payment, PaymentOpts } from './index'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; +import { Payment, PaymentOpts, Stack } from './index'; import * as lazy from './lazy'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; const OPS = bscript.OPS; const typef = require('typeforce'); const ecc = require('tiny-secp256k1'); const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 -function stacksEqual(a: Array, b: Array): boolean { +function stacksEqual(a: Buffer[], b: Buffer[]): boolean { if (a.length !== b.length) return false; - return a.every(function(x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -30,8 +30,8 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { function isAcceptableSignature(x: Buffer | number) { return ( - bscript.isCanonicalScriptSignature(x) || - (opts!.allowIncomplete && x === OPS.OP_0) !== undefined + bscript.isCanonicalScriptSignature(x as Buffer) || + (opts!.allowIncomplete && (x as number) === OPS.OP_0) !== undefined ); } @@ -52,23 +52,23 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { const network = a.network || BITCOIN_NETWORK; const o: Payment = { network }; - let chunks: Array = []; + let chunks: Stack = []; let decoded = false; - function decode(output: Buffer | Array): void { + function decode(output: Buffer | Stack): void { if (decoded) return; decoded = true; - chunks = >bscript.decompile(output); - o.m = chunks[0] - OP_INT_BASE; - o.n = chunks[chunks.length - 2] - OP_INT_BASE; - o.pubkeys = >chunks.slice(1, -2); + chunks = bscript.decompile(output) as Stack; + o.m = (chunks[0] as number) - OP_INT_BASE; + o.n = (chunks[chunks.length - 2] as number) - OP_INT_BASE; + o.pubkeys = chunks.slice(1, -2) as Buffer[]; } - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!a.m) return; if (!o.n) return; if (!a.pubkeys) return; return bscript.compile( - (>[]).concat( + ([] as Stack).concat( OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, @@ -76,31 +76,29 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { ), ); }); - lazy.prop(o, 'm', function() { + lazy.prop(o, 'm', () => { if (!o.output) return; decode(o.output); return o.m; }); - lazy.prop(o, 'n', function() { + lazy.prop(o, 'n', () => { if (!o.pubkeys) return; return o.pubkeys.length; }); - lazy.prop(o, 'pubkeys', function() { + lazy.prop(o, 'pubkeys', () => { if (!a.output) return; decode(a.output); return o.pubkeys; }); - lazy.prop(o, 'signatures', function() { + lazy.prop(o, 'signatures', () => { if (!a.input) return; return bscript.decompile(a.input)!.slice(1); }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!a.signatures) return; - return bscript.compile( - (>[OPS.OP_0]).concat(a.signatures), - ); + return bscript.compile(([OPS.OP_0] as Stack).concat(a.signatures)); }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; }); From 8d5d78431c8e8b6a5ffbfb167d66cedb63febfd6 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:47:26 +0900 Subject: [PATCH 135/183] Fix P2PK payment lint --- src/payments/p2pk.js | 14 +++++++------- ts_src/payments/index.ts | 1 + ts_src/payments/p2pk.ts | 20 ++++++++++---------- types/payments/index.d.ts | 1 + 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 9c9318f..81fe427 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const networks_1 = require("../networks"); const bscript = require("../script"); const lazy = require("./lazy"); -const networks_1 = require("../networks"); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -19,32 +19,32 @@ function p2pk(a, opts) { signature: typef.maybe(bscript.isCanonicalScriptSignature), input: typef.maybe(typef.Buffer), }, a); - const _chunks = lazy.value(function () { + const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); const network = a.network || networks_1.bitcoin; const o = { network }; - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!a.pubkey) return; return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); }); - lazy.prop(o, 'pubkey', function () { + lazy.prop(o, 'pubkey', () => { if (!a.output) return; return a.output.slice(1, -1); }); - lazy.prop(o, 'signature', function () { + lazy.prop(o, 'signature', () => { if (!a.input) return; return _chunks()[0]; }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!a.signature) return; return bscript.compile([a.signature]); }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 4f6eb75..0c70fba 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -31,6 +31,7 @@ export interface PaymentOpts { export type StackElement = Buffer | number; export type Stack = StackElement[]; +export type StackFunction = () => Stack; export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index 69fb404..d14aacf 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -1,7 +1,7 @@ -import { Payment, PaymentOpts } from './index'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; +import { Payment, PaymentOpts, StackFunction } from './index'; import * as lazy from './lazy'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -25,30 +25,30 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { a, ); - const _chunks = <() => Array>lazy.value(function() { + const _chunks = lazy.value(() => { return bscript.decompile(a.input!); - }); + }) as StackFunction; const network = a.network || BITCOIN_NETWORK; const o: Payment = { network }; - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!a.pubkey) return; return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); }); - lazy.prop(o, 'pubkey', function() { + lazy.prop(o, 'pubkey', () => { if (!a.output) return; return a.output.slice(1, -1); }); - lazy.prop(o, 'signature', function() { + lazy.prop(o, 'signature', () => { if (!a.input) return; - return _chunks()[0]; + return _chunks()[0] as Buffer; }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!a.signature) return; return bscript.compile([a.signature]); }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; }); diff --git a/types/payments/index.d.ts b/types/payments/index.d.ts index 3009bef..66654d2 100644 --- a/types/payments/index.d.ts +++ b/types/payments/index.d.ts @@ -29,4 +29,5 @@ export interface PaymentOpts { } export declare type StackElement = Buffer | number; export declare type Stack = StackElement[]; +export declare type StackFunction = () => Stack; export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; From db0e3f1203ae50ba03a58a19f424a2fe7c75bf75 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:51:22 +0900 Subject: [PATCH 136/183] Fix lint payments p2pkh --- src/payments/p2pkh.js | 22 +++++++++++----------- ts_src/payments/p2pkh.ts | 38 +++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 6b41a77..9f06bde 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../script"); const bcrypto = require("../crypto"); -const lazy = require("./lazy"); const networks_1 = require("../networks"); +const bscript = require("../script"); +const lazy = require("./lazy"); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -23,18 +23,18 @@ function p2pkh(a, opts) { signature: typef.maybe(bscript.isCanonicalScriptSignature), input: typef.maybe(typef.Buffer), }, a); - const _address = lazy.value(function () { + const _address = lazy.value(() => { const payload = bs58check.decode(a.address); const version = payload.readUInt8(0); const hash = payload.slice(1); return { version, hash }; }); - const _chunks = lazy.value(function () { + const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); const network = a.network || networks_1.bitcoin; const o = { network }; - lazy.prop(o, 'address', function () { + lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = Buffer.allocUnsafe(21); @@ -42,7 +42,7 @@ function p2pkh(a, opts) { o.hash.copy(payload, 1); return bs58check.encode(payload); }); - lazy.prop(o, 'hash', function () { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(3, 23); if (a.address) @@ -50,7 +50,7 @@ function p2pkh(a, opts) { if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); }); - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([ @@ -61,24 +61,24 @@ function p2pkh(a, opts) { OPS.OP_CHECKSIG, ]); }); - lazy.prop(o, 'pubkey', function () { + lazy.prop(o, 'pubkey', () => { if (!a.input) return; return _chunks()[1]; }); - lazy.prop(o, 'signature', function () { + lazy.prop(o, 'signature', () => { if (!a.input) return; return _chunks()[0]; }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!a.pubkey) return; if (!a.signature) return; return bscript.compile([a.signature, a.pubkey]); }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index 63594ad..12c9473 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -1,8 +1,8 @@ -import { Payment, PaymentOpts } from './index'; -import * as bscript from '../script'; import * as bcrypto from '../crypto'; -import * as lazy from './lazy'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { Payment, PaymentOpts, StackFunction } from './index'; +import * as lazy from './lazy'; const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -30,20 +30,20 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { a, ); - const _address = lazy.value(function() { + const _address = lazy.value(() => { const payload = bs58check.decode(a.address); const version = payload.readUInt8(0); const hash = payload.slice(1); return { version, hash }; }); - const _chunks = <() => Array>lazy.value(function() { + const _chunks = lazy.value(() => { return bscript.decompile(a.input!); - }); + }) as StackFunction; const network = a.network || BITCOIN_NETWORK; const o: Payment = { network }; - lazy.prop(o, 'address', function() { + lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = Buffer.allocUnsafe(21); @@ -51,12 +51,12 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { o.hash.copy(payload, 1); return bs58check.encode(payload); }); - lazy.prop(o, 'hash', function() { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(3, 23); if (a.address) return _address().hash; if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!); }); - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([ OPS.OP_DUP, @@ -66,20 +66,20 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { OPS.OP_CHECKSIG, ]); }); - lazy.prop(o, 'pubkey', function() { + lazy.prop(o, 'pubkey', () => { if (!a.input) return; - return _chunks()[1]; + return _chunks()[1] as Buffer; }); - lazy.prop(o, 'signature', function() { + lazy.prop(o, 'signature', () => { if (!a.input) return; - return _chunks()[0]; + return _chunks()[0] as Buffer; }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!a.pubkey) return; if (!a.signature) return; return bscript.compile([a.signature, a.pubkey]); }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { if (!o.input) return; return []; }); @@ -127,17 +127,17 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { if (a.input) { const chunks = _chunks(); if (chunks.length !== 2) throw new TypeError('Input is invalid'); - if (!bscript.isCanonicalScriptSignature(chunks[0])) + if (!bscript.isCanonicalScriptSignature(chunks[0] as Buffer)) throw new TypeError('Input has invalid signature'); if (!ecc.isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); - if (a.signature && !a.signature.equals(chunks[0])) + if (a.signature && !a.signature.equals(chunks[0] as Buffer)) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(chunks[1])) + if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) throw new TypeError('Pubkey mismatch'); - const pkh = bcrypto.hash160(chunks[1]); + const pkh = bcrypto.hash160(chunks[1] as Buffer); if (hash.length > 0 && !hash.equals(pkh)) throw new TypeError('Hash mismatch'); } From fe62e130236624d84c7ee78e0679af4fcc7bd136 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 12:59:52 +0900 Subject: [PATCH 137/183] Fix lint payments p2sh --- src/payments/p2sh.js | 26 ++++++++-------- ts_src/payments/index.ts | 2 ++ ts_src/payments/p2sh.ts | 62 +++++++++++++++++++++------------------ types/payments/index.d.ts | 1 + 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index f98ef71..e419deb 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const bcrypto = require("../crypto"); const networks_1 = require("../networks"); const bscript = require("../script"); -const bcrypto = require("../crypto"); const lazy = require("./lazy"); const typef = require('typeforce'); const OPS = bscript.OPS; @@ -10,7 +10,7 @@ const bs58check = require('bs58check'); function stacksEqual(a, b) { if (a.length !== b.length) return false; - return a.every(function (x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -40,16 +40,16 @@ function p2sh(a, opts) { network = (a.redeem && a.redeem.network) || networks_1.bitcoin; } const o = { network }; - const _address = lazy.value(function () { + const _address = lazy.value(() => { const payload = bs58check.decode(a.address); const version = payload.readUInt8(0); const hash = payload.slice(1); return { version, hash }; }); - const _chunks = lazy.value(function () { + const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); - const _redeem = lazy.value(function () { + const _redeem = lazy.value(() => { const chunks = _chunks(); return { network, @@ -59,7 +59,7 @@ function p2sh(a, opts) { }; }); // output dependents - lazy.prop(o, 'address', function () { + lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = Buffer.allocUnsafe(21); @@ -67,7 +67,7 @@ function p2sh(a, opts) { o.hash.copy(payload, 1); return bs58check.encode(payload); }); - lazy.prop(o, 'hash', function () { + lazy.prop(o, 'hash', () => { // in order of least effort if (a.output) return a.output.slice(2, 22); @@ -76,23 +76,23 @@ function p2sh(a, opts) { if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); }); - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); }); // input dependents - lazy.prop(o, 'redeem', function () { + lazy.prop(o, 'redeem', () => { if (!a.input) return; return _redeem(); }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!a.redeem || !a.redeem.input || !a.redeem.output) return; return bscript.compile([].concat(bscript.decompile(a.redeem.input), a.redeem.output)); }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { if (o.redeem && o.redeem.witness) return o.redeem.witness; if (o.input) @@ -126,7 +126,7 @@ function p2sh(a, opts) { hash = hash2; } // inlined to prevent 'no-inner-declarations' failing - const checkRedeem = function (redeem) { + const checkRedeem = (redeem) => { // is the redeem output empty/invalid? if (redeem.output) { const decompile = bscript.decompile(redeem.output); @@ -147,7 +147,7 @@ function p2sh(a, opts) { if (hasInput && hasWitness) throw new TypeError('Input and witness provided'); if (hasInput) { - const richunks = (bscript.decompile(redeem.input)); + const richunks = bscript.decompile(redeem.input); if (!bscript.isPushOnly(richunks)) throw new TypeError('Non push-only scriptSig'); } diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 0c70fba..acd6ddb 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -24,6 +24,8 @@ export interface Payment { witness?: Buffer[]; } +export type PaymentFunction = () => Payment; + export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index b7df1dc..46c11cc 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -1,17 +1,23 @@ -import { Payment, PaymentOpts } from './index'; +import * as bcrypto from '../crypto'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; -import * as bcrypto from '../crypto'; +import { + Payment, + PaymentFunction, + PaymentOpts, + Stack, + StackFunction, +} from './index'; import * as lazy from './lazy'; const typef = require('typeforce'); const OPS = bscript.OPS; const bs58check = require('bs58check'); -function stacksEqual(a: Array, b: Array): boolean { +function stacksEqual(a: Buffer[], b: Buffer[]): boolean { if (a.length !== b.length) return false; - return a.every(function(x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -51,27 +57,29 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { const o: Payment = { network }; - const _address = lazy.value(function() { + const _address = lazy.value(() => { const payload = bs58check.decode(a.address); const version = payload.readUInt8(0); const hash = payload.slice(1); return { version, hash }; }); - const _chunks = <() => Array>lazy.value(function() { + const _chunks = lazy.value(() => { return bscript.decompile(a.input!); - }); - const _redeem = lazy.value(function(): Payment { - const chunks = _chunks(); - return { - network, - output: chunks[chunks.length - 1], - input: bscript.compile(chunks.slice(0, -1)), - witness: a.witness || [], - }; - }); + }) as StackFunction; + const _redeem = lazy.value( + (): Payment => { + const chunks = _chunks(); + return { + network, + output: chunks[chunks.length - 1] as Buffer, + input: bscript.compile(chunks.slice(0, -1)), + witness: a.witness || [], + }; + }, + ) as PaymentFunction; // output dependents - lazy.prop(o, 'address', function() { + lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = Buffer.allocUnsafe(21); @@ -79,32 +87,32 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { o.hash.copy(payload, 1); return bs58check.encode(payload); }); - lazy.prop(o, 'hash', function() { + lazy.prop(o, 'hash', () => { // in order of least effort if (a.output) return a.output.slice(2, 22); if (a.address) return _address().hash; if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); }); - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); }); // input dependents - lazy.prop(o, 'redeem', function() { + lazy.prop(o, 'redeem', () => { if (!a.input) return; return _redeem(); }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!a.redeem || !a.redeem.input || !a.redeem.output) return; return bscript.compile( - (>[]).concat( - >bscript.decompile(a.redeem.input), + ([] as Stack).concat( + bscript.decompile(a.redeem.input) as Stack, a.redeem.output, ), ); }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { if (o.redeem && o.redeem.witness) return o.redeem.witness; if (o.input) return []; }); @@ -140,7 +148,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { } // inlined to prevent 'no-inner-declarations' failing - const checkRedeem = function(redeem: Payment): void { + const checkRedeem = (redeem: Payment): void => { // is the redeem output empty/invalid? if (redeem.output) { const decompile = bscript.decompile(redeem.output); @@ -161,9 +169,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { if (hasInput && hasWitness) throw new TypeError('Input and witness provided'); if (hasInput) { - const richunks = >( - bscript.decompile(redeem.input) - ); + const richunks = bscript.decompile(redeem.input) as Stack; if (!bscript.isPushOnly(richunks)) throw new TypeError('Non push-only scriptSig'); } diff --git a/types/payments/index.d.ts b/types/payments/index.d.ts index 66654d2..102f20a 100644 --- a/types/payments/index.d.ts +++ b/types/payments/index.d.ts @@ -23,6 +23,7 @@ export interface Payment { redeem?: Payment; witness?: Buffer[]; } +export declare type PaymentFunction = () => Payment; export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; From 3ddb88168d8248f3fb86f5e6a8ced725864b5b70 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 13:01:40 +0900 Subject: [PATCH 138/183] Fix lint payments p2wpkh --- src/payments/p2wpkh.js | 20 ++++++++++---------- ts_src/payments/p2wpkh.ts | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index 9165f96..9e99610 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../script"); const bcrypto = require("../crypto"); -const lazy = require("./lazy"); const networks_1 = require("../networks"); +const bscript = require("../script"); +const lazy = require("./lazy"); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -26,7 +26,7 @@ function p2wpkh(a, opts) { signature: typef.maybe(bscript.isCanonicalScriptSignature), witness: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); - const _address = lazy.value(function () { + const _address = lazy.value(() => { const result = bech32.decode(a.address); const version = result.words.shift(); const data = bech32.fromWords(result.words); @@ -38,14 +38,14 @@ function p2wpkh(a, opts) { }); const network = a.network || networks_1.bitcoin; const o = { network }; - lazy.prop(o, 'address', function () { + lazy.prop(o, 'address', () => { if (!o.hash) return; const words = bech32.toWords(o.hash); words.unshift(0x00); return bech32.encode(network.bech32, words); }); - lazy.prop(o, 'hash', function () { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2, 22); if (a.address) @@ -53,29 +53,29 @@ function p2wpkh(a, opts) { if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); }); - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_0, o.hash]); }); - lazy.prop(o, 'pubkey', function () { + lazy.prop(o, 'pubkey', () => { if (a.pubkey) return a.pubkey; if (!a.witness) return; return a.witness[1]; }); - lazy.prop(o, 'signature', function () { + lazy.prop(o, 'signature', () => { if (!a.witness) return; return a.witness[0]; }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!o.witness) return; return EMPTY_BUFFER; }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { if (!a.pubkey) return; if (!a.signature) diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index 04f0e92..7d2748c 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -1,8 +1,8 @@ -import { Payment, PaymentOpts } from './index'; -import * as bscript from '../script'; import * as bcrypto from '../crypto'; -import * as lazy from './lazy'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { Payment, PaymentOpts } from './index'; +import * as lazy from './lazy'; const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -33,7 +33,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { a, ); - const _address = lazy.value(function() { + const _address = lazy.value(() => { const result = bech32.decode(a.address); const version = result.words.shift(); const data = bech32.fromWords(result.words); @@ -47,36 +47,36 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { const network = a.network || BITCOIN_NETWORK; const o: Payment = { network }; - lazy.prop(o, 'address', function() { + lazy.prop(o, 'address', () => { if (!o.hash) return; const words = bech32.toWords(o.hash); words.unshift(0x00); return bech32.encode(network.bech32, words); }); - lazy.prop(o, 'hash', function() { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2, 22); if (a.address) return _address().data; if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!); }); - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_0, o.hash]); }); - lazy.prop(o, 'pubkey', function() { + lazy.prop(o, 'pubkey', () => { if (a.pubkey) return a.pubkey; if (!a.witness) return; return a.witness[1]; }); - lazy.prop(o, 'signature', function() { + lazy.prop(o, 'signature', () => { if (!a.witness) return; return a.witness[0]; }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!o.witness) return; return EMPTY_BUFFER; }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { if (!a.pubkey) return; if (!a.signature) return; return [a.signature, a.pubkey]; From f058140ea8a0313b319d59b6c17c02d3fa1587cc Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 13:05:04 +0900 Subject: [PATCH 139/183] Fix lint payments p2wsh --- src/payments/p2wsh.js | 20 ++++++++++---------- ts_src/payments/p2wsh.ts | 30 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index 7c71ac3..0def430 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +const bcrypto = require("../crypto"); const networks_1 = require("../networks"); const bscript = require("../script"); -const bcrypto = require("../crypto"); const lazy = require("./lazy"); const typef = require('typeforce'); const OPS = bscript.OPS; @@ -11,7 +11,7 @@ const EMPTY_BUFFER = Buffer.alloc(0); function stacksEqual(a, b) { if (a.length !== b.length) return false; - return a.every(function (x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -36,7 +36,7 @@ function p2wsh(a, opts) { input: typef.maybe(typef.BufferN(0)), witness: typef.maybe(typef.arrayOf(typef.Buffer)), }, a); - const _address = lazy.value(function () { + const _address = lazy.value(() => { const result = bech32.decode(a.address); const version = result.words.shift(); const data = bech32.fromWords(result.words); @@ -46,7 +46,7 @@ function p2wsh(a, opts) { data: Buffer.from(data), }; }); - const _rchunks = lazy.value(function () { + const _rchunks = lazy.value(() => { return bscript.decompile(a.redeem.input); }); let network = a.network; @@ -54,14 +54,14 @@ function p2wsh(a, opts) { network = (a.redeem && a.redeem.network) || networks_1.bitcoin; } const o = { network }; - lazy.prop(o, 'address', function () { + lazy.prop(o, 'address', () => { if (!o.hash) return; const words = bech32.toWords(o.hash); words.unshift(0x00); return bech32.encode(network.bech32, words); }); - lazy.prop(o, 'hash', function () { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2); if (a.address) @@ -69,12 +69,12 @@ function p2wsh(a, opts) { if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); }); - lazy.prop(o, 'output', function () { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_0, o.hash]); }); - lazy.prop(o, 'redeem', function () { + lazy.prop(o, 'redeem', () => { if (!a.witness) return; return { @@ -83,12 +83,12 @@ function p2wsh(a, opts) { witness: a.witness.slice(0, -1), }; }); - lazy.prop(o, 'input', function () { + lazy.prop(o, 'input', () => { if (!o.witness) return; return EMPTY_BUFFER; }); - lazy.prop(o, 'witness', function () { + lazy.prop(o, 'witness', () => { // transform redeem input to witness stack? if (a.redeem && a.redeem.input && diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 28a235c..131de45 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -1,7 +1,7 @@ -import { Payment, PaymentOpts } from './index'; +import * as bcrypto from '../crypto'; import { bitcoin as BITCOIN_NETWORK } from '../networks'; import * as bscript from '../script'; -import * as bcrypto from '../crypto'; +import { Payment, PaymentOpts, StackFunction } from './index'; import * as lazy from './lazy'; const typef = require('typeforce'); const OPS = bscript.OPS; @@ -10,10 +10,10 @@ const bech32 = require('bech32'); const EMPTY_BUFFER = Buffer.alloc(0); -function stacksEqual(a: Array, b: Array): boolean { +function stacksEqual(a: Buffer[], b: Buffer[]): boolean { if (a.length !== b.length) return false; - return a.every(function(x, i) { + return a.every((x, i) => { return x.equals(b[i]); }); } @@ -46,7 +46,7 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { a, ); - const _address = lazy.value(function() { + const _address = lazy.value(() => { const result = bech32.decode(a.address); const version = result.words.shift(); const data = bech32.fromWords(result.words); @@ -56,9 +56,9 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { data: Buffer.from(data), }; }); - const _rchunks = <() => Array>lazy.value(function() { + const _rchunks = lazy.value(() => { return bscript.decompile(a.redeem!.input!); - }); + }) as StackFunction; let network = a.network; if (!network) { @@ -67,22 +67,22 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { const o: Payment = { network }; - lazy.prop(o, 'address', function() { + lazy.prop(o, 'address', () => { if (!o.hash) return; const words = bech32.toWords(o.hash); words.unshift(0x00); return bech32.encode(network!.bech32, words); }); - lazy.prop(o, 'hash', function() { + lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2); if (a.address) return _address().data; if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); }); - lazy.prop(o, 'output', function() { + lazy.prop(o, 'output', () => { if (!o.hash) return; return bscript.compile([OPS.OP_0, o.hash]); }); - lazy.prop(o, 'redeem', function() { + lazy.prop(o, 'redeem', () => { if (!a.witness) return; return { output: a.witness[a.witness.length - 1], @@ -90,11 +90,11 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { witness: a.witness.slice(0, -1), }; }); - lazy.prop(o, 'input', function() { + lazy.prop(o, 'input', () => { if (!o.witness) return; return EMPTY_BUFFER; }); - lazy.prop(o, 'witness', function() { + lazy.prop(o, 'witness', () => { // transform redeem input to witness stack? if ( a.redeem && @@ -108,13 +108,13 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { // assign, and blank the existing input o.redeem = Object.assign({ witness: stack }, a.redeem); o.redeem.input = EMPTY_BUFFER; - return (>[]).concat(stack, a.redeem.output); + return ([] as Buffer[]).concat(stack, a.redeem.output); } if (!a.redeem) return; if (!a.redeem.output) return; if (!a.redeem.witness) return; - return (>[]).concat(a.redeem.witness, a.redeem.output); + return ([] as Buffer[]).concat(a.redeem.witness, a.redeem.output); }); // extended validation From c2c650812e74a150220cdc05475d2c7e95b4d3fd Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 13:17:03 +0900 Subject: [PATCH 140/183] Fix lint script.ts --- src/script.js | 13 +++++++------ ts_src/script.ts | 40 +++++++++++++++++++--------------------- types/script.d.ts | 7 ++++--- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/script.js b/src/script.js index a114d1f..ac334f8 100644 --- a/src/script.js +++ b/src/script.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const types = require("./types"); const scriptNumber = require("./script_number"); const scriptSignature = require("./script_signature"); +const types = require("./types"); const bip66 = require('bip66'); const ecc = require('tiny-secp256k1'); const pushdata = require('pushdata-bitcoin'); @@ -47,7 +47,7 @@ function compile(chunks) { if (chunksIsBuffer(chunks)) return chunks; typeforce(types.Array, chunks); - const bufferSize = chunks.reduce(function (accum, chunk) { + const bufferSize = chunks.reduce((accum, chunk) => { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy @@ -61,7 +61,7 @@ function compile(chunks) { }, 0.0); const buffer = Buffer.allocUnsafe(bufferSize); let offset = 0; - chunks.forEach(function (chunk) { + chunks.forEach(chunk => { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy @@ -130,7 +130,7 @@ function toASM(chunks) { chunks = decompile(chunks); } return chunks - .map(function (chunk) { + .map(chunk => { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); @@ -146,7 +146,7 @@ function toASM(chunks) { exports.toASM = toASM; function fromASM(asm) { typeforce(types.String, asm); - return compile(asm.split(' ').map(function (chunkStr) { + return compile(asm.split(' ').map(chunkStr => { // opcode? if (exports.OPS[chunkStr] !== undefined) return exports.OPS[chunkStr]; @@ -159,7 +159,7 @@ exports.fromASM = fromASM; function toStack(chunks) { chunks = decompile(chunks); typeforce(isPushOnly, chunks); - return chunks.map(function (op) { + return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; if (op === exports.OPS.OP_0) @@ -186,5 +186,6 @@ function isCanonicalScriptSignature(buffer) { return bip66.check(buffer.slice(0, -1)); } exports.isCanonicalScriptSignature = isCanonicalScriptSignature; +// tslint:disable-next-line variable-name exports.number = scriptNumber; exports.signature = scriptSignature; diff --git a/ts_src/script.ts b/ts_src/script.ts index 36fef95..1c705d3 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -1,15 +1,16 @@ -import * as types from './types'; +import { Stack } from './payments'; import * as scriptNumber from './script_number'; import * as scriptSignature from './script_signature'; +import * as types from './types'; const bip66 = require('bip66'); const ecc = require('tiny-secp256k1'); const pushdata = require('pushdata-bitcoin'); const typeforce = require('typeforce'); export type OpCode = number; -export const OPS = <{ [index: string]: OpCode }>require('bitcoin-ops'); +export const OPS = require('bitcoin-ops') as { [index: string]: OpCode }; -const REVERSE_OPS = <{ [index: number]: string }>require('bitcoin-ops/map'); +const REVERSE_OPS = require('bitcoin-ops/map') as { [index: number]: string }; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 function isOPInt(value: number): boolean { @@ -22,10 +23,10 @@ function isOPInt(value: number): boolean { } function isPushOnlyChunk(value: number | Buffer): boolean { - return types.Buffer(value) || isOPInt(value); + return types.Buffer(value) || isOPInt(value as number); } -export function isPushOnly(value: Array) { +export function isPushOnly(value: Stack) { return types.Array(value) && value.every(isPushOnlyChunk); } @@ -36,13 +37,11 @@ function asMinimalOP(buffer: Buffer): number | void { if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } -function chunksIsBuffer(buf: Buffer | Array): buf is Buffer { +function chunksIsBuffer(buf: Buffer | Stack): buf is Buffer { return Buffer.isBuffer(buf); } -function chunksIsArray( - buf: Buffer | Array, -): buf is Array { +function chunksIsArray(buf: Buffer | Stack): buf is Stack { return types.Array(buf); } @@ -50,13 +49,13 @@ function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer { return Buffer.isBuffer(buf); } -export function compile(chunks: Buffer | Array): Buffer { +export function compile(chunks: Buffer | Stack): Buffer { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; typeforce(types.Array, chunks); - const bufferSize = chunks.reduce(function(accum: number, chunk) { + const bufferSize = chunks.reduce((accum: number, chunk) => { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy @@ -74,7 +73,7 @@ export function compile(chunks: Buffer | Array): Buffer { const buffer = Buffer.allocUnsafe(bufferSize); let offset = 0; - chunks.forEach(function(chunk) { + chunks.forEach(chunk => { // data chunk if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy @@ -149,16 +148,16 @@ export function decompile( export function toASM(chunks: Buffer | Array): string { if (chunksIsBuffer(chunks)) { - chunks = >decompile(chunks); + chunks = decompile(chunks) as Stack; } return chunks - .map(function(chunk) { + .map(chunk => { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); if (op === undefined) return chunk.toString('hex'); - chunk = op; + chunk = op as number; } // opcode! @@ -171,7 +170,7 @@ export function fromASM(asm: string): Buffer { typeforce(types.String, asm); return compile( - asm.split(' ').map(function(chunkStr) { + asm.split(' ').map(chunkStr => { // opcode? if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; typeforce(types.Hex, chunkStr); @@ -182,13 +181,11 @@ export function fromASM(asm: string): Buffer { ); } -export function toStack( - chunks: Buffer | Array, -): Array { - chunks = >decompile(chunks); +export function toStack(chunks: Buffer | Array): Buffer[] { + chunks = decompile(chunks) as Stack; typeforce(isPushOnly, chunks); - return chunks.map(function(op) { + return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; if (op === OPS.OP_0) return Buffer.allocUnsafe(0); @@ -214,5 +211,6 @@ export function isCanonicalScriptSignature(buffer: Buffer): boolean { return bip66.check(buffer.slice(0, -1)); } +// tslint:disable-next-line variable-name export const number = scriptNumber; export const signature = scriptSignature; diff --git a/types/script.d.ts b/types/script.d.ts index 702e76b..52ad4dd 100644 --- a/types/script.d.ts +++ b/types/script.d.ts @@ -1,16 +1,17 @@ /// +import { Stack } from './payments'; import * as scriptNumber from './script_number'; import * as scriptSignature from './script_signature'; export declare type OpCode = number; export declare const OPS: { [index: string]: number; }; -export declare function isPushOnly(value: Array): boolean; -export declare function compile(chunks: Buffer | Array): Buffer; +export declare function isPushOnly(value: Stack): boolean; +export declare function compile(chunks: Buffer | Stack): Buffer; export declare function decompile(buffer: Buffer | Array): Array | null; export declare function toASM(chunks: Buffer | Array): string; export declare function fromASM(asm: string): Buffer; -export declare function toStack(chunks: Buffer | Array): Array; +export declare function toStack(chunks: Buffer | Array): Buffer[]; export declare function isCanonicalPubKey(buffer: Buffer): boolean; export declare function isDefinedHashType(hashType: number): boolean; export declare function isCanonicalScriptSignature(buffer: Buffer): boolean; From 94f334851937eed434acf3cf413257394f861f8d Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 13:21:18 +0900 Subject: [PATCH 141/183] Fix lint for script_number.ts script_signature.ts --- src/script_number.js | 10 +++++----- src/script_signature.js | 12 +++++------- ts_src/script_number.ts | 10 +++++----- ts_src/script_signature.ts | 12 +++++------- types/script_number.d.ts | 2 +- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/script_number.js b/src/script_number.js index a8c42d3..3a30a43 100644 --- a/src/script_number.js +++ b/src/script_number.js @@ -24,7 +24,7 @@ function decode(buffer, maxLength, minimal) { } // 32-bit / 24-bit / 16-bit / 8-bit let result = 0; - for (var i = 0; i < length; ++i) { + for (let i = 0; i < length; ++i) { result |= buffer[i] << (8 * i); } if (buffer[length - 1] & 0x80) @@ -45,12 +45,12 @@ function scriptNumSize(i) { ? 1 : 0; } -function encode(number) { - let value = Math.abs(number); +function encode(_number) { + let value = Math.abs(_number); const size = scriptNumSize(value); const buffer = Buffer.allocUnsafe(size); - const negative = number < 0; - for (var i = 0; i < size; ++i) { + const negative = _number < 0; + for (let i = 0; i < size; ++i) { buffer.writeUInt8(value & 0xff, i); value >>= 8; } diff --git a/src/script_signature.js b/src/script_signature.js index c185981..a1f2f22 100644 --- a/src/script_signature.js +++ b/src/script_signature.js @@ -29,13 +29,11 @@ function decode(buffer) { const hashTypeMod = hashType & ~0x80; if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType); - const decode = bip66.decode(buffer.slice(0, -1)); - const r = fromDER(decode.r); - const s = fromDER(decode.s); - return { - signature: Buffer.concat([r, s], 64), - hashType: hashType, - }; + const decoded = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decoded.r); + const s = fromDER(decoded.s); + const signature = Buffer.concat([r, s], 64); + return { signature, hashType }; } exports.decode = decode; function encode(signature, hashType) { diff --git a/ts_src/script_number.ts b/ts_src/script_number.ts index cd48373..a4c502f 100644 --- a/ts_src/script_number.ts +++ b/ts_src/script_number.ts @@ -27,7 +27,7 @@ export function decode( // 32-bit / 24-bit / 16-bit / 8-bit let result = 0; - for (var i = 0; i < length; ++i) { + for (let i = 0; i < length; ++i) { result |= buffer[i] << (8 * i); } @@ -50,13 +50,13 @@ function scriptNumSize(i: number): number { : 0; } -export function encode(number: number): Buffer { - let value = Math.abs(number); +export function encode(_number: number): Buffer { + let value = Math.abs(_number); const size = scriptNumSize(value); const buffer = Buffer.allocUnsafe(size); - const negative = number < 0; + const negative = _number < 0; - for (var i = 0; i < size; ++i) { + for (let i = 0; i < size; ++i) { buffer.writeUInt8(value & 0xff, i); value >>= 8; } diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts index 1f11d00..af9930e 100644 --- a/ts_src/script_signature.ts +++ b/ts_src/script_signature.ts @@ -33,14 +33,12 @@ export function decode(buffer: Buffer): ScriptSignature { if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType); - const decode = bip66.decode(buffer.slice(0, -1)); - const r = fromDER(decode.r); - const s = fromDER(decode.s); + const decoded = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decoded.r); + const s = fromDER(decoded.s); + const signature = Buffer.concat([r, s], 64); - return { - signature: Buffer.concat([r, s], 64), - hashType: hashType, - }; + return { signature, hashType }; } export function encode(signature: Buffer, hashType: number): Buffer { diff --git a/types/script_number.d.ts b/types/script_number.d.ts index d0b87b1..015bb89 100644 --- a/types/script_number.d.ts +++ b/types/script_number.d.ts @@ -1,3 +1,3 @@ /// export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number; -export declare function encode(number: number): Buffer; +export declare function encode(_number: number): Buffer; From e6ea0389a2c22c096da0707455735ed7eb8ce36a Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 13:40:23 +0900 Subject: [PATCH 142/183] Fix lint for transaction.ts --- src/transaction.js | 90 +++++++++++----------- ts_src/transaction.ts | 168 +++++++++++++++++++++-------------------- types/transaction.d.ts | 34 +++++---- 3 files changed, 148 insertions(+), 144 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index cfd31fe..c6c847a 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,11 +1,11 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypto = require("./crypto"); -const bscript = require("./script"); -const types = require("./types"); const bufferutils = require("./bufferutils"); const bufferutils_1 = require("./bufferutils"); +const bcrypto = require("./crypto"); +const bscript = require("./script"); const script_1 = require("./script"); +const types = require("./types"); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); function varSliceSize(someScript) { @@ -38,7 +38,7 @@ class Transaction { this.ins = []; this.outs = []; } - static fromBuffer(buffer, __noStrict) { + static fromBuffer(buffer, _NO_STRICT) { let offset = 0; function readSlice(n) { offset += n; @@ -70,7 +70,7 @@ class Transaction { function readVector() { const count = readVarInt(); const vector = []; - for (var i = 0; i < count; i++) + for (let i = 0; i < count; i++) vector.push(readVarSlice()); return vector; } @@ -85,7 +85,7 @@ class Transaction { hasWitnesses = true; } const vinLen = readVarInt(); - for (var i = 0; i < vinLen; ++i) { + for (let i = 0; i < vinLen; ++i) { tx.ins.push({ hash: readSlice(32), index: readUInt32(), @@ -95,14 +95,14 @@ class Transaction { }); } const voutLen = readVarInt(); - for (i = 0; i < voutLen; ++i) { + for (let i = 0; i < voutLen; ++i) { tx.outs.push({ value: readUInt64(), script: readVarSlice(), }); } if (hasWitnesses) { - for (i = 0; i < vinLen; ++i) { + for (let i = 0; i < vinLen; ++i) { tx.ins[i].witness = readVector(); } // was this pointless? @@ -110,7 +110,7 @@ class Transaction { throw new Error('Transaction has superfluous witness data'); } tx.locktime = readUInt32(); - if (__noStrict) + if (_NO_STRICT) return tx; if (offset !== buffer.length) throw new Error('Transaction has unexpected data'); @@ -121,7 +121,7 @@ class Transaction { } static isCoinbaseHash(buffer) { typeforce(types.Hash256bit, buffer); - for (var i = 0; i < 32; ++i) { + for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; } @@ -137,8 +137,8 @@ class Transaction { } // Add the input and return the input's index return (this.ins.push({ - hash: hash, - index: index, + hash, + index, script: scriptSig || EMPTY_SCRIPT, sequence: sequence, witness: EMPTY_WITNESS, @@ -149,7 +149,7 @@ class Transaction { // Add the output and return the output's index return (this.outs.push({ script: scriptPubKey, - value: value, + value, }) - 1); } hasWitnesses() { @@ -168,23 +168,6 @@ class Transaction { byteLength() { return this.__byteLength(true); } - __byteLength(__allowWitness) { - const hasWitnesses = __allowWitness && this.hasWitnesses(); - return ((hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script); - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0) + - (hasWitnesses - ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) - : 0)); - } clone() { const newTx = new Transaction(); newTx.version = this.version; @@ -242,7 +225,7 @@ class Transaction { // truncate outputs after txTmp.outs.length = inIndex + 1; // "blank" outputs before - for (var i = 0; i < inIndex; i++) { + for (let i = 0; i < inIndex; i++) { txTmp.outs[i] = BLANK_OUTPUT; } // ignore sequence numbers (except at inIndex) @@ -365,9 +348,37 @@ class Transaction { toBuffer(buffer, initialOffset) { return this.__toBuffer(buffer, initialOffset, true); } - __toBuffer(buffer, initialOffset, __allowWitness) { + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } + __byteLength(_ALLOW_WITNESS) { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + return ((hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0)); + } + __toBuffer(buffer, initialOffset, _ALLOW_WITNESS) { if (!buffer) - buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness)); + buffer = Buffer.allocUnsafe(this.__byteLength(_ALLOW_WITNESS)); let offset = initialOffset || 0; function writeSlice(slice) { offset += slice.copy(buffer, offset); @@ -397,7 +408,7 @@ class Transaction { vector.forEach(writeVarSlice); } writeInt32(this.version); - const hasWitnesses = __allowWitness && this.hasWitnesses(); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); if (hasWitnesses) { writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); @@ -430,17 +441,6 @@ class Transaction { return buffer.slice(initialOffset, offset); return buffer; } - toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); - } - setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); - this.ins[index].script = scriptSig; - } - setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - this.ins[index].witness = witness; - } } Transaction.DEFAULT_SEQUENCE = 0xffffffff; Transaction.SIGHASH_ALL = 0x01; diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index a456a32..995f1d7 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -1,9 +1,9 @@ -import * as bcrypto from './crypto'; -import * as bscript from './script'; -import * as types from './types'; import * as bufferutils from './bufferutils'; import { reverseBuffer } from './bufferutils'; +import * as bcrypto from './crypto'; +import * as bscript from './script'; import { OPS as opcodes } from './script'; +import * as types from './types'; const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); @@ -14,7 +14,7 @@ function varSliceSize(someScript: Buffer): number { return varuint.encodingLength(length) + length; } -function vectorSize(someVector: Array): number { +function vectorSize(someVector: Buffer[]): number { const length = someVector.length; return ( @@ -26,7 +26,7 @@ function vectorSize(someVector: Array): number { } const EMPTY_SCRIPT: Buffer = Buffer.allocUnsafe(0); -const EMPTY_WITNESS: Array = []; +const EMPTY_WITNESS: Buffer[] = []; const ZERO: Buffer = Buffer.from( '0000000000000000000000000000000000000000000000000000000000000000', 'hex', @@ -42,33 +42,30 @@ const BLANK_OUTPUT: BlankOutput = { }; function isOutput(out: Output | BlankOutput): out is Output { - return (out).value !== undefined; + return (out as Output).value !== undefined; } -export type BlankOutput = { +export interface BlankOutput { script: Buffer; valueBuffer: Buffer; -}; +} -export type Output = { +export interface Output { script: Buffer; value: number; -}; +} -export type Input = { +type OpenOutput = Output | BlankOutput; + +export interface Input { hash: Buffer; index: number; script: Buffer; sequence: number; - witness: Array; -}; + witness: Buffer[]; +} export class Transaction { - version: number; - locktime: number; - ins: Array; - outs: Array; - static readonly DEFAULT_SEQUENCE = 0xffffffff; static readonly SIGHASH_ALL = 0x01; static readonly SIGHASH_NONE = 0x02; @@ -77,14 +74,7 @@ export class Transaction { static readonly ADVANCED_TRANSACTION_MARKER = 0x00; static readonly ADVANCED_TRANSACTION_FLAG = 0x01; - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; - } - - static fromBuffer(buffer: Buffer, __noStrict?: boolean): Transaction { + static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction { let offset: number = 0; function readSlice(n: number): Buffer { @@ -120,10 +110,10 @@ export class Transaction { return readSlice(readVarInt()); } - function readVector(): Array { + function readVector(): Buffer[] { const count = readVarInt(); - const vector: Array = []; - for (var i = 0; i < count; i++) vector.push(readVarSlice()); + const vector: Buffer[] = []; + for (let i = 0; i < count; i++) vector.push(readVarSlice()); return vector; } @@ -143,7 +133,7 @@ export class Transaction { } const vinLen = readVarInt(); - for (var i = 0; i < vinLen; ++i) { + for (let i = 0; i < vinLen; ++i) { tx.ins.push({ hash: readSlice(32), index: readUInt32(), @@ -154,7 +144,7 @@ export class Transaction { } const voutLen = readVarInt(); - for (i = 0; i < voutLen; ++i) { + for (let i = 0; i < voutLen; ++i) { tx.outs.push({ value: readUInt64(), script: readVarSlice(), @@ -162,7 +152,7 @@ export class Transaction { } if (hasWitnesses) { - for (i = 0; i < vinLen; ++i) { + for (let i = 0; i < vinLen; ++i) { tx.ins[i].witness = readVector(); } @@ -173,7 +163,7 @@ export class Transaction { tx.locktime = readUInt32(); - if (__noStrict) return tx; + if (_NO_STRICT) return tx; if (offset !== buffer.length) throw new Error('Transaction has unexpected data'); @@ -186,12 +176,24 @@ export class Transaction { static isCoinbaseHash(buffer: Buffer): boolean { typeforce(types.Hash256bit, buffer); - for (var i = 0; i < 32; ++i) { + for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; } return true; } + version: number; + locktime: number; + ins: Input[]; + outs: OpenOutput[]; + + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; + } + isCoinbase(): boolean { return ( this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) @@ -221,10 +223,10 @@ export class Transaction { // Add the input and return the input's index return ( this.ins.push({ - hash: hash, - index: index, + hash, + index, script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, + sequence: sequence as number, witness: EMPTY_WITNESS, }) - 1 ); @@ -237,7 +239,7 @@ export class Transaction { return ( this.outs.push({ script: scriptPubKey, - value: value, + value, }) - 1 ); } @@ -262,27 +264,6 @@ export class Transaction { return this.__byteLength(true); } - private __byteLength(__allowWitness: boolean): number { - const hasWitnesses = __allowWitness && this.hasWitnesses(); - - return ( - (hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script); - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0) + - (hasWitnesses - ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) - : 0) - ); - } - clone(): Transaction { const newTx = new Transaction(); newTx.version = this.version; @@ -301,7 +282,7 @@ export class Transaction { newTx.outs = this.outs.map(txOut => { return { script: txOut.script, - value: (txOut).value, + value: (txOut as Output).value, }; }); @@ -358,7 +339,7 @@ export class Transaction { txTmp.outs.length = inIndex + 1; // "blank" outputs before - for (var i = 0; i < inIndex; i++) { + for (let i = 0; i < inIndex; i++) { txTmp.outs[i] = BLANK_OUTPUT; } @@ -471,7 +452,7 @@ export class Transaction { toffset = 0; this.outs.forEach(out => { - writeUInt64((out).value); + writeUInt64((out as Output).value); writeVarSlice(out.script); }); @@ -484,7 +465,7 @@ export class Transaction { tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); toffset = 0; - writeUInt64((output).value); + writeUInt64((output as Output).value); writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); @@ -523,13 +504,50 @@ export class Transaction { return this.__toBuffer(buffer, initialOffset, true); } + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + + setInputScript(index: number, scriptSig: Buffer) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + + this.ins[index].script = scriptSig; + } + + setWitness(index: number, witness: Buffer[]) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + + this.ins[index].witness = witness; + } + + private __byteLength(_ALLOW_WITNESS: boolean): number { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0) + ); + } + private __toBuffer( buffer?: Buffer, initialOffset?: number, - __allowWitness?: boolean, + _ALLOW_WITNESS?: boolean, ): Buffer { if (!buffer) - buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness!)); + buffer = Buffer.allocUnsafe(this.__byteLength(_ALLOW_WITNESS!)) as Buffer; let offset = initialOffset || 0; @@ -563,14 +581,14 @@ export class Transaction { writeSlice(slice); } - function writeVector(vector: Array) { + function writeVector(vector: Buffer[]) { writeVarInt(vector.length); vector.forEach(writeVarSlice); } writeInt32(this.version); - const hasWitnesses = __allowWitness && this.hasWitnesses(); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); if (hasWitnesses) { writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); @@ -609,20 +627,4 @@ export class Transaction { if (initialOffset !== undefined) return buffer.slice(initialOffset, offset); return buffer; } - - toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); - } - - setInputScript(index: number, scriptSig: Buffer) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); - - this.ins[index].script = scriptSig; - } - - setWitness(index: number, witness: Array) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - - this.ins[index].witness = witness; - } } diff --git a/types/transaction.d.ts b/types/transaction.d.ts index 60bbf45..4f8a2b9 100644 --- a/types/transaction.d.ts +++ b/types/transaction.d.ts @@ -1,24 +1,21 @@ /// -export declare type BlankOutput = { +export interface BlankOutput { script: Buffer; valueBuffer: Buffer; -}; -export declare type Output = { +} +export interface Output { script: Buffer; value: number; -}; -export declare type Input = { +} +declare type OpenOutput = Output | BlankOutput; +export interface Input { hash: Buffer; index: number; script: Buffer; sequence: number; - witness: Array; -}; + witness: Buffer[]; +} export declare class Transaction { - version: number; - locktime: number; - ins: Array; - outs: Array; static readonly DEFAULT_SEQUENCE = 4294967295; static readonly SIGHASH_ALL = 1; static readonly SIGHASH_NONE = 2; @@ -26,10 +23,14 @@ export declare class Transaction { static readonly SIGHASH_ANYONECANPAY = 128; static readonly ADVANCED_TRANSACTION_MARKER = 0; static readonly ADVANCED_TRANSACTION_FLAG = 1; - constructor(); - static fromBuffer(buffer: Buffer, __noStrict?: boolean): Transaction; + static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction; static fromHex(hex: string): Transaction; static isCoinbaseHash(buffer: Buffer): boolean; + version: number; + locktime: number; + ins: Input[]; + outs: OpenOutput[]; + constructor(); isCoinbase(): boolean; addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; addOutput(scriptPubKey: Buffer, value: number): number; @@ -37,7 +38,6 @@ export declare class Transaction { weight(): number; virtualSize(): number; byteLength(): number; - private __byteLength; clone(): Transaction; /** * Hash transaction for signing a specific input. @@ -52,8 +52,10 @@ export declare class Transaction { getHash(forWitness?: boolean): Buffer; getId(): string; toBuffer(buffer?: Buffer, initialOffset?: number): Buffer; - private __toBuffer; toHex(): string; setInputScript(index: number, scriptSig: Buffer): void; - setWitness(index: number, witness: Array): void; + setWitness(index: number, witness: Buffer[]): void; + private __byteLength; + private __toBuffer; } +export {}; From 512b03e28406a281b37fbe357c303ecfc16915c3 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 14:03:04 +0900 Subject: [PATCH 143/183] Fix lint transaction_builder.ts --- src/transaction_builder.js | 227 ++++++++--------- test/fixtures/transaction_builder.json | 2 +- test/transaction_builder.js | 26 +- ts_src/transaction_builder.ts | 335 +++++++++++++------------ types/transaction_builder.d.ts | 14 +- 5 files changed, 305 insertions(+), 299 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 540a17a..0b876a7 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -1,16 +1,16 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const networks = require("./networks"); -const bufferutils_1 = require("./bufferutils"); -const transaction_1 = require("./transaction"); -const ECPair = require("./ecpair"); -const types = require("./types"); const baddress = require("./address"); +const bufferutils_1 = require("./bufferutils"); +const classify = require("./classify"); const bcrypto = require("./crypto"); -const bscript = require("./script"); +const ECPair = require("./ecpair"); +const networks = require("./networks"); const payments = require("./payments"); -const classify = require("./classify"); +const bscript = require("./script"); const script_1 = require("./script"); +const transaction_1 = require("./transaction"); +const types = require("./types"); const typeforce = require('typeforce'); const SCRIPT_TYPES = classify.types; function txIsString(tx) { @@ -20,15 +20,6 @@ function txIsTransaction(tx) { return tx instanceof transaction_1.Transaction; } class TransactionBuilder { - constructor(network, maximumFeeRate) { - this.__prevTxSet = {}; - this.network = network || networks.bitcoin; - // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500; - this.__inputs = []; - this.__tx = new transaction_1.Transaction(); - this.__tx.version = 2; - } static fromTransaction(transaction, network) { const txb = new TransactionBuilder(network); // Copy transaction fields @@ -47,33 +38,42 @@ class TransactionBuilder { }); }); // fix some things not possible through the public API - txb.__inputs.forEach((input, i) => { + txb.__INPUTS.forEach((input, i) => { fixMultisigOrder(input, transaction, i); }); return txb; } + constructor(network, maximumFeeRate) { + this.__PREV_TX_SET = {}; + this.network = network || networks.bitcoin; + // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) + this.maximumFeeRate = maximumFeeRate || 2500; + this.__INPUTS = []; + this.__TX = new transaction_1.Transaction(); + this.__TX.version = 2; + } setLockTime(locktime) { typeforce(types.UInt32, locktime); // if any signatures exist, throw - if (this.__inputs.some(input => { + if (this.__INPUTS.some(input => { if (!input.signatures) return false; return input.signatures.some(s => s !== undefined); })) { throw new Error('No, this would invalidate signatures'); } - this.__tx.locktime = locktime; + this.__TX.locktime = locktime; } setVersion(version) { typeforce(types.UInt32, version); // XXX: this might eventually become more complex depending on what the versions represent - this.__tx.version = version; + this.__TX.version = version; } addInput(txHash, vout, sequence, prevOutScript) { if (!this.__canModifyInputs()) { throw new Error('No, this would invalidate signatures'); } - let value = undefined; + let value; // is it a hex string? if (txIsString(txHash)) { // transaction hashs's are displayed in reverse order, un-reverse it @@ -87,46 +87,11 @@ class TransactionBuilder { txHash = txHash.getHash(false); } return this.__addInputUnsafe(txHash, vout, { - sequence: sequence, - prevOutScript: prevOutScript, - value: value, + sequence, + prevOutScript, + value, }); } - __addInputUnsafe(txHash, vout, options) { - if (transaction_1.Transaction.isCoinbaseHash(txHash)) { - throw new Error('coinbase inputs not supported'); - } - const prevTxOut = txHash.toString('hex') + ':' + vout; - if (this.__prevTxSet[prevTxOut] !== undefined) - throw new Error('Duplicate TxOut: ' + prevTxOut); - let input = {}; - // derive what we can from the scriptSig - if (options.script !== undefined) { - input = expandInput(options.script, options.witness || []); - } - // if an input value was given, retain it - if (options.value !== undefined) { - input.value = options.value; - } - // derive what we can from the previous transactions output script - if (!input.prevOutScript && options.prevOutScript) { - let prevOutType; - if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript); - if (expanded.pubkeys) { - input.pubkeys = expanded.pubkeys; - input.signatures = expanded.signatures; - } - prevOutType = expanded.type; - } - input.prevOutScript = options.prevOutScript; - input.prevOutType = prevOutType || classify.output(options.prevOutScript); - } - const vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig); - this.__inputs[vin] = input; - this.__prevTxSet[prevTxOut] = true; - return vin; - } addOutput(scriptPubKey, value) { if (!this.__canModifyOutputs()) { throw new Error('No, this would invalidate signatures'); @@ -135,7 +100,7 @@ class TransactionBuilder { if (typeof scriptPubKey === 'string') { scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); } - return this.__tx.addOutput(scriptPubKey, value); + return this.__TX.addOutput(scriptPubKey, value); } build() { return this.__build(false); @@ -143,47 +108,16 @@ class TransactionBuilder { buildIncomplete() { return this.__build(true); } - __build(allowIncomplete) { - if (!allowIncomplete) { - if (!this.__tx.ins.length) - throw new Error('Transaction has no inputs'); - if (!this.__tx.outs.length) - throw new Error('Transaction has no outputs'); - } - const tx = this.__tx.clone(); - // create script signatures from inputs - this.__inputs.forEach((input, i) => { - if (!input.prevOutType && !allowIncomplete) - throw new Error('Transaction is not complete'); - const result = build(input.prevOutType, input, allowIncomplete); - if (!result) { - if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) - throw new Error('Unknown input type'); - if (!allowIncomplete) - throw new Error('Not enough information'); - return; - } - tx.setInputScript(i, result.input); - tx.setWitness(i, result.witness); - }); - if (!allowIncomplete) { - // do not rely on this, its merely a last resort - if (this.__overMaximumFees(tx.virtualSize())) { - throw new Error('Transaction has absurd fees'); - } - } - return tx; - } sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network'); - if (!this.__inputs[vin]) + if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin); hashType = hashType || transaction_1.Transaction.SIGHASH_ALL; if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs'); - const input = this.__inputs[vin]; + const input = this.__INPUTS[vin]; // if redeemScript was previously provided, enforce consistency if (input.redeemScript !== undefined && redeemScript && @@ -194,7 +128,7 @@ class TransactionBuilder { if (!canSign(input)) { if (witnessValue !== undefined) { if (input.value !== undefined && input.value !== witnessValue) - throw new Error("Input didn't match witnessValue"); + throw new Error('Input did not match witnessValue'); typeforce(types.Satoshi, witnessValue); input.value = witnessValue; } @@ -209,10 +143,10 @@ class TransactionBuilder { // ready to sign let signatureHash; if (input.hasWitness) { - signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType); + signatureHash = this.__TX.hashForWitnessV0(vin, input.signScript, input.value, hashType); } else { - signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType); + signatureHash = this.__TX.hashForSignature(vin, input.signScript, hashType); } // enforce in order signing of public keys const signed = input.pubkeys.some((pubKey, i) => { @@ -231,8 +165,74 @@ class TransactionBuilder { if (!signed) throw new Error('Key pair cannot sign for this input'); } + __addInputUnsafe(txHash, vout, options) { + if (transaction_1.Transaction.isCoinbaseHash(txHash)) { + throw new Error('coinbase inputs not supported'); + } + const prevTxOut = txHash.toString('hex') + ':' + vout; + if (this.__PREV_TX_SET[prevTxOut] !== undefined) + throw new Error('Duplicate TxOut: ' + prevTxOut); + let input = {}; + // derive what we can from the scriptSig + if (options.script !== undefined) { + input = expandInput(options.script, options.witness || []); + } + // if an input value was given, retain it + if (options.value !== undefined) { + input.value = options.value; + } + // derive what we can from the previous transactions output script + if (!input.prevOutScript && options.prevOutScript) { + let prevOutType; + if (!input.pubkeys && !input.signatures) { + const expanded = expandOutput(options.prevOutScript); + if (expanded.pubkeys) { + input.pubkeys = expanded.pubkeys; + input.signatures = expanded.signatures; + } + prevOutType = expanded.type; + } + input.prevOutScript = options.prevOutScript; + input.prevOutType = prevOutType || classify.output(options.prevOutScript); + } + const vin = this.__TX.addInput(txHash, vout, options.sequence, options.scriptSig); + this.__INPUTS[vin] = input; + this.__PREV_TX_SET[prevTxOut] = true; + return vin; + } + __build(allowIncomplete) { + if (!allowIncomplete) { + if (!this.__TX.ins.length) + throw new Error('Transaction has no inputs'); + if (!this.__TX.outs.length) + throw new Error('Transaction has no outputs'); + } + const tx = this.__TX.clone(); + // create script signatures from inputs + this.__INPUTS.forEach((input, i) => { + if (!input.prevOutType && !allowIncomplete) + throw new Error('Transaction is not complete'); + const result = build(input.prevOutType, input, allowIncomplete); + if (!result) { + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) + throw new Error('Unknown input type'); + if (!allowIncomplete) + throw new Error('Not enough information'); + return; + } + tx.setInputScript(i, result.input); + tx.setWitness(i, result.witness); + }); + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__overMaximumFees(tx.virtualSize())) { + throw new Error('Transaction has absurd fees'); + } + } + return tx; + } __canModifyInputs() { - return this.__inputs.every(input => { + return this.__INPUTS.every(input => { if (!input.signatures) return true; return input.signatures.every(signature => { @@ -247,12 +247,12 @@ class TransactionBuilder { } __needsOutputs(signingHashType) { if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) { - return this.__tx.outs.length === 0; + return this.__TX.outs.length === 0; } // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // .build() will fail, but .buildIncomplete() is OK - return (this.__tx.outs.length === 0 && - this.__inputs.some(input => { + return (this.__TX.outs.length === 0 && + this.__INPUTS.some(input => { if (!input.signatures) return false; return input.signatures.some(signature => { @@ -266,9 +266,9 @@ class TransactionBuilder { })); } __canModifyOutputs() { - const nInputs = this.__tx.ins.length; - const nOutputs = this.__tx.outs.length; - return this.__inputs.every(input => { + const nInputs = this.__TX.ins.length; + const nOutputs = this.__TX.outs.length; + return this.__INPUTS.every(input => { if (input.signatures === undefined) return true; return input.signatures.every(signature => { @@ -290,10 +290,10 @@ class TransactionBuilder { } __overMaximumFees(bytes) { // not all inputs will have .value defined - const incoming = this.__inputs.reduce((a, x) => a + (x.value >>> 0), 0); + const incoming = this.__INPUTS.reduce((a, x) => a + (x.value >>> 0), 0); // but all outputs do, and if we have any input value // we can immediately determine if the outputs are too small - const outgoing = this.__tx.outs.reduce((a, x) => a + x.value, 0); + const outgoing = this.__TX.outs.reduce((a, x) => a + x.value, 0); const fee = incoming - outgoing; const feeRate = fee / bytes; return feeRate > this.maximumFeeRate; @@ -350,8 +350,8 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) { }, { allowIncomplete: true }); return { prevOutType: SCRIPT_TYPES.P2MS, - pubkeys: pubkeys, - signatures: signatures, + pubkeys, + signatures, maxSignatures: m, }; } @@ -488,7 +488,9 @@ function expandOutput(script, ourPubKey) { } function prepareInput(input, ourPubKey, redeemScript, witnessScript) { if (redeemScript && witnessScript) { - const p2wsh = (payments.p2wsh({ redeem: { output: witnessScript } })); + const p2wsh = payments.p2wsh({ + redeem: { output: witnessScript }, + }); const p2wshAlt = payments.p2wsh({ output: redeemScript }); const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); const p2shAlt = payments.p2sh({ redeem: p2wsh }); @@ -506,7 +508,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } - let signScript = witnessScript; + const signScript = witnessScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); return { @@ -579,7 +581,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { if (input.signatures && input.signatures.some(x => x !== undefined)) { expanded.signatures = input.signatures; } - let signScript = witnessScript; + const signScript = witnessScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2WSH(P2WPKH) is a consensus failure'); return { @@ -614,7 +616,8 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { } let signScript = input.prevOutScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = (payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output); + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }) + .output; } return { prevOutType: expanded.type, @@ -630,7 +633,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) { const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; return { prevOutType: SCRIPT_TYPES.P2PKH, - prevOutScript: prevOutScript, + prevOutScript, hasWitness: false, signScript: prevOutScript, signType: SCRIPT_TYPES.P2PKH, diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json index a2ca5d7..24be3ba 100644 --- a/test/fixtures/transaction_builder.json +++ b/test/fixtures/transaction_builder.json @@ -1976,7 +1976,7 @@ "sign": [ { "description": "Transaction w/ witness value mismatch", - "exception": "Input didn\\'t match witnessValue", + "exception": "Input did not match witnessValue", "network": "testnet", "inputs": [ { diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 574b669..3f84b19 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -164,7 +164,7 @@ describe('TransactionBuilder', function () { const tx = Transaction.fromHex(fixtures.valid.classification.hex) const txb = TransactionBuilder.fromTransaction(tx) - txb.__inputs.forEach(function (i) { + txb.__INPUTS.forEach(function (i) { assert.strictEqual(i.prevOutType, 'scripthash') assert.strictEqual(i.redeemScriptType, 'multisig') }) @@ -191,22 +191,22 @@ describe('TransactionBuilder', function () { const vin = txb.addInput(txHash, 1, 54) assert.strictEqual(vin, 0) - const txIn = txb.__tx.ins[0] + const txIn = txb.__TX.ins[0] assert.strictEqual(txIn.hash, txHash) assert.strictEqual(txIn.index, 1) assert.strictEqual(txIn.sequence, 54) - assert.strictEqual(txb.__inputs[0].prevOutScript, undefined) + assert.strictEqual(txb.__INPUTS[0].prevOutScript, undefined) }) it('accepts a txHash, index [, sequence number and scriptPubKey]', function () { const vin = txb.addInput(txHash, 1, 54, scripts[1]) assert.strictEqual(vin, 0) - const txIn = txb.__tx.ins[0] + const txIn = txb.__TX.ins[0] assert.strictEqual(txIn.hash, txHash) assert.strictEqual(txIn.index, 1) assert.strictEqual(txIn.sequence, 54) - assert.strictEqual(txb.__inputs[0].prevOutScript, scripts[1]) + assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1]) }) it('accepts a prevTx, index [and sequence number]', function () { @@ -217,11 +217,11 @@ describe('TransactionBuilder', function () { const vin = txb.addInput(prevTx, 1, 54) assert.strictEqual(vin, 0) - const txIn = txb.__tx.ins[0] + const txIn = txb.__TX.ins[0] assert.deepEqual(txIn.hash, prevTx.getHash()) assert.strictEqual(txIn.index, 1) assert.strictEqual(txIn.sequence, 54) - assert.strictEqual(txb.__inputs[0].prevOutScript, scripts[1]) + assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1]) }) it('returns the input index', function () { @@ -251,7 +251,7 @@ describe('TransactionBuilder', function () { const vout = txb.addOutput(address, 1000) assert.strictEqual(vout, 0) - const txout = txb.__tx.outs[0] + const txout = txb.__TX.outs[0] assert.deepEqual(txout.script, scripts[0]) assert.strictEqual(txout.value, 1000) }) @@ -260,7 +260,7 @@ describe('TransactionBuilder', function () { const vout = txb.addOutput(scripts[0], 1000) assert.strictEqual(vout, 0) - const txout = txb.__tx.outs[0] + const txout = txb.__TX.outs[0] assert.deepEqual(txout.script, scripts[0]) assert.strictEqual(txout.value, 1000) }) @@ -533,10 +533,10 @@ describe('TransactionBuilder', function () { '194a565cd6aa4cc38b8eaffa343402201c5b4b61d73fa38e49c1ee68cc0e6dfd2f5dae453dd86eb142e87a' + '0bafb1bc8401210283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f44800000000' const txb = TransactionBuilder.fromTransaction(Transaction.fromHex(rawtx)) - txb.__inputs[0].value = 241530 - txb.__inputs[1].value = 241530 - txb.__inputs[2].value = 248920 - txb.__inputs[3].value = 248920 + txb.__INPUTS[0].value = 241530 + txb.__INPUTS[1].value = 241530 + txb.__INPUTS[2].value = 248920 + txb.__INPUTS[3].value = 248920 assert.throws(function () { txb.build() diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index a3bd9e6..4c939e1 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -1,24 +1,25 @@ -import { Network } from './networks'; -import * as networks from './networks'; +import * as baddress from './address'; import { reverseBuffer } from './bufferutils'; -import { Transaction, Output } from './transaction'; +import * as classify from './classify'; +import * as bcrypto from './crypto'; import { ECPairInterface } from './ecpair'; import * as ECPair from './ecpair'; -import * as types from './types'; -import * as baddress from './address'; -import * as bcrypto from './crypto'; -import * as bscript from './script'; +import { Network } from './networks'; +import * as networks from './networks'; import { Payment } from './payments'; import * as payments from './payments'; -import * as classify from './classify'; +import * as bscript from './script'; import { OPS as ops } from './script'; +import { Output, Transaction } from './transaction'; +import * as types from './types'; const typeforce = require('typeforce'); const SCRIPT_TYPES = classify.types; -type TxbSignatures = Array | Array; -type TxbPubkeys = Array; -type TxbWitness = Array; +type MaybeBuffer = Buffer | undefined; +type TxbSignatures = Buffer[] | MaybeBuffer[]; +type TxbPubkeys = MaybeBuffer[]; +type TxbWitness = Buffer[]; type TxbScriptType = string; type TxbScript = Buffer; @@ -58,24 +59,6 @@ function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { } export class TransactionBuilder { - network: Network; - maximumFeeRate: number; - private __prevTxSet: { [index: string]: boolean }; - private __inputs: Array; - private __tx: Transaction; - - constructor(network?: Network, maximumFeeRate?: number) { - this.__prevTxSet = {}; - this.network = network || networks.bitcoin; - - // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500; - - this.__inputs = []; - this.__tx = new Transaction(); - this.__tx.version = 2; - } - static fromTransaction( transaction: Transaction, network?: Network, @@ -88,7 +71,7 @@ export class TransactionBuilder { // Copy outputs (done first to avoid signature invalidation) transaction.outs.forEach(txOut => { - txb.addOutput(txOut.script, (txOut).value); + txb.addOutput(txOut.script, (txOut as Output).value); }); // Copy inputs @@ -101,19 +84,37 @@ export class TransactionBuilder { }); // fix some things not possible through the public API - txb.__inputs.forEach((input, i) => { + txb.__INPUTS.forEach((input, i) => { fixMultisigOrder(input, transaction, i); }); return txb; } + network: Network; + maximumFeeRate: number; + private __PREV_TX_SET: { [index: string]: boolean }; + private __INPUTS: TxbInput[]; + private __TX: Transaction; + + constructor(network?: Network, maximumFeeRate?: number) { + this.__PREV_TX_SET = {}; + this.network = network || networks.bitcoin; + + // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) + this.maximumFeeRate = maximumFeeRate || 2500; + + this.__INPUTS = []; + this.__TX = new Transaction(); + this.__TX.version = 2; + } + setLockTime(locktime: number): void { typeforce(types.UInt32, locktime); // if any signatures exist, throw if ( - this.__inputs.some(input => { + this.__INPUTS.some(input => { if (!input.signatures) return false; return input.signatures.some(s => s !== undefined); @@ -122,14 +123,14 @@ export class TransactionBuilder { throw new Error('No, this would invalidate signatures'); } - this.__tx.locktime = locktime; + this.__TX.locktime = locktime; } setVersion(version: number): void { typeforce(types.UInt32, version); // XXX: this might eventually become more complex depending on what the versions represent - this.__tx.version = version; + this.__TX.version = version; } addInput( @@ -142,7 +143,7 @@ export class TransactionBuilder { throw new Error('No, this would invalidate signatures'); } - let value: number | undefined = undefined; + let value: number | undefined; // is it a hex string? if (txIsString(txHash)) { @@ -153,72 +154,18 @@ export class TransactionBuilder { } else if (txIsTransaction(txHash)) { const txOut = txHash.outs[vout]; prevOutScript = txOut.script; - value = (txOut).value; + value = (txOut as Output).value; - txHash = txHash.getHash(false); + txHash = txHash.getHash(false) as Buffer; } return this.__addInputUnsafe(txHash, vout, { - sequence: sequence, - prevOutScript: prevOutScript, - value: value, + sequence, + prevOutScript, + value, }); } - private __addInputUnsafe( - txHash: Buffer, - vout: number, - options: TxbInput, - ): number { - if (Transaction.isCoinbaseHash(txHash)) { - throw new Error('coinbase inputs not supported'); - } - - const prevTxOut = txHash.toString('hex') + ':' + vout; - if (this.__prevTxSet[prevTxOut] !== undefined) - throw new Error('Duplicate TxOut: ' + prevTxOut); - - let input = {}; - - // derive what we can from the scriptSig - if (options.script !== undefined) { - input = expandInput(options.script, options.witness || []); - } - - // if an input value was given, retain it - if (options.value !== undefined) { - input.value = options.value; - } - - // derive what we can from the previous transactions output script - if (!input.prevOutScript && options.prevOutScript) { - let prevOutType; - - if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript); - if (expanded.pubkeys) { - input.pubkeys = expanded.pubkeys; - input.signatures = expanded.signatures; - } - - prevOutType = expanded.type; - } - - input.prevOutScript = options.prevOutScript; - input.prevOutType = prevOutType || classify.output(options.prevOutScript); - } - - const vin = this.__tx.addInput( - txHash, - vout, - options.sequence, - options.scriptSig, - ); - this.__inputs[vin] = input; - this.__prevTxSet[prevTxOut] = true; - return vin; - } - addOutput(scriptPubKey: string | Buffer, value: number): number { if (!this.__canModifyOutputs()) { throw new Error('No, this would invalidate signatures'); @@ -229,7 +176,7 @@ export class TransactionBuilder { scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); } - return this.__tx.addOutput(scriptPubKey, value); + return this.__TX.addOutput(scriptPubKey, value); } build(): Transaction { @@ -240,41 +187,6 @@ export class TransactionBuilder { return this.__build(true); } - private __build(allowIncomplete?: boolean): Transaction { - if (!allowIncomplete) { - if (!this.__tx.ins.length) throw new Error('Transaction has no inputs'); - if (!this.__tx.outs.length) throw new Error('Transaction has no outputs'); - } - - const tx = this.__tx.clone(); - - // create script signatures from inputs - this.__inputs.forEach((input, i) => { - if (!input.prevOutType && !allowIncomplete) - throw new Error('Transaction is not complete'); - - const result = build(input.prevOutType!, input, allowIncomplete); - if (!result) { - if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) - throw new Error('Unknown input type'); - if (!allowIncomplete) throw new Error('Not enough information'); - return; - } - - tx.setInputScript(i, result.input!); - tx.setWitness(i, result.witness!); - }); - - if (!allowIncomplete) { - // do not rely on this, its merely a last resort - if (this.__overMaximumFees(tx.virtualSize())) { - throw new Error('Transaction has absurd fees'); - } - } - - return tx; - } - sign( vin: number, keyPair: ECPairInterface, @@ -286,13 +198,13 @@ export class TransactionBuilder { // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network'); - if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin); + if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin); hashType = hashType || Transaction.SIGHASH_ALL; if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs'); - const input = this.__inputs[vin]; + const input = this.__INPUTS[vin]; // if redeemScript was previously provided, enforce consistency if ( @@ -307,7 +219,7 @@ export class TransactionBuilder { if (!canSign(input)) { if (witnessValue !== undefined) { if (input.value !== undefined && input.value !== witnessValue) - throw new Error("Input didn't match witnessValue"); + throw new Error('Input did not match witnessValue'); typeforce(types.Satoshi, witnessValue); input.value = witnessValue; } @@ -330,16 +242,16 @@ export class TransactionBuilder { // ready to sign let signatureHash: Buffer; if (input.hasWitness) { - signatureHash = this.__tx.hashForWitnessV0( + signatureHash = this.__TX.hashForWitnessV0( vin, - input.signScript, - input.value, + input.signScript as Buffer, + input.value as number, hashType, ); } else { - signatureHash = this.__tx.hashForSignature( + signatureHash = this.__TX.hashForSignature( vin, - input.signScript, + input.signScript as Buffer, hashType, ); } @@ -364,8 +276,97 @@ export class TransactionBuilder { if (!signed) throw new Error('Key pair cannot sign for this input'); } + private __addInputUnsafe( + txHash: Buffer, + vout: number, + options: TxbInput, + ): number { + if (Transaction.isCoinbaseHash(txHash)) { + throw new Error('coinbase inputs not supported'); + } + + const prevTxOut = txHash.toString('hex') + ':' + vout; + if (this.__PREV_TX_SET[prevTxOut] !== undefined) + throw new Error('Duplicate TxOut: ' + prevTxOut); + + let input: TxbInput = {}; + + // derive what we can from the scriptSig + if (options.script !== undefined) { + input = expandInput(options.script, options.witness || []); + } + + // if an input value was given, retain it + if (options.value !== undefined) { + input.value = options.value; + } + + // derive what we can from the previous transactions output script + if (!input.prevOutScript && options.prevOutScript) { + let prevOutType; + + if (!input.pubkeys && !input.signatures) { + const expanded = expandOutput(options.prevOutScript); + if (expanded.pubkeys) { + input.pubkeys = expanded.pubkeys; + input.signatures = expanded.signatures; + } + + prevOutType = expanded.type; + } + + input.prevOutScript = options.prevOutScript; + input.prevOutType = prevOutType || classify.output(options.prevOutScript); + } + + const vin = this.__TX.addInput( + txHash, + vout, + options.sequence, + options.scriptSig, + ); + this.__INPUTS[vin] = input; + this.__PREV_TX_SET[prevTxOut] = true; + return vin; + } + + private __build(allowIncomplete?: boolean): Transaction { + if (!allowIncomplete) { + if (!this.__TX.ins.length) throw new Error('Transaction has no inputs'); + if (!this.__TX.outs.length) throw new Error('Transaction has no outputs'); + } + + const tx = this.__TX.clone(); + + // create script signatures from inputs + this.__INPUTS.forEach((input, i) => { + if (!input.prevOutType && !allowIncomplete) + throw new Error('Transaction is not complete'); + + const result = build(input.prevOutType!, input, allowIncomplete); + if (!result) { + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) + throw new Error('Unknown input type'); + if (!allowIncomplete) throw new Error('Not enough information'); + return; + } + + tx.setInputScript(i, result.input!); + tx.setWitness(i, result.witness!); + }); + + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__overMaximumFees(tx.virtualSize())) { + throw new Error('Transaction has absurd fees'); + } + } + + return tx; + } + private __canModifyInputs(): boolean { - return this.__inputs.every(input => { + return this.__INPUTS.every(input => { if (!input.signatures) return true; return input.signatures.every(signature => { @@ -381,14 +382,14 @@ export class TransactionBuilder { private __needsOutputs(signingHashType: number): boolean { if (signingHashType === Transaction.SIGHASH_ALL) { - return this.__tx.outs.length === 0; + return this.__TX.outs.length === 0; } // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // .build() will fail, but .buildIncomplete() is OK return ( - this.__tx.outs.length === 0 && - this.__inputs.some(input => { + this.__TX.outs.length === 0 && + this.__INPUTS.some(input => { if (!input.signatures) return false; return input.signatures.some(signature => { @@ -402,10 +403,10 @@ export class TransactionBuilder { } private __canModifyOutputs(): boolean { - const nInputs = this.__tx.ins.length; - const nOutputs = this.__tx.outs.length; + const nInputs = this.__TX.ins.length; + const nOutputs = this.__TX.outs.length; - return this.__inputs.every(input => { + return this.__INPUTS.every(input => { if (input.signatures === undefined) return true; return input.signatures.every(signature => { @@ -427,11 +428,14 @@ export class TransactionBuilder { private __overMaximumFees(bytes: number): boolean { // not all inputs will have .value defined - const incoming = this.__inputs.reduce((a, x) => a + (x.value! >>> 0), 0); + const incoming = this.__INPUTS.reduce((a, x) => a + (x.value! >>> 0), 0); // but all outputs do, and if we have any input value // we can immediately determine if the outputs are too small - const outgoing = this.__tx.outs.reduce((a, x) => a + (x).value, 0); + const outgoing = this.__TX.outs.reduce( + (a, x) => a + (x as Output).value, + 0, + ); const fee = incoming - outgoing; const feeRate = fee / bytes; @@ -441,7 +445,7 @@ export class TransactionBuilder { function expandInput( scriptSig: Buffer, - witnessStack: Array, + witnessStack: Buffer[], type?: string, scriptPubKey?: Buffer, ): TxbInput { @@ -502,8 +506,8 @@ function expandInput( return { prevOutType: SCRIPT_TYPES.P2MS, - pubkeys: pubkeys, - signatures: signatures, + pubkeys, + signatures, maxSignatures: m, }; } @@ -681,12 +685,12 @@ function prepareInput( witnessScript: Buffer, ): TxbInput { if (redeemScript && witnessScript) { - const p2wsh = ( - payments.p2wsh({ redeem: { output: witnessScript } }) - ); - const p2wshAlt = payments.p2wsh({ output: redeemScript }); - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); - const p2shAlt = payments.p2sh({ redeem: p2wsh }); + const p2wsh = payments.p2wsh({ + redeem: { output: witnessScript }, + }) as Payment; + const p2wshAlt = payments.p2wsh({ output: redeemScript }) as Payment; + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) as Payment; + const p2shAlt = payments.p2sh({ redeem: p2wsh }) as Payment; // enforces P2SH(P2WSH(...)) if (!p2wsh.hash!.equals(p2wshAlt.hash!)) @@ -706,7 +710,7 @@ function prepareInput( expanded.signatures = input.signatures; } - let signScript = witnessScript; + const signScript = witnessScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); @@ -731,12 +735,12 @@ function prepareInput( } if (redeemScript) { - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) as Payment; if (input.prevOutScript) { let p2shAlt; try { - p2shAlt = payments.p2sh({ output: input.prevOutScript }); + p2shAlt = payments.p2sh({ output: input.prevOutScript }) as Payment; } catch (e) { throw new Error('PrevOutScript must be P2SH'); } @@ -799,7 +803,7 @@ function prepareInput( expanded.signatures = input.signatures; } - let signScript = witnessScript; + const signScript = witnessScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) throw new Error('P2WSH(P2WPKH) is a consensus failure'); @@ -846,9 +850,8 @@ function prepareInput( let signScript = input.prevOutScript; if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = ( - payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output - ); + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }) + .output as Buffer; } return { @@ -868,7 +871,7 @@ function prepareInput( const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; return { prevOutType: SCRIPT_TYPES.P2PKH, - prevOutScript: prevOutScript, + prevOutScript, hasWitness: false, signScript: prevOutScript, @@ -884,8 +887,8 @@ function build( input: TxbInput, allowIncomplete?: boolean, ): Payment | undefined { - const pubkeys = >(input.pubkeys || []); - let signatures = >(input.signatures || []); + const pubkeys = (input.pubkeys || []) as Buffer[]; + let signatures = (input.signatures || []) as Buffer[]; switch (type) { case SCRIPT_TYPES.P2PKH: { diff --git a/types/transaction_builder.d.ts b/types/transaction_builder.d.ts index 4be5968..b3dedb3 100644 --- a/types/transaction_builder.d.ts +++ b/types/transaction_builder.d.ts @@ -1,24 +1,24 @@ /// +import { ECPairInterface } from './ecpair'; import { Network } from './networks'; import { Transaction } from './transaction'; -import { ECPairInterface } from './ecpair'; export declare class TransactionBuilder { + static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; network: Network; maximumFeeRate: number; - private __prevTxSet; - private __inputs; - private __tx; + private __PREV_TX_SET; + private __INPUTS; + private __TX; constructor(network?: Network, maximumFeeRate?: number); - static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; setLockTime(locktime: number): void; setVersion(version: number): void; addInput(txHash: Buffer | string | Transaction, vout: number, sequence: number, prevOutScript: Buffer): number; - private __addInputUnsafe; addOutput(scriptPubKey: string | Buffer, value: number): number; build(): Transaction; buildIncomplete(): Transaction; - private __build; sign(vin: number, keyPair: ECPairInterface, redeemScript: Buffer, hashType: number, witnessValue: number, witnessScript: Buffer): void; + private __addInputUnsafe; + private __build; private __canModifyInputs; private __needsOutputs; private __canModifyOutputs; From 08c4d6ac7dae7a8d61ded59f64bab68ad7f39f92 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 14:16:45 +0900 Subject: [PATCH 144/183] Fix lint for templates --- src/templates/multisig/input.js | 2 +- src/templates/multisig/output.js | 4 ++-- src/templates/nulldata.js | 2 +- src/templates/pubkey/input.js | 5 +++-- src/templates/pubkey/output.js | 2 +- src/templates/pubkeyhash/input.js | 2 +- src/templates/pubkeyhash/output.js | 2 +- src/templates/scripthash/input.js | 2 +- src/templates/scripthash/output.js | 2 +- src/templates/witnesscommitment/output.js | 4 ++-- src/templates/witnesspubkeyhash/input.js | 2 +- src/templates/witnesspubkeyhash/output.js | 2 +- src/templates/witnessscripthash/input.js | 2 +- src/templates/witnessscripthash/output.js | 2 +- ts_src/templates/multisig/input.ts | 11 ++++++----- ts_src/templates/multisig/output.ts | 15 ++++++++------- ts_src/templates/nulldata.ts | 2 +- ts_src/templates/pubkey/input.ts | 10 ++++++---- ts_src/templates/pubkey/output.ts | 9 +++++---- ts_src/templates/pubkeyhash/input.ts | 11 ++++++----- ts_src/templates/pubkeyhash/output.ts | 2 +- ts_src/templates/scripthash/input.ts | 2 +- ts_src/templates/scripthash/output.ts | 2 +- ts_src/templates/witnesscommitment/output.ts | 6 +++--- ts_src/templates/witnesspubkeyhash/input.ts | 11 ++++++----- ts_src/templates/witnesspubkeyhash/output.ts | 2 +- ts_src/templates/witnessscripthash/input.ts | 7 ++----- ts_src/templates/witnessscripthash/output.ts | 2 +- types/templates/multisig/input.d.ts | 3 ++- types/templates/multisig/output.d.ts | 3 ++- types/templates/pubkey/input.d.ts | 3 ++- types/templates/pubkey/output.d.ts | 3 ++- types/templates/pubkeyhash/input.d.ts | 3 ++- types/templates/witnesspubkeyhash/input.d.ts | 3 ++- types/templates/witnessscripthash/input.d.ts | 2 +- 35 files changed, 79 insertions(+), 68 deletions(-) diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.js index 24a9710..4b4f395 100644 --- a/src/templates/multisig/input.js +++ b/src/templates/multisig/input.js @@ -18,6 +18,6 @@ function check(script, allowIncomplete) { return chunks.slice(1).every(bscript.isCanonicalScriptSignature); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'multisig input'; }; diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.js index 64d07bc..c79fe9b 100644 --- a/src/templates/multisig/output.js +++ b/src/templates/multisig/output.js @@ -2,8 +2,8 @@ // m [pubKeys ...] n OP_CHECKMULTISIG Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); -const types = require("../../types"); const script_1 = require("../../script"); +const types = require("../../types"); const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1 function check(script, allowIncomplete) { const chunks = bscript.decompile(script); @@ -31,6 +31,6 @@ function check(script, allowIncomplete) { return keys.every(bscript.isCanonicalPubKey); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'multi-sig output'; }; diff --git a/src/templates/nulldata.js b/src/templates/nulldata.js index b5ffdce..29bee7a 100644 --- a/src/templates/nulldata.js +++ b/src/templates/nulldata.js @@ -8,7 +8,7 @@ function check(script) { return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'null data output'; }; const output = { check }; diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.js index 10d3c07..479fdc5 100644 --- a/src/templates/pubkey/input.js +++ b/src/templates/pubkey/input.js @@ -4,9 +4,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); function check(script) { const chunks = bscript.decompile(script); - return (chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0])); + return (chunks.length === 1 && + bscript.isCanonicalScriptSignature(chunks[0])); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'pubKey input'; }; diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.js index e2f87c2..1f17990 100644 --- a/src/templates/pubkey/output.js +++ b/src/templates/pubkey/output.js @@ -10,6 +10,6 @@ function check(script) { chunks[1] === script_1.OPS.OP_CHECKSIG); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'pubKey output'; }; diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.js index f03d391..7de30ec 100644 --- a/src/templates/pubkeyhash/input.js +++ b/src/templates/pubkeyhash/input.js @@ -9,6 +9,6 @@ function check(script) { bscript.isCanonicalPubKey(chunks[1])); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'pubKeyHash input'; }; diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.js index 222244b..5ee692b 100644 --- a/src/templates/pubkeyhash/output.js +++ b/src/templates/pubkeyhash/output.js @@ -13,6 +13,6 @@ function check(script) { buffer[24] === script_1.OPS.OP_CHECKSIG); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'pubKeyHash output'; }; diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.js index 5d2b576..488b931 100644 --- a/src/templates/scripthash/input.js +++ b/src/templates/scripthash/input.js @@ -39,6 +39,6 @@ function check(script, allowIncomplete) { return false; } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'scriptHash input'; }; diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.js index 5fd2f65..bf1246a 100644 --- a/src/templates/scripthash/output.js +++ b/src/templates/scripthash/output.js @@ -11,6 +11,6 @@ function check(script) { buffer[22] === script_1.OPS.OP_EQUAL); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'scriptHash output'; }; diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.js index 38f622a..f4d6af0 100644 --- a/src/templates/witnesscommitment/output.js +++ b/src/templates/witnesscommitment/output.js @@ -2,9 +2,9 @@ // OP_RETURN {aa21a9ed} {commitment} Object.defineProperty(exports, "__esModule", { value: true }); const bscript = require("../../script"); +const script_1 = require("../../script"); const types = require("../../types"); const typeforce = require('typeforce'); -const script_1 = require("../../script"); const HEADER = Buffer.from('aa21a9ed', 'hex'); function check(script) { const buffer = bscript.compile(script); @@ -14,7 +14,7 @@ function check(script) { buffer.slice(2, 6).equals(HEADER)); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'Witness commitment output'; }; function encode(commitment) { diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.js index 4585623..3d589e9 100644 --- a/src/templates/witnesspubkeyhash/input.js +++ b/src/templates/witnesspubkeyhash/input.js @@ -12,6 +12,6 @@ function check(script) { isCompressedCanonicalPubKey(chunks[1])); } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'witnessPubKeyHash input'; }; diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.js index 9c508a0..69aab11 100644 --- a/src/templates/witnesspubkeyhash/output.js +++ b/src/templates/witnesspubkeyhash/output.js @@ -8,6 +8,6 @@ function check(script) { return buffer.length === 22 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x14; } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'Witness pubKeyHash output'; }; diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.js index ca8c8b6..3f5c002 100644 --- a/src/templates/witnessscripthash/input.js +++ b/src/templates/witnessscripthash/input.js @@ -31,6 +31,6 @@ function check(chunks, allowIncomplete) { return false; } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'witnessScriptHash input'; }; diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.js index f283b86..a6d4d95 100644 --- a/src/templates/witnessscripthash/output.js +++ b/src/templates/witnessscripthash/output.js @@ -8,6 +8,6 @@ function check(script) { return buffer.length === 34 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x20; } exports.check = check; -check.toJSON = function () { +check.toJSON = () => { return 'Witness scriptHash output'; }; diff --git a/ts_src/templates/multisig/input.ts b/ts_src/templates/multisig/input.ts index 222ff10..57b73d2 100644 --- a/ts_src/templates/multisig/input.ts +++ b/ts_src/templates/multisig/input.ts @@ -1,19 +1,20 @@ // OP_0 [signatures ...] +import { Stack } from '../../payments'; import * as bscript from '../../script'; import { OPS } from '../../script'; function partialSignature(value: number | Buffer): boolean { return ( - value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value) + value === OPS.OP_0 || bscript.isCanonicalScriptSignature(value as Buffer) ); } export function check( - script: Buffer | Array, + script: Buffer | Stack, allowIncomplete?: boolean, ): boolean { - const chunks = >bscript.decompile(script); + const chunks = bscript.decompile(script) as Stack; if (chunks.length < 2) return false; if (chunks[0] !== OPS.OP_0) return false; @@ -21,10 +22,10 @@ export function check( return chunks.slice(1).every(partialSignature); } - return (>chunks.slice(1)).every( + return (chunks.slice(1) as Buffer[]).every( bscript.isCanonicalScriptSignature, ); } -check.toJSON = function() { +check.toJSON = () => { return 'multisig input'; }; diff --git a/ts_src/templates/multisig/output.ts b/ts_src/templates/multisig/output.ts index 040649b..3ee0820 100644 --- a/ts_src/templates/multisig/output.ts +++ b/ts_src/templates/multisig/output.ts @@ -1,22 +1,23 @@ // m [pubKeys ...] n OP_CHECKMULTISIG +import { Stack } from '../../payments'; import * as bscript from '../../script'; -import * as types from '../../types'; import { OPS } from '../../script'; +import * as types from '../../types'; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 export function check( - script: Buffer | Array, + script: Buffer | Stack, allowIncomplete?: boolean, ): boolean { - const chunks = >bscript.decompile(script); + const chunks = bscript.decompile(script) as Stack; if (chunks.length < 4) return false; if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false; if (!types.Number(chunks[0])) return false; if (!types.Number(chunks[chunks.length - 2])) return false; - const m = chunks[0] - OP_INT_BASE; - const n = chunks[chunks.length - 2] - OP_INT_BASE; + const m = (chunks[0] as number) - OP_INT_BASE; + const n = (chunks[chunks.length - 2] as number) - OP_INT_BASE; if (m <= 0) return false; if (n > 16) return false; @@ -24,9 +25,9 @@ export function check( if (n !== chunks.length - 3) return false; if (allowIncomplete) return true; - const keys = >chunks.slice(1, -2); + const keys = chunks.slice(1, -2) as Buffer[]; return keys.every(bscript.isCanonicalPubKey); } -check.toJSON = function() { +check.toJSON = () => { return 'multi-sig output'; }; diff --git a/ts_src/templates/nulldata.ts b/ts_src/templates/nulldata.ts index f0694a3..bafe4a4 100644 --- a/ts_src/templates/nulldata.ts +++ b/ts_src/templates/nulldata.ts @@ -7,7 +7,7 @@ export function check(script: Buffer | Array): boolean { return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } -check.toJSON = function() { +check.toJSON = () => { return 'null data output'; }; diff --git a/ts_src/templates/pubkey/input.ts b/ts_src/templates/pubkey/input.ts index e9ea1be..7e07a94 100644 --- a/ts_src/templates/pubkey/input.ts +++ b/ts_src/templates/pubkey/input.ts @@ -1,14 +1,16 @@ // {signature} +import { Stack } from '../../payments'; import * as bscript from '../../script'; -export function check(script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script); +export function check(script: Buffer | Stack): boolean { + const chunks = bscript.decompile(script) as Stack; return ( - chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]) + chunks.length === 1 && + bscript.isCanonicalScriptSignature(chunks[0] as Buffer) ); } -check.toJSON = function() { +check.toJSON = () => { return 'pubKey input'; }; diff --git a/ts_src/templates/pubkey/output.ts b/ts_src/templates/pubkey/output.ts index 8378870..d57422d 100644 --- a/ts_src/templates/pubkey/output.ts +++ b/ts_src/templates/pubkey/output.ts @@ -1,17 +1,18 @@ // {pubKey} OP_CHECKSIG +import { Stack } from '../../payments'; import * as bscript from '../../script'; import { OPS } from '../../script'; -export function check(script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script); +export function check(script: Buffer | Stack): boolean { + const chunks = bscript.decompile(script) as Stack; return ( chunks.length === 2 && - bscript.isCanonicalPubKey(chunks[0]) && + bscript.isCanonicalPubKey(chunks[0] as Buffer) && chunks[1] === OPS.OP_CHECKSIG ); } -check.toJSON = function() { +check.toJSON = () => { return 'pubKey output'; }; diff --git a/ts_src/templates/pubkeyhash/input.ts b/ts_src/templates/pubkeyhash/input.ts index c091764..83da475 100644 --- a/ts_src/templates/pubkeyhash/input.ts +++ b/ts_src/templates/pubkeyhash/input.ts @@ -1,16 +1,17 @@ // {signature} {pubKey} +import { Stack } from '../../payments'; import * as bscript from '../../script'; -export function check(script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script); +export function check(script: Buffer | Stack): boolean { + const chunks = bscript.decompile(script) as Stack; return ( chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - bscript.isCanonicalPubKey(chunks[1]) + bscript.isCanonicalScriptSignature(chunks[0] as Buffer) && + bscript.isCanonicalPubKey(chunks[1] as Buffer) ); } -check.toJSON = function() { +check.toJSON = () => { return 'pubKeyHash input'; }; diff --git a/ts_src/templates/pubkeyhash/output.ts b/ts_src/templates/pubkeyhash/output.ts index a5c5c9b..37070a3 100644 --- a/ts_src/templates/pubkeyhash/output.ts +++ b/ts_src/templates/pubkeyhash/output.ts @@ -15,6 +15,6 @@ export function check(script: Buffer | Array): boolean { buffer[24] === OPS.OP_CHECKSIG ); } -check.toJSON = function() { +check.toJSON = () => { return 'pubKeyHash output'; }; diff --git a/ts_src/templates/scripthash/input.ts b/ts_src/templates/scripthash/input.ts index 0b86d63..1e3f97d 100644 --- a/ts_src/templates/scripthash/input.ts +++ b/ts_src/templates/scripthash/input.ts @@ -56,6 +56,6 @@ export function check( return false; } -check.toJSON = function() { +check.toJSON = () => { return 'scriptHash input'; }; diff --git a/ts_src/templates/scripthash/output.ts b/ts_src/templates/scripthash/output.ts index 6ff138a..7eac30d 100644 --- a/ts_src/templates/scripthash/output.ts +++ b/ts_src/templates/scripthash/output.ts @@ -13,6 +13,6 @@ export function check(script: Buffer | Array): boolean { buffer[22] === OPS.OP_EQUAL ); } -check.toJSON = function() { +check.toJSON = () => { return 'scriptHash output'; }; diff --git a/ts_src/templates/witnesscommitment/output.ts b/ts_src/templates/witnesscommitment/output.ts index 29beb39..9439e4c 100644 --- a/ts_src/templates/witnesscommitment/output.ts +++ b/ts_src/templates/witnesscommitment/output.ts @@ -1,10 +1,10 @@ // OP_RETURN {aa21a9ed} {commitment} import * as bscript from '../../script'; +import { OPS } from '../../script'; import * as types from '../../types'; const typeforce = require('typeforce'); -import { OPS } from '../../script'; const HEADER: Buffer = Buffer.from('aa21a9ed', 'hex'); @@ -19,7 +19,7 @@ export function check(script: Buffer | Array): boolean { ); } -check.toJSON = function() { +check.toJSON = () => { return 'Witness commitment output'; }; @@ -36,5 +36,5 @@ export function encode(commitment: Buffer): Buffer { export function decode(buffer: Buffer): Buffer { typeforce(check, buffer); - return (bscript.decompile(buffer)![1]).slice(4, 36); + return (bscript.decompile(buffer)![1] as Buffer).slice(4, 36); } diff --git a/ts_src/templates/witnesspubkeyhash/input.ts b/ts_src/templates/witnesspubkeyhash/input.ts index 22fc2cf..aa3bef8 100644 --- a/ts_src/templates/witnesspubkeyhash/input.ts +++ b/ts_src/templates/witnesspubkeyhash/input.ts @@ -1,20 +1,21 @@ // {signature} {pubKey} +import { Stack } from '../../payments'; import * as bscript from '../../script'; function isCompressedCanonicalPubKey(pubKey: Buffer): boolean { return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; } -export function check(script: Buffer | Array): boolean { - const chunks = >bscript.decompile(script); +export function check(script: Buffer | Stack): boolean { + const chunks = bscript.decompile(script) as Stack; return ( chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - isCompressedCanonicalPubKey(chunks[1]) + bscript.isCanonicalScriptSignature(chunks[0] as Buffer) && + isCompressedCanonicalPubKey(chunks[1] as Buffer) ); } -check.toJSON = function() { +check.toJSON = () => { return 'witnessPubKeyHash input'; }; diff --git a/ts_src/templates/witnesspubkeyhash/output.ts b/ts_src/templates/witnesspubkeyhash/output.ts index 09c49d0..0e9432c 100644 --- a/ts_src/templates/witnesspubkeyhash/output.ts +++ b/ts_src/templates/witnesspubkeyhash/output.ts @@ -8,6 +8,6 @@ export function check(script: Buffer | Array): boolean { return buffer.length === 22 && buffer[0] === OPS.OP_0 && buffer[1] === 0x14; } -check.toJSON = function() { +check.toJSON = () => { return 'Witness pubKeyHash output'; }; diff --git a/ts_src/templates/witnessscripthash/input.ts b/ts_src/templates/witnessscripthash/input.ts index 6cf35bf..42a13ac 100644 --- a/ts_src/templates/witnessscripthash/input.ts +++ b/ts_src/templates/witnessscripthash/input.ts @@ -7,10 +7,7 @@ import * as p2ms from '../multisig'; import * as p2pk from '../pubkey'; import * as p2pkh from '../pubkeyhash'; -export function check( - chunks: Array, - allowIncomplete?: boolean, -): boolean { +export function check(chunks: Buffer[], allowIncomplete?: boolean): boolean { typeforce(typeforce.Array, chunks); if (chunks.length < 1) return false; @@ -45,6 +42,6 @@ export function check( return false; } -check.toJSON = function() { +check.toJSON = () => { return 'witnessScriptHash input'; }; diff --git a/ts_src/templates/witnessscripthash/output.ts b/ts_src/templates/witnessscripthash/output.ts index 430cc4f..85034d1 100644 --- a/ts_src/templates/witnessscripthash/output.ts +++ b/ts_src/templates/witnessscripthash/output.ts @@ -8,6 +8,6 @@ export function check(script: Buffer | Array): boolean { return buffer.length === 34 && buffer[0] === OPS.OP_0 && buffer[1] === 0x20; } -check.toJSON = function() { +check.toJSON = () => { return 'Witness scriptHash output'; }; diff --git a/types/templates/multisig/input.d.ts b/types/templates/multisig/input.d.ts index a04d03c..a207dd6 100644 --- a/types/templates/multisig/input.d.ts +++ b/types/templates/multisig/input.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack, allowIncomplete?: boolean): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/multisig/output.d.ts b/types/templates/multisig/output.d.ts index a04d03c..a207dd6 100644 --- a/types/templates/multisig/output.d.ts +++ b/types/templates/multisig/output.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack, allowIncomplete?: boolean): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/pubkey/input.d.ts b/types/templates/pubkey/input.d.ts index 091758f..c4ffeab 100644 --- a/types/templates/pubkey/input.d.ts +++ b/types/templates/pubkey/input.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/pubkey/output.d.ts b/types/templates/pubkey/output.d.ts index 091758f..c4ffeab 100644 --- a/types/templates/pubkey/output.d.ts +++ b/types/templates/pubkey/output.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/pubkeyhash/input.d.ts b/types/templates/pubkeyhash/input.d.ts index 091758f..c4ffeab 100644 --- a/types/templates/pubkeyhash/input.d.ts +++ b/types/templates/pubkeyhash/input.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/witnesspubkeyhash/input.d.ts b/types/templates/witnesspubkeyhash/input.d.ts index 091758f..c4ffeab 100644 --- a/types/templates/witnesspubkeyhash/input.d.ts +++ b/types/templates/witnesspubkeyhash/input.d.ts @@ -1,5 +1,6 @@ /// -export declare function check(script: Buffer | Array): boolean; +import { Stack } from '../../payments'; +export declare function check(script: Buffer | Stack): boolean; export declare namespace check { var toJSON: () => string; } diff --git a/types/templates/witnessscripthash/input.d.ts b/types/templates/witnessscripthash/input.d.ts index 7786731..b2a6e8a 100644 --- a/types/templates/witnessscripthash/input.d.ts +++ b/types/templates/witnessscripthash/input.d.ts @@ -1,5 +1,5 @@ /// -export declare function check(chunks: Array, allowIncomplete?: boolean): boolean; +export declare function check(chunks: Buffer[], allowIncomplete?: boolean): boolean; export declare namespace check { var toJSON: () => string; } From 7fb859b1f70f0aab4fe68fe60f85f4aa62689637 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 14:21:11 +0900 Subject: [PATCH 145/183] Fix lint types.ts --- src/types.js | 8 ++++---- ts_src/types.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/types.js b/src/types.js index 76b98cf..dbe7ca5 100644 --- a/src/types.js +++ b/src/types.js @@ -10,7 +10,7 @@ function BIP32Path(value) { return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } exports.BIP32Path = BIP32Path; -BIP32Path.toJSON = function () { +BIP32Path.toJSON = () => { return 'BIP32 derivation path'; }; const SATOSHI_MAX = 21 * 1e14; @@ -34,10 +34,10 @@ exports.Network = typeforce.compile({ exports.Buffer256bit = typeforce.BufferN(32); exports.Hash160bit = typeforce.BufferN(20); exports.Hash256bit = typeforce.BufferN(32); -exports.Number = typeforce.Number; +exports.Number = typeforce.Number; // tslint:disable-line variable-name exports.Array = typeforce.Array; -exports.Boolean = typeforce.Boolean; -exports.String = typeforce.String; +exports.Boolean = typeforce.Boolean; // tslint:disable-line variable-name +exports.String = typeforce.String; // tslint:disable-line variable-name exports.Buffer = typeforce.Buffer; exports.Hex = typeforce.Hex; exports.maybe = typeforce.maybe; diff --git a/ts_src/types.ts b/ts_src/types.ts index 42ddb40..033e62a 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -8,7 +8,7 @@ export function UInt31(value: number): boolean { export function BIP32Path(value: string): boolean { return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } -BIP32Path.toJSON = function() { +BIP32Path.toJSON = () => { return 'BIP32 derivation path'; }; @@ -35,10 +35,10 @@ export const Network = typeforce.compile({ export const Buffer256bit = typeforce.BufferN(32); export const Hash160bit = typeforce.BufferN(20); export const Hash256bit = typeforce.BufferN(32); -export const Number = typeforce.Number; +export const Number = typeforce.Number; // tslint:disable-line variable-name export const Array = typeforce.Array; -export const Boolean = typeforce.Boolean; -export const String = typeforce.String; +export const Boolean = typeforce.Boolean; // tslint:disable-line variable-name +export const String = typeforce.String; // tslint:disable-line variable-name export const Buffer = typeforce.Buffer; export const Hex = typeforce.Hex; export const maybe = typeforce.maybe; From cb21cdb74c398a95b183cc2ed9abb3ffc17c0ac3 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 15:54:58 +0900 Subject: [PATCH 146/183] Specify version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 898fac8..ae28889 100644 --- a/package.json +++ b/package.json @@ -69,9 +69,9 @@ "minimaldata": "^1.0.2", "mocha": "^5.2.0", "nyc": "^11.8.0", - "prettier": "^1.16.4", + "prettier": "1.16.4", "proxyquire": "^2.0.1", - "tslint": "^5.13.1", + "tslint": "5.13.1", "typescript": "3.2.2" }, "license": "MIT" From 64aa7bacc3fc237cf4c0cb62c336bdfd063d123c Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 16:43:12 +0900 Subject: [PATCH 147/183] Add TypeScript section to CONTRIBUTING --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index efc9cae..2c72633 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,22 @@ The length of time required for peer review is unpredictable and will vary from Refer to the [Git manual](https://git-scm.com/doc) for any information about `git`. +## Regarding TypeScript +This library is written in TypeScript with tslint, prettier, and the tsc transpiler. These tools will help during testing to notice improper logic before committing and sending a pull request. + +Some rules regarding TypeScript: + +* Modify the typescript source code in an IDE that will give you warnings for transpile/lint errors. +* Once you are done with the modifications, run `npm run format` then `npm test` +* Running the tests will transpile the ts files into js and d.ts files. +* Use `git diff` or other tools to verify that the ts and js are changing the same parts. +* Commit all changes to ts, js, and d.ts files. +* Add tests where necessary. +* Submit your pull request. + +Using TypeScript is for preventing bugs while writing code, as well as automatically generating type definitions. However, the JS file diffs must be verified, and any unverified JS will not be published to npm. + + ## We adhere to Bitcoin-Core policy Bitcoin script payment/script templates are based on community consensus, but typically adhere to bitcoin-core node policy by default. From 32721c723e232936676121052fe26d02a6519bf9 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 7 Mar 2019 16:46:17 +0900 Subject: [PATCH 148/183] Modify typescript portion of README --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index b8f70f2..458693f 100644 --- a/README.md +++ b/README.md @@ -78,16 +78,7 @@ If you're familiar with how to use browserify, ignore this and carry on, otherwi **WARNING**: iOS devices have [problems](https://github.com/feross/buffer/issues/136), use atleast [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater, and enforce the test suites (for `Buffer`, and any other dependency) pass before use. ### Typescript or VSCode users -Type declarations for Typescript [are available](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/0897921174860ec3d5318992d2323b3ae8100a68/types/bitcoinjs-lib) for version `^3.0.0` of the library. - -``` bash -npm install @types/bitcoinjs-lib -``` - -For VSCode (and other editors), it is advised to install the type declarations, as Intellisense uses that information to help you code (autocompletion, static analysis). - -**WARNING**: These Typescript definitions are not maintained by the maintainers of this repository, and are instead maintained at [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped). -Please report any issues or problems there. +Type declarations for Typescript are included in this library. Normal installation should include all the needed type information. ### Flow From 0426c6638971dbb4748e948342416fb7dafedf0d Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 14 Mar 2019 17:32:45 +0900 Subject: [PATCH 149/183] Remove prepare script and checkMerkleRoot method on Block --- package.json | 1 - src/block.js | 5 ----- ts_src/block.ts | 8 -------- types/block.d.ts | 1 - 4 files changed, 15 deletions(-) diff --git a/package.json b/package.json index ae28889..e62819a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", "nobuild:integration": "mocha --timeout 50000 test/integration/", "nobuild:unit": "mocha", - "prepare": "npm run build", "prettier": "prettier 'ts_src/**/*.ts' --ignore-path ./.prettierignore", "test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" diff --git a/src/block.js b/src/block.js index 9419989..913ad9a 100644 --- a/src/block.js +++ b/src/block.js @@ -199,11 +199,6 @@ class Block { return (this.__checkMerkleRoot() && (hasWitnessCommit ? this.__checkWitnessCommit() : true)); } - checkMerkleRoot() { - console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + - 'deprecated in v5. Please use checkTxRoots instead.'); - return this.checkTxRoots(); - } checkProofOfWork() { const hash = bufferutils_1.reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); diff --git a/ts_src/block.ts b/ts_src/block.ts index 888337d..9a9bd45 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -269,14 +269,6 @@ export class Block { ); } - checkMerkleRoot(): boolean { - console.warn( - 'Deprecation Warning: Block method checkMerkleRoot will be ' + - 'deprecated in v5. Please use checkTxRoots instead.', - ); - return this.checkTxRoots(); - } - checkProofOfWork(): boolean { const hash: Buffer = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); diff --git a/types/block.d.ts b/types/block.d.ts index 6f2d5b9..6b6596c 100644 --- a/types/block.d.ts +++ b/types/block.d.ts @@ -24,7 +24,6 @@ export declare class Block { toBuffer(headersOnly: boolean): Buffer; toHex(headersOnly: boolean): string; checkTxRoots(): boolean; - checkMerkleRoot(): boolean; checkProofOfWork(): boolean; private __checkMerkleRoot; private __checkWitnessCommit; From fabd1d6c9d78046bdeb27da52ef7340ea6f24db8 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 19 Mar 2019 12:57:27 +0900 Subject: [PATCH 150/183] Update bip32 and nyc to latest --- package-lock.json | 2775 +++++++++++---------------------------------- package.json | 4 +- 2 files changed, 686 insertions(+), 2093 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9de2ff5..3b11623 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,138 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "dev": true + }, + "@babel/template": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" + } + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", @@ -90,9 +222,11 @@ } }, "bip32": { - "version": "git+https://github.com/junderw/bip32.git#0df550ad047210fe5cfcc189bb78db645f2f1a89", - "from": "git+https://github.com/junderw/bip32.git#typeScript", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.0.tgz", + "integrity": "sha512-dYuSVcH43KXLsmiOlud62m5ZP3KG8UBUAbP+wMq8VKuhPvxOOM8VOXRs6ppcJB4iUJtYjmg7VuzTlr8waMusfg==", "requires": { + "@types/node": "10.12.18", "bs58check": "^2.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -363,6 +497,12 @@ "path-is-absolute": "^1.0.0" } }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -445,6 +585,27 @@ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", "dev": true }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -461,6 +622,18 @@ "esprima": "^4.0.0" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -563,1287 +736,288 @@ "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, "nyc": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz", - "integrity": "sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.3.0.tgz", + "integrity": "sha512-P+FwIuro2aFG6B0Esd9ZDWUd51uZrAEoGutqZxzrVmYl3qSfkLgcQpBPBjtDFsUQLFY1dvTQJPOyeqr8S9GF8w==", "dev": true, "requires": { "archy": "^1.0.0", "arrify": "^1.0.1", - "caching-transform": "^1.0.0", - "convert-source-map": "^1.5.1", - "debug-log": "^1.0.1", - "default-require-extensions": "^1.0.0", - "find-cache-dir": "^0.1.1", - "find-up": "^2.1.0", - "foreground-child": "^1.5.3", - "glob": "^7.0.6", - "istanbul-lib-coverage": "^1.1.2", - "istanbul-lib-hook": "^1.1.0", - "istanbul-lib-instrument": "^1.10.0", - "istanbul-lib-report": "^1.1.3", - "istanbul-lib-source-maps": "^1.2.3", - "istanbul-reports": "^1.4.0", - "md5-hex": "^1.2.0", + "caching-transform": "^3.0.1", + "convert-source-map": "^1.6.0", + "find-cache-dir": "^2.0.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.3", + "istanbul-lib-hook": "^2.0.3", + "istanbul-lib-instrument": "^3.1.0", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.2", + "istanbul-reports": "^2.1.1", + "make-dir": "^1.3.0", "merge-source-map": "^1.1.0", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.0", - "resolve-from": "^2.0.0", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.1", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.0", - "yargs": "11.1.0", - "yargs-parser": "^8.0.0" + "test-exclude": "^5.1.0", + "uuid": "^3.3.2", + "yargs": "^12.0.5", + "yargs-parser": "^11.1.1" }, "dependencies": { - "align-text": { - "version": "0.1.4", + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "default-require-extensions": "^2.0.0" } }, - "amdefine": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", + "archy": { + "version": "1.0.0", "bundled": true, "dev": true }, - "ansi-styles": { - "version": "2.2.1", + "arrify": { + "version": "1.0.1", "bundled": true, "dev": true }, - "append-transform": { - "version": "0.4.0", + "async": { + "version": "2.6.2", "bundled": true, "dev": true, "requires": { - "default-require-extensions": "^1.0.0" + "lodash": "^4.17.11" } }, - "archy": { + "balanced-match": { "version": "1.0.0", "bundled": true, "dev": true }, - "arr-diff": { - "version": "4.0.0", + "brace-expansion": { + "version": "1.1.11", "bundled": true, - "dev": true + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "arr-flatten": { - "version": "1.1.0", + "caching-transform": { + "version": "3.0.1", "bundled": true, - "dev": true + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^1.3.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.3.0" + } }, - "arr-union": { - "version": "3.1.0", + "camelcase": { + "version": "5.0.0", "bundled": true, "dev": true }, - "array-unique": { - "version": "0.3.2", + "cliui": { + "version": "4.1.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } }, - "arrify": { - "version": "1.0.1", + "code-point-at": { + "version": "1.1.0", "bundled": true, "dev": true }, - "assign-symbols": { - "version": "1.0.0", + "commander": { + "version": "2.17.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, - "async": { - "version": "1.5.2", + "commondir": { + "version": "1.0.1", "bundled": true, "dev": true }, - "atob": { - "version": "2.1.1", + "concat-map": { + "version": "0.0.1", "bundled": true, "dev": true }, - "babel-code-frame": { - "version": "6.26.0", + "convert-source-map": { + "version": "1.6.0", "bundled": true, "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "safe-buffer": "~5.1.1" } }, - "babel-generator": { - "version": "6.26.1", + "cross-spawn": { + "version": "4.0.2", "bundled": true, "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, - "babel-messages": { - "version": "6.23.0", + "debug": { + "version": "4.1.1", "bundled": true, "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "ms": "^2.1.1" } }, - "babel-runtime": { - "version": "6.26.0", + "decamelize": { + "version": "1.2.0", "bundled": true, - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } + "dev": true }, - "babel-template": { - "version": "6.26.0", + "default-require-extensions": { + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "strip-bom": "^3.0.0" } }, - "babel-traverse": { - "version": "6.26.0", + "end-of-stream": { + "version": "1.4.1", "bundled": true, "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "once": "^1.4.0" } }, - "babel-types": { - "version": "6.26.0", + "error-ex": { + "version": "1.3.2", "bundled": true, "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "is-arrayish": "^0.2.1" } }, - "babylon": { - "version": "6.18.0", + "es6-error": { + "version": "4.1.1", "bundled": true, "dev": true }, - "balanced-match": { + "execa": { "version": "1.0.0", "bundled": true, - "dev": true - }, - "base": { - "version": "0.11.2", - "bundled": true, "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", + "cross-spawn": { + "version": "6.0.5", "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true } } }, - "brace-expansion": { - "version": "1.1.11", + "find-cache-dir": { + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^3.0.0" } }, - "braces": { - "version": "2.3.2", + "find-up": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "locate-path": "^3.0.0" } }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "cache-base": { - "version": "1.0.1", + "foreground-child": { + "version": "1.5.6", "bundled": true, "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } + "cross-spawn": "^4", + "signal-exit": "^3.0.0" } }, - "caching-transform": { - "version": "1.0.1", + "fs.realpath": { + "version": "1.0.0", "bundled": true, - "dev": true, - "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" - } + "dev": true }, - "camelcase": { - "version": "1.2.1", + "get-caller-file": { + "version": "1.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, - "center-align": { - "version": "0.1.3", + "get-stream": { + "version": "4.1.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "pump": "^3.0.0" } }, - "chalk": { - "version": "1.1.3", + "glob": { + "version": "7.1.3", "bundled": true, "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "class-utils": { - "version": "0.3.6", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "cliui": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "bundled": true, - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "core-js": { - "version": "2.5.6", - "bundled": true, - "dev": true - }, - "cross-spawn": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "debug-log": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "default-require-extensions": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-property": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "detect-indent": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true, - "dev": true - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "foreground-child": { - "version": "1.5.6", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "fragment-cache": { - "version": "0.2.1", - "bundled": true, - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "get-value": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "9.18.0", - "bundled": true, - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "bundled": true, - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "bundled": true, - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "has-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "has-values": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true, - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "invariant": { - "version": "2.2.4", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-odd": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "istanbul-lib-coverage": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.10.1", - "bundled": true, - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "supports-color": { - "version": "3.2.3", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.3", - "bundled": true, - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "istanbul-reports": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "handlebars": "^4.0.3" - } - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "jsesc": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "lazy-cache": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true, - "dev": true - }, - "longest": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "loose-envify": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "map-cache": { - "version": "0.2.2", - "bundled": true, - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5-hex": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } - }, - "md5-o-matic": { - "version": "0.1.1", + "graceful-fs": { + "version": "4.1.15", "bundled": true, "dev": true }, - "mem": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", + "handlebars": { + "version": "4.1.0", "bundled": true, "dev": true, "requires": { - "source-map": "^0.6.1" + "async": "^2.5.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" }, "dependencies": { "source-map": { @@ -1853,1188 +1027,626 @@ } } }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", + "has-flag": { + "version": "3.0.0", "bundled": true, "dev": true }, - "minimatch": { - "version": "3.0.4", + "hasha": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "is-stream": "^1.0.1" } }, - "minimist": { - "version": "0.0.8", + "hosted-git-info": { + "version": "2.7.1", "bundled": true, "dev": true }, - "mixin-deep": { - "version": "1.3.1", + "imurmurhash": { + "version": "0.1.4", "bundled": true, - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } + "dev": true }, - "mkdirp": { - "version": "0.5.1", + "inflight": { + "version": "1.0.6", "bundled": true, "dev": true, "requires": { - "minimist": "0.0.8" + "once": "^1.3.0", + "wrappy": "1" } }, - "ms": { + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invert-kv": { "version": "2.0.0", "bundled": true, "dev": true }, - "nanomatch": { - "version": "1.2.9", + "is-arrayish": { + "version": "0.2.1", "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } + "dev": true }, - "normalize-package-data": { - "version": "2.4.0", + "is-fullwidth-code-point": { + "version": "2.0.0", "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } + "dev": true }, - "npm-run-path": { - "version": "2.0.2", + "is-stream": { + "version": "1.1.0", "bundled": true, - "dev": true, - "requires": { - "path-key": "^2.0.0" - } + "dev": true }, - "number-is-nan": { - "version": "1.0.1", + "isexe": { + "version": "2.0.0", "bundled": true, "dev": true }, - "object-assign": { - "version": "4.1.1", + "istanbul-lib-coverage": { + "version": "2.0.3", "bundled": true, "dev": true }, - "object-copy": { - "version": "0.1.0", + "istanbul-lib-hook": { + "version": "2.0.3", "bundled": true, "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "append-transform": "^1.0.0" } }, - "object-visit": { - "version": "1.0.1", + "istanbul-lib-report": { + "version": "2.0.4", "bundled": true, "dev": true, "requires": { - "isobject": "^3.0.0" + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "supports-color": "^6.0.0" }, "dependencies": { - "isobject": { - "version": "3.0.1", + "supports-color": { + "version": "6.1.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "object.pick": { - "version": "1.3.0", + "istanbul-lib-source-maps": { + "version": "3.0.2", "bundled": true, "dev": true, "requires": { - "isobject": "^3.0.1" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" }, "dependencies": { - "isobject": { - "version": "3.0.1", + "source-map": { + "version": "0.6.1", "bundled": true, "dev": true } } }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", + "istanbul-reports": { + "version": "2.1.1", "bundled": true, "dev": true, "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "handlebars": "^4.1.0" } }, - "os-homedir": { + "json-parse-better-errors": { "version": "1.0.2", "bundled": true, "dev": true }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { + "lcid": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "p-limit": "^1.1.0" + "invert-kv": "^2.0.0" } }, - "p-try": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pascalcase": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "2.1.0", + "load-json-file": { + "version": "4.0.0", "bundled": true, "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "path-type": { - "version": "1.1.0", + "locate-path": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, - "pify": { - "version": "2.3.0", + "lodash": { + "version": "4.17.11", "bundled": true, "dev": true }, - "pinkie": { - "version": "2.0.4", + "lodash.flattendeep": { + "version": "4.4.0", "bundled": true, "dev": true }, - "pinkie-promise": { - "version": "2.0.1", + "lru-cache": { + "version": "4.1.5", "bundled": true, "dev": true, "requires": { - "pinkie": "^2.0.0" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "pkg-dir": { - "version": "1.0.0", + "make-dir": { + "version": "1.3.0", "bundled": true, "dev": true, "requires": { - "find-up": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } + "pify": "^3.0.0" } - }, - "posix-character-classes": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "pseudomap": { - "version": "1.0.2", + }, + "map-age-cleaner": { + "version": "0.1.3", "bundled": true, - "dev": true + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } }, - "read-pkg": { - "version": "1.1.0", + "mem": { + "version": "4.1.0", "bundled": true, "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" } }, - "read-pkg-up": { - "version": "1.0.1", + "merge-source-map": { + "version": "1.1.0", "bundled": true, "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "source-map": "^0.6.1" }, "dependencies": { - "find-up": { - "version": "1.1.2", + "source-map": { + "version": "0.6.1", "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } + "dev": true } } }, - "regenerator-runtime": { - "version": "0.11.1", + "mimic-fn": { + "version": "1.2.0", "bundled": true, "dev": true }, - "regex-not": { - "version": "1.0.2", + "minimatch": { + "version": "3.0.4", "bundled": true, "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "brace-expansion": "^1.1.7" } }, - "repeat-element": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "repeat-string": { - "version": "1.6.1", + "minimist": { + "version": "0.0.10", "bundled": true, "dev": true }, - "repeating": { - "version": "2.0.1", + "mkdirp": { + "version": "0.5.1", "bundled": true, "dev": true, "requires": { - "is-finite": "^1.0.0" + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + } } }, - "require-directory": { + "ms": { "version": "2.1.1", "bundled": true, "dev": true }, - "require-main-filename": { - "version": "1.0.1", + "nice-try": { + "version": "1.0.5", "bundled": true, "dev": true }, - "resolve-from": { - "version": "2.0.0", + "normalize-package-data": { + "version": "2.5.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } }, - "resolve-url": { - "version": "0.2.1", + "npm-run-path": { + "version": "2.0.2", "bundled": true, - "dev": true + "dev": true, + "requires": { + "path-key": "^2.0.0" + } }, - "ret": { - "version": "0.1.15", + "number-is-nan": { + "version": "1.0.1", "bundled": true, "dev": true }, - "right-align": { - "version": "0.1.3", + "once": { + "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "align-text": "^0.1.1" + "wrappy": "1" } }, - "rimraf": { - "version": "2.6.2", + "optimist": { + "version": "0.6.1", "bundled": true, "dev": true, "requires": { - "glob": "^7.0.5" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, - "safe-regex": { - "version": "1.1.0", + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "3.1.0", "bundled": true, "dev": true, "requires": { - "ret": "~0.1.10" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, - "semver": { - "version": "5.5.0", + "p-defer": { + "version": "1.0.0", "bundled": true, "dev": true }, - "set-blocking": { - "version": "2.0.0", + "p-finally": { + "version": "1.0.0", "bundled": true, "dev": true }, - "set-value": { + "p-is-promise": { "version": "2.0.0", "bundled": true, + "dev": true + }, + "p-limit": { + "version": "2.1.0", + "bundled": true, "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "p-try": "^2.0.0" } }, - "shebang-command": { - "version": "1.2.0", + "p-locate": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "p-limit": "^2.0.0" } }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", + "p-try": { + "version": "2.0.0", "bundled": true, "dev": true }, - "snapdragon": { - "version": "0.8.2", + "package-hash": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" } }, - "snapdragon-node": { - "version": "2.1.1", + "parse-json": { + "version": "4.0.0", "bundled": true, "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, - "snapdragon-util": { - "version": "3.0.1", + "path-exists": { + "version": "3.0.0", "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } + "dev": true }, - "source-map": { - "version": "0.5.7", + "path-is-absolute": { + "version": "1.0.1", "bundled": true, "dev": true }, - "source-map-resolve": { - "version": "0.5.1", + "path-key": { + "version": "2.0.1", "bundled": true, - "dev": true, - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } + "dev": true }, - "source-map-url": { - "version": "0.4.0", + "path-parse": { + "version": "1.0.6", "bundled": true, "dev": true }, - "spawn-wrap": { - "version": "1.4.2", + "path-type": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" + "pify": "^3.0.0" } }, - "spdx-correct": { + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "pkg-dir": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "find-up": "^3.0.0" } }, - "spdx-exceptions": { - "version": "2.1.0", + "pseudomap": { + "version": "1.0.2", "bundled": true, "dev": true }, - "spdx-expression-parse": { + "pump": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "spdx-license-ids": { + "read-pkg": { "version": "3.0.0", "bundled": true, - "dev": true - }, - "split-string": { - "version": "3.1.0", - "bundled": true, "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" } }, - "static-extend": { - "version": "0.1.2", + "read-pkg-up": { + "version": "4.0.0", "bundled": true, "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" } }, - "string-width": { - "version": "2.1.1", + "release-zalgo": { + "version": "1.0.0", "bundled": true, "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "es6-error": "^4.0.1" } }, - "strip-ansi": { - "version": "3.0.1", + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve": { + "version": "1.10.0", "bundled": true, "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "path-parse": "^1.0.6" } }, - "strip-bom": { - "version": "2.0.0", + "resolve-from": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "2.6.3", "bundled": true, "dev": true, "requires": { - "is-utf8": "^0.2.0" + "glob": "^7.1.3" } }, - "strip-eof": { - "version": "1.0.0", + "safe-buffer": { + "version": "5.1.2", "bundled": true, "dev": true }, - "supports-color": { + "semver": { + "version": "5.6.0", + "bundled": true, + "dev": true + }, + "set-blocking": { "version": "2.0.0", "bundled": true, "dev": true }, - "test-exclude": { - "version": "4.2.1", + "shebang-command": { + "version": "1.2.0", "bundled": true, "dev": true, "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "braces": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "shebang-regex": "^1.0.0" } }, - "to-fast-properties": { - "version": "1.0.3", + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", "bundled": true, "dev": true }, - "to-object-path": { - "version": "0.3.0", + "spawn-wrap": { + "version": "1.4.2", "bundled": true, "dev": true, "requires": { - "kind-of": "^3.0.2" + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" } }, - "to-regex": { - "version": "3.0.2", + "spdx-correct": { + "version": "3.1.0", "bundled": true, "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "to-regex-range": { - "version": "2.1.1", + "spdx-exceptions": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "trim-right": { - "version": "1.0.1", + "spdx-license-ids": { + "version": "3.0.3", "bundled": true, "dev": true }, - "uglify-js": { - "version": "2.8.29", + "string-width": { + "version": "2.1.1", "bundled": true, "dev": true, - "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "uglify-to-browserify": { - "version": "1.0.2", + "strip-ansi": { + "version": "4.0.0", "bundled": true, "dev": true, - "optional": true + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true, + "dev": true }, - "union-value": { + "strip-eof": { "version": "1.0.0", "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "5.1.0", + "bundled": true, "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" } }, - "unset-value": { - "version": "1.0.0", + "uglify-js": { + "version": "3.4.9", "bundled": true, "dev": true, + "optional": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "commander": "~2.17.1", + "source-map": "~0.6.1" }, "dependencies": { - "has-value": { - "version": "0.3.1", + "source-map": { + "version": "0.6.1", "bundled": true, "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true + "optional": true } } }, - "urix": { - "version": "0.1.0", + "uuid": { + "version": "3.3.2", "bundled": true, "dev": true }, - "use": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, "validate-npm-package-license": { - "version": "3.0.3", + "version": "3.0.4", "bundled": true, "dev": true, "requires": { @@ -3043,7 +1655,7 @@ } }, "which": { - "version": "1.3.0", + "version": "1.3.1", "bundled": true, "dev": true, "requires": { @@ -3055,12 +1667,6 @@ "bundled": true, "dev": true }, - "window-size": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "optional": true - }, "wordwrap": { "version": "0.0.3", "bundled": true, @@ -3075,6 +1681,11 @@ "strip-ansi": "^3.0.1" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, @@ -3092,6 +1703,14 @@ "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } } } }, @@ -3101,17 +1720,17 @@ "dev": true }, "write-file-atomic": { - "version": "1.3.4", + "version": "2.4.2", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "slide": "^1.1.5" + "signal-exit": "^3.0.2" } }, "y18n": { - "version": "3.2.1", + "version": "4.0.0", "bundled": true, "dev": true }, @@ -3121,75 +1740,31 @@ "dev": true }, "yargs": { - "version": "11.1.0", + "version": "12.0.5", "bundled": true, "dev": true, "requires": { "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "cliui": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "yargs-parser": { - "version": "9.0.2", - "bundled": true, - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" } }, "yargs-parser": { - "version": "8.1.0", + "version": "11.1.1", "bundled": true, "dev": true, "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - } + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } @@ -3299,6 +1874,12 @@ "safe-buffer": "^5.0.1" } }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3341,6 +1922,18 @@ "nan": "^2.10.0" } }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", diff --git a/package.json b/package.json index e62819a..4ec4077 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "dependencies": { "@types/node": "10.12.18", "bech32": "^1.1.2", - "bip32": "git+https://github.com/junderw/bip32.git#typeScript", + "bip32": "^2.0.0", "bip66": "^1.1.0", "bitcoin-ops": "^1.4.0", "bs58check": "^2.0.0", @@ -67,7 +67,7 @@ "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", - "nyc": "^11.8.0", + "nyc": "^13.3.0", "prettier": "1.16.4", "proxyquire": "^2.0.1", "tslint": "5.13.1", From 74375bfedf702cccadc426c086d53e9334110ec9 Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 20 Mar 2019 15:25:48 +0900 Subject: [PATCH 151/183] Fix class constructors --- src/block.js | 56 +++++++++++----------- src/ecpair.js | 12 ++--- src/transaction_builder.js | 19 ++++---- ts_src/block.ts | 87 +++++++++++++++------------------- ts_src/ecpair.ts | 13 +++-- ts_src/transaction.ts | 15 ++---- ts_src/transaction_builder.ts | 14 +++--- types/block.d.ts | 1 - types/ecpair.d.ts | 6 +-- types/transaction.d.ts | 1 - types/transaction_builder.d.ts | 2 +- 11 files changed, 101 insertions(+), 125 deletions(-) diff --git a/src/block.js b/src/block.js index 913ad9a..da17193 100644 --- a/src/block.js +++ b/src/block.js @@ -9,25 +9,17 @@ const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); -function txesHaveWitnessCommit(transactions) { - return (transactions instanceof Array && - transactions[0] && - transactions[0].ins && - transactions[0].ins instanceof Array && - transactions[0].ins[0] && - transactions[0].ins[0].witness && - transactions[0].ins[0].witness instanceof Array && - transactions[0].ins[0].witness.length > 0); -} -function anyTxHasWitness(transactions) { - return (transactions instanceof Array && - transactions.some(tx => typeof tx === 'object' && - tx.ins instanceof Array && - tx.ins.some(input => typeof input === 'object' && - input.witness instanceof Array && - input.witness.length > 0))); -} class Block { + constructor() { + this.version = 1; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.timestamp = 0; + this.witnessCommit = undefined; + this.bits = 0; + this.nonce = 0; + this.transactions = undefined; + } static fromBuffer(buffer) { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); @@ -99,16 +91,6 @@ class Block { ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) : rootHash; } - constructor() { - this.version = 1; - this.timestamp = 0; - this.bits = 0; - this.nonce = 0; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.witnessCommit = undefined; - this.transactions = undefined; - } getWitnessCommit() { if (!txesHaveWitnessCommit(this.transactions)) return null; @@ -220,3 +202,21 @@ class Block { } } exports.Block = Block; +function txesHaveWitnessCommit(transactions) { + return (transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0); +} +function anyTxHasWitness(transactions) { + return (transactions instanceof Array && + transactions.some(tx => typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some(input => typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0))); +} diff --git a/src/ecpair.js b/src/ecpair.js index 1335014..2026c63 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -11,18 +11,16 @@ const isOptions = typeforce.maybe(typeforce.compile({ network: types.maybe(types.Network), })); class ECPair { - constructor(d, Q, options) { + constructor(__D, __Q, options) { + this.__D = __D; + this.__Q = __Q; if (options === undefined) options = {}; this.compressed = options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.bitcoin; - this.__D = undefined; - this.__Q = undefined; - if (d !== undefined) - this.__D = d; - if (Q !== undefined) - this.__Q = ecc.pointCompress(Q, this.compressed); + if (__Q !== undefined) + this.__Q = ecc.pointCompress(__Q, this.compressed); } get privateKey() { return this.__D; diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 0b876a7..d3b2673 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -20,6 +20,16 @@ function txIsTransaction(tx) { return tx instanceof transaction_1.Transaction; } class TransactionBuilder { + // WARNING: maximumFeeRate is __NOT__ to be relied on, + // it's just another potential safety mechanism (safety in-depth) + constructor(network = networks.bitcoin, maximumFeeRate = 2500) { + this.network = network; + this.maximumFeeRate = maximumFeeRate; + this.__PREV_TX_SET = {}; + this.__INPUTS = []; + this.__TX = new transaction_1.Transaction(); + this.__TX.version = 2; + } static fromTransaction(transaction, network) { const txb = new TransactionBuilder(network); // Copy transaction fields @@ -43,15 +53,6 @@ class TransactionBuilder { }); return txb; } - constructor(network, maximumFeeRate) { - this.__PREV_TX_SET = {}; - this.network = network || networks.bitcoin; - // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500; - this.__INPUTS = []; - this.__TX = new transaction_1.Transaction(); - this.__TX.version = 2; - } setLockTime(locktime) { typeforce(types.UInt32, locktime); // if any signatures exist, throw diff --git a/ts_src/block.ts b/ts_src/block.ts index 9a9bd45..820c075 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -14,36 +14,6 @@ const errorWitnessNotSegwit = new TypeError( 'Cannot compute witness commit for non-segwit block', ); -function txesHaveWitnessCommit(transactions: Transaction[]): boolean { - return ( - transactions instanceof Array && - transactions[0] && - transactions[0].ins && - transactions[0].ins instanceof Array && - transactions[0].ins[0] && - transactions[0].ins[0].witness && - transactions[0].ins[0].witness instanceof Array && - transactions[0].ins[0].witness.length > 0 - ); -} - -function anyTxHasWitness(transactions: Transaction[]): boolean { - return ( - transactions instanceof Array && - transactions.some( - tx => - typeof tx === 'object' && - tx.ins instanceof Array && - tx.ins.some( - input => - typeof input === 'object' && - input.witness instanceof Array && - input.witness.length > 0, - ), - ) - ); -} - export class Block { static fromBuffer(buffer: Buffer): Block { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); @@ -137,25 +107,14 @@ export class Block { : rootHash; } - version: number; - prevHash?: Buffer; - merkleRoot?: Buffer; - timestamp: number; - witnessCommit?: Buffer; - bits: number; - nonce: number; - transactions?: Transaction[]; - - constructor() { - this.version = 1; - this.timestamp = 0; - this.bits = 0; - this.nonce = 0; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.witnessCommit = undefined; - this.transactions = undefined; - } + version: number = 1; + prevHash?: Buffer = undefined; + merkleRoot?: Buffer = undefined; + timestamp: number = 0; + witnessCommit?: Buffer = undefined; + bits: number = 0; + nonce: number = 0; + transactions?: Transaction[] = undefined; getWitnessCommit(): Buffer | null { if (!txesHaveWitnessCommit(this.transactions!)) return null; @@ -294,3 +253,33 @@ export class Block { return this.witnessCommit!.compare(actualWitnessCommit) === 0; } } + +function txesHaveWitnessCommit(transactions: Transaction[]): boolean { + return ( + transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0 + ); +} + +function anyTxHasWitness(transactions: Transaction[]): boolean { + return ( + transactions instanceof Array && + transactions.some( + tx => + typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some( + input => + typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0, + ), + ) + ); +} diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index ec8dc13..9e56919 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -33,19 +33,18 @@ export interface ECPairInterface { class ECPair implements ECPairInterface { compressed: boolean; network: Network; - private __D?: Buffer; - private __Q?: Buffer; - constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions) { + constructor( + private __D?: Buffer, + private __Q?: Buffer, + options?: ECPairOptions, + ) { if (options === undefined) options = {}; this.compressed = options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.bitcoin; - this.__D = undefined; - this.__Q = undefined; - if (d !== undefined) this.__D = d; - if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed); + if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); } get privateKey(): Buffer | undefined { diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 995f1d7..b788d91 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -182,17 +182,10 @@ export class Transaction { return true; } - version: number; - locktime: number; - ins: Input[]; - outs: OpenOutput[]; - - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; - } + version: number = 1; + locktime: number = 0; + ins: Input[] = []; + outs: OpenOutput[] = []; isCoinbase(): boolean { return ( diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 4c939e1..575fbc2 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -91,19 +91,17 @@ export class TransactionBuilder { return txb; } - network: Network; - maximumFeeRate: number; private __PREV_TX_SET: { [index: string]: boolean }; private __INPUTS: TxbInput[]; private __TX: Transaction; - constructor(network?: Network, maximumFeeRate?: number) { + // WARNING: maximumFeeRate is __NOT__ to be relied on, + // it's just another potential safety mechanism (safety in-depth) + constructor( + public network: Network = networks.bitcoin, + public maximumFeeRate: number = 2500, + ) { this.__PREV_TX_SET = {}; - this.network = network || networks.bitcoin; - - // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) - this.maximumFeeRate = maximumFeeRate || 2500; - this.__INPUTS = []; this.__TX = new Transaction(); this.__TX.version = 2; diff --git a/types/block.d.ts b/types/block.d.ts index 6b6596c..dd4fc55 100644 --- a/types/block.d.ts +++ b/types/block.d.ts @@ -13,7 +13,6 @@ export declare class Block { bits: number; nonce: number; transactions?: Transaction[]; - constructor(); getWitnessCommit(): Buffer | null; hasWitnessCommit(): boolean; hasWitness(): boolean; diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index 674615b..33535bd 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -16,11 +16,11 @@ export interface ECPairInterface { getPublicKey?(): Buffer; } declare class ECPair implements ECPairInterface { - compressed: boolean; - network: Network; private __D?; private __Q?; - constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions); + compressed: boolean; + network: Network; + constructor(__D?: Buffer | undefined, __Q?: Buffer | undefined, options?: ECPairOptions); readonly privateKey: Buffer | undefined; readonly publicKey: Buffer | undefined; toWIF(): string; diff --git a/types/transaction.d.ts b/types/transaction.d.ts index 4f8a2b9..9bdba19 100644 --- a/types/transaction.d.ts +++ b/types/transaction.d.ts @@ -30,7 +30,6 @@ export declare class Transaction { locktime: number; ins: Input[]; outs: OpenOutput[]; - constructor(); isCoinbase(): boolean; addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; addOutput(scriptPubKey: Buffer, value: number): number; diff --git a/types/transaction_builder.d.ts b/types/transaction_builder.d.ts index b3dedb3..16adee6 100644 --- a/types/transaction_builder.d.ts +++ b/types/transaction_builder.d.ts @@ -3,9 +3,9 @@ import { ECPairInterface } from './ecpair'; import { Network } from './networks'; import { Transaction } from './transaction'; export declare class TransactionBuilder { - static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; network: Network; maximumFeeRate: number; + static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; private __PREV_TX_SET; private __INPUTS; private __TX; From 0cdd7b1e2c478f4403d3dcd0acaa821433a57b6b Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Fri, 22 Mar 2019 00:15:37 +0900 Subject: [PATCH 152/183] ci: add a tslint rule to require type definitions --- ts_src/payments/lazy.ts | 4 ++-- ts_src/payments/p2ms.ts | 2 +- ts_src/script.ts | 2 +- ts_src/templates/multisig/input.ts | 2 +- ts_src/templates/multisig/output.ts | 2 +- ts_src/templates/nulldata.ts | 2 +- ts_src/templates/pubkey/input.ts | 2 +- ts_src/templates/pubkey/output.ts | 2 +- ts_src/templates/pubkeyhash/input.ts | 2 +- ts_src/templates/pubkeyhash/output.ts | 2 +- ts_src/templates/scripthash/input.ts | 2 +- ts_src/templates/scripthash/output.ts | 2 +- ts_src/templates/witnesscommitment/output.ts | 2 +- ts_src/templates/witnesspubkeyhash/input.ts | 2 +- ts_src/templates/witnesspubkeyhash/output.ts | 2 +- ts_src/templates/witnessscripthash/input.ts | 2 +- ts_src/templates/witnessscripthash/output.ts | 2 +- ts_src/transaction.ts | 20 ++++++++++---------- ts_src/transaction_builder.ts | 2 +- ts_src/types.ts | 2 +- tslint.json | 6 ++++++ 21 files changed, 36 insertions(+), 30 deletions(-) diff --git a/ts_src/payments/lazy.ts b/ts_src/payments/lazy.ts index fe0fb6d..1df181f 100644 --- a/ts_src/payments/lazy.ts +++ b/ts_src/payments/lazy.ts @@ -2,12 +2,12 @@ export function prop(object: {}, name: string, f: () => any): void { Object.defineProperty(object, name, { configurable: true, enumerable: true, - get() { + get(): any { const _value = f.call(this); this[name] = _value; return _value; }, - set(_value) { + set(_value: any): void { Object.defineProperty(this, name, { configurable: true, enumerable: true, diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index b8691c0..bac8b83 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -28,7 +28,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - function isAcceptableSignature(x: Buffer | number) { + function isAcceptableSignature(x: Buffer | number): boolean { return ( bscript.isCanonicalScriptSignature(x as Buffer) || (opts!.allowIncomplete && (x as number) === OPS.OP_0) !== undefined diff --git a/ts_src/script.ts b/ts_src/script.ts index 1c705d3..951f48b 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -26,7 +26,7 @@ function isPushOnlyChunk(value: number | Buffer): boolean { return types.Buffer(value) || isOPInt(value as number); } -export function isPushOnly(value: Stack) { +export function isPushOnly(value: Stack): boolean { return types.Array(value) && value.every(isPushOnlyChunk); } diff --git a/ts_src/templates/multisig/input.ts b/ts_src/templates/multisig/input.ts index 57b73d2..31fe416 100644 --- a/ts_src/templates/multisig/input.ts +++ b/ts_src/templates/multisig/input.ts @@ -26,6 +26,6 @@ export function check( bscript.isCanonicalScriptSignature, ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'multisig input'; }; diff --git a/ts_src/templates/multisig/output.ts b/ts_src/templates/multisig/output.ts index 3ee0820..20c2162 100644 --- a/ts_src/templates/multisig/output.ts +++ b/ts_src/templates/multisig/output.ts @@ -28,6 +28,6 @@ export function check( const keys = chunks.slice(1, -2) as Buffer[]; return keys.every(bscript.isCanonicalPubKey); } -check.toJSON = () => { +check.toJSON = (): string => { return 'multi-sig output'; }; diff --git a/ts_src/templates/nulldata.ts b/ts_src/templates/nulldata.ts index bafe4a4..99b5c44 100644 --- a/ts_src/templates/nulldata.ts +++ b/ts_src/templates/nulldata.ts @@ -7,7 +7,7 @@ export function check(script: Buffer | Array): boolean { return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } -check.toJSON = () => { +check.toJSON = (): string => { return 'null data output'; }; diff --git a/ts_src/templates/pubkey/input.ts b/ts_src/templates/pubkey/input.ts index 7e07a94..745e6d9 100644 --- a/ts_src/templates/pubkey/input.ts +++ b/ts_src/templates/pubkey/input.ts @@ -11,6 +11,6 @@ export function check(script: Buffer | Stack): boolean { bscript.isCanonicalScriptSignature(chunks[0] as Buffer) ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'pubKey input'; }; diff --git a/ts_src/templates/pubkey/output.ts b/ts_src/templates/pubkey/output.ts index d57422d..1b2c391 100644 --- a/ts_src/templates/pubkey/output.ts +++ b/ts_src/templates/pubkey/output.ts @@ -13,6 +13,6 @@ export function check(script: Buffer | Stack): boolean { chunks[1] === OPS.OP_CHECKSIG ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'pubKey output'; }; diff --git a/ts_src/templates/pubkeyhash/input.ts b/ts_src/templates/pubkeyhash/input.ts index 83da475..de93968 100644 --- a/ts_src/templates/pubkeyhash/input.ts +++ b/ts_src/templates/pubkeyhash/input.ts @@ -12,6 +12,6 @@ export function check(script: Buffer | Stack): boolean { bscript.isCanonicalPubKey(chunks[1] as Buffer) ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'pubKeyHash input'; }; diff --git a/ts_src/templates/pubkeyhash/output.ts b/ts_src/templates/pubkeyhash/output.ts index 37070a3..248c210 100644 --- a/ts_src/templates/pubkeyhash/output.ts +++ b/ts_src/templates/pubkeyhash/output.ts @@ -15,6 +15,6 @@ export function check(script: Buffer | Array): boolean { buffer[24] === OPS.OP_CHECKSIG ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'pubKeyHash output'; }; diff --git a/ts_src/templates/scripthash/input.ts b/ts_src/templates/scripthash/input.ts index 1e3f97d..3ef8aab 100644 --- a/ts_src/templates/scripthash/input.ts +++ b/ts_src/templates/scripthash/input.ts @@ -56,6 +56,6 @@ export function check( return false; } -check.toJSON = () => { +check.toJSON = (): string => { return 'scriptHash input'; }; diff --git a/ts_src/templates/scripthash/output.ts b/ts_src/templates/scripthash/output.ts index 7eac30d..aea8e24 100644 --- a/ts_src/templates/scripthash/output.ts +++ b/ts_src/templates/scripthash/output.ts @@ -13,6 +13,6 @@ export function check(script: Buffer | Array): boolean { buffer[22] === OPS.OP_EQUAL ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'scriptHash output'; }; diff --git a/ts_src/templates/witnesscommitment/output.ts b/ts_src/templates/witnesscommitment/output.ts index 9439e4c..482798f 100644 --- a/ts_src/templates/witnesscommitment/output.ts +++ b/ts_src/templates/witnesscommitment/output.ts @@ -19,7 +19,7 @@ export function check(script: Buffer | Array): boolean { ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'Witness commitment output'; }; diff --git a/ts_src/templates/witnesspubkeyhash/input.ts b/ts_src/templates/witnesspubkeyhash/input.ts index aa3bef8..26fe63d 100644 --- a/ts_src/templates/witnesspubkeyhash/input.ts +++ b/ts_src/templates/witnesspubkeyhash/input.ts @@ -16,6 +16,6 @@ export function check(script: Buffer | Stack): boolean { isCompressedCanonicalPubKey(chunks[1] as Buffer) ); } -check.toJSON = () => { +check.toJSON = (): string => { return 'witnessPubKeyHash input'; }; diff --git a/ts_src/templates/witnesspubkeyhash/output.ts b/ts_src/templates/witnesspubkeyhash/output.ts index 0e9432c..bfd6690 100644 --- a/ts_src/templates/witnesspubkeyhash/output.ts +++ b/ts_src/templates/witnesspubkeyhash/output.ts @@ -8,6 +8,6 @@ export function check(script: Buffer | Array): boolean { return buffer.length === 22 && buffer[0] === OPS.OP_0 && buffer[1] === 0x14; } -check.toJSON = () => { +check.toJSON = (): string => { return 'Witness pubKeyHash output'; }; diff --git a/ts_src/templates/witnessscripthash/input.ts b/ts_src/templates/witnessscripthash/input.ts index 42a13ac..0f63330 100644 --- a/ts_src/templates/witnessscripthash/input.ts +++ b/ts_src/templates/witnessscripthash/input.ts @@ -42,6 +42,6 @@ export function check(chunks: Buffer[], allowIncomplete?: boolean): boolean { return false; } -check.toJSON = () => { +check.toJSON = (): string => { return 'witnessScriptHash input'; }; diff --git a/ts_src/templates/witnessscripthash/output.ts b/ts_src/templates/witnessscripthash/output.ts index 85034d1..7d4f33a 100644 --- a/ts_src/templates/witnessscripthash/output.ts +++ b/ts_src/templates/witnessscripthash/output.ts @@ -8,6 +8,6 @@ export function check(script: Buffer | Array): boolean { return buffer.length === 34 && buffer[0] === OPS.OP_0 && buffer[1] === 0x20; } -check.toJSON = () => { +check.toJSON = (): string => { return 'Witness scriptHash output'; }; diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index b788d91..218d004 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -497,17 +497,17 @@ export class Transaction { return this.__toBuffer(buffer, initialOffset, true); } - toHex() { + toHex(): string { return this.toBuffer(undefined, undefined).toString('hex'); } - setInputScript(index: number, scriptSig: Buffer) { + setInputScript(index: number, scriptSig: Buffer): void { typeforce(types.tuple(types.Number, types.Buffer), arguments); this.ins[index].script = scriptSig; } - setWitness(index: number, witness: Buffer[]) { + setWitness(index: number, witness: Buffer[]): void { typeforce(types.tuple(types.Number, [types.Buffer]), arguments); this.ins[index].witness = witness; @@ -548,33 +548,33 @@ export class Transaction { offset += slice.copy(buffer!, offset); } - function writeUInt8(i: number) { + function writeUInt8(i: number): void { offset = buffer!.writeUInt8(i, offset); } - function writeUInt32(i: number) { + function writeUInt32(i: number): void { offset = buffer!.writeUInt32LE(i, offset); } - function writeInt32(i: number) { + function writeInt32(i: number): void { offset = buffer!.writeInt32LE(i, offset); } - function writeUInt64(i: number) { + function writeUInt64(i: number): void { offset = bufferutils.writeUInt64LE(buffer!, i, offset); } - function writeVarInt(i: number) { + function writeVarInt(i: number): void { varuint.encode(i, buffer, offset); offset += varuint.encode.bytes; } - function writeVarSlice(slice: Buffer) { + function writeVarSlice(slice: Buffer): void { writeVarInt(slice.length); writeSlice(slice); } - function writeVector(vector: Buffer[]) { + function writeVector(vector: Buffer[]): void { writeVarInt(vector.length); vector.forEach(writeVarSlice); } diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 575fbc2..2367250 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -192,7 +192,7 @@ export class TransactionBuilder { hashType: number, witnessValue: number, witnessScript: Buffer, - ) { + ): void { // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network'); diff --git a/ts_src/types.ts b/ts_src/types.ts index 033e62a..06c247d 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -8,7 +8,7 @@ export function UInt31(value: number): boolean { export function BIP32Path(value: string): boolean { return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } -BIP32Path.toJSON = () => { +BIP32Path.toJSON = (): string => { return 'BIP32 derivation path'; }; diff --git a/tslint.json b/tslint.json index 9708e8b..1ba998d 100644 --- a/tslint.json +++ b/tslint.json @@ -22,6 +22,12 @@ "no-unused-expression": false, "object-literal-sort-keys": false, "quotemark": [true, "single"], + "typedef": [ + true, + "call-signature", + "arrow-call-signature", + "property-declaration" + ], "variable-name": [ true, "ban-keywords", From 2d5307f06f4d72234779455d400b52276d37e8dc Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 22 Mar 2019 12:33:33 +0900 Subject: [PATCH 153/183] Add tslint to travis --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 90088bb..dde4713 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,14 @@ sudo: false language: node_js node_js: + - "8" - "lts/*" - - "9" - - "10" matrix: include: - node_js: "lts/*" env: TEST_SUITE=format:ci + - node_js: "lts/*" + env: TEST_SUITE=lint - node_js: "lts/*" env: TEST_SUITE=coverage env: From d4dc26fb339e311e7f37bbeb6f7e3a0f81ea070c Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 1 Apr 2019 16:22:47 +0900 Subject: [PATCH 154/183] Prevent JS/TS diff in Travis --- .travis.yml | 2 ++ package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index dde4713..5c1cfd3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ matrix: include: - node_js: "lts/*" env: TEST_SUITE=format:ci + - node_js: "lts/*" + env: TEST_SUITE=gitdiff:ci - node_js: "lts/*" env: TEST_SUITE=lint - node_js: "lts/*" diff --git a/package.json b/package.json index 4ec4077..491a24a 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "coverage": "npm run build && npm run nobuild:coverage", "format": "npm run prettier -- --write", "format:ci": "npm run prettier -- --check", + "gitdiff:ci": "npm run build && git diff --exit-code", "integration": "npm run build && npm run nobuild:integration", "lint": "tslint -p tsconfig.json -c tslint.json", "nobuild:coverage-report": "nyc report --reporter=lcov", From 335ed99a1cfae5029948e9f7bd20be8502c74319 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 2 Apr 2019 18:57:07 +0900 Subject: [PATCH 155/183] Fix error for lack of rmd160 in Electron v4 --- src/crypto.js | 13 ++++++++++--- ts_src/crypto.ts | 12 +++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/crypto.js b/src/crypto.js index d494b86..38ec4f9 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -2,9 +2,16 @@ Object.defineProperty(exports, "__esModule", { value: true }); const createHash = require('create-hash'); function ripemd160(buffer) { - return createHash('rmd160') - .update(buffer) - .digest(); + try { + return createHash('rmd160') + .update(buffer) + .digest(); + } + catch (err) { + return createHash('ripemd160') + .update(buffer) + .digest(); + } } exports.ripemd160 = ripemd160; function sha1(buffer) { diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts index 6d92e60..1cb5a69 100644 --- a/ts_src/crypto.ts +++ b/ts_src/crypto.ts @@ -1,9 +1,15 @@ const createHash = require('create-hash'); export function ripemd160(buffer: Buffer): Buffer { - return createHash('rmd160') - .update(buffer) - .digest(); + try { + return createHash('rmd160') + .update(buffer) + .digest(); + } catch (err) { + return createHash('ripemd160') + .update(buffer) + .digest(); + } } export function sha1(buffer: Buffer): Buffer { From af7c308465768550f725cf414dba92c11141d9e0 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 5 Apr 2019 18:15:35 +0900 Subject: [PATCH 156/183] Update README and CHANGELOG for v5 (typescript) --- CHANGELOG.md | 12 ++++++++++++ README.md | 20 +++----------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f31645b..25c9b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 5.0.0 +__added__ +- TypeScript support (#1319) +- `Block.prototype.checkTxRoots` will check the merkleRoot and witnessCommit if it exists against the transactions array. (e52abec) (0426c66) + +__changed__ +- `Transaction.prototype.getHash` now has `forWitness?: boolean` which when true returns the hash for wtxid (a652d04) +- `Block.calculateMerkleRoot` now has `forWitness?: boolean` which when true returns the witness commit (a652d04) + +__removed__ +- `Block.prototype.checkMerkleRoot` was removed, please use `checkTxRoots` (0426c66) + # 4.0.3 __fixed__ - Fixed `TransactionBuilder` to require that the Transaction has outputs before signing (#1151) diff --git a/README.md b/README.md index 458693f..27b336c 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) [![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) -[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) +[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) -A javascript Bitcoin library for node.js and browsers. +A javascript Bitcoin library for node.js and browsers. Written in TypeScript, but committing the JS files to verify. Released under the terms of the [MIT LICENSE](LICENSE). @@ -23,7 +23,7 @@ Mistakes and bugs happen, but with your help in resolving and reporting [issues] - Easy to audit and verify, - Tested, with test coverage >95%, - Advanced and feature rich, -- Standardized, using [standard](https://github.com/standard/standard) and Node `Buffer`'s throughout, and +- Standardized, using [prettier](https://github.com/prettier/prettier) and Node `Buffer`'s throughout, and - Friendly, with a strong and helpful community, ready to answer questions. @@ -80,20 +80,6 @@ If you're familiar with how to use browserify, ignore this and carry on, otherwi ### Typescript or VSCode users Type declarations for Typescript are included in this library. Normal installation should include all the needed type information. - -### Flow -[Flow-type](https://flowtype.org/) definitions for are available in the [flow-*typed* repository](https://github.com/flowtype/flow-typed/tree/master/definitions/npm/bitcoinjs-lib_v2.x.x) for version `^2.0.0` of the library. - -You can [download them directly](https://github.com/flowtype/flow-typed/blob/master/definitions/npm/bitcoinjs-lib_v2.x.x/flow_v0.17.x-/bitcoinjs-lib_v2.x.x.js), or using the flow-typed CLI: - -``` bash -npm install -g flow-typed -flow-typed install -f 0.27 bitcoinjs-lib@2.2.0 -``` - -**WARNING**: These flow-typed definitions are not maintained by the maintainers of this repository. - - ## Examples The below examples are implemented as integration tests, they should be very easy to understand. Otherwise, pull requests are appreciated. From 8a65e85915fcb8ee7dfc7b95018e59d7e69ca179 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 5 Apr 2019 18:17:39 +0900 Subject: [PATCH 157/183] 5.0.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3b11623..e56b8d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "4.0.3", + "version": "5.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 491a24a..69d704f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "4.0.3", + "version": "5.0.0", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "types": "./types/index.d.ts", From fcde97769e138b3d2d0c288825e014939adf84de Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 6 Apr 2019 14:34:14 +0900 Subject: [PATCH 158/183] Amend CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c9b3c..cd856e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ __changed__ __removed__ - `Block.prototype.checkMerkleRoot` was removed, please use `checkTxRoots` (0426c66) +# 4.0.5 +__fixed__ +- Fixed bug where Angular apps break due to lack of crypto at build time. Reverted #1373 and added (6bead5d). + +# 4.0.4 +__fixed__ +- Fixed bug where Electron v4 breaks due to lack of `'rmd160'` alias for ripemd160 hash. (#1373) + # 4.0.3 __fixed__ - Fixed `TransactionBuilder` to require that the Transaction has outputs before signing (#1151) From 8ec1911a269a5a3839fd51b45dec38b2df43b38f Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 7 Apr 2019 22:27:16 +0900 Subject: [PATCH 159/183] Fix tests Missing Input --- test/integration/_regtest.js | 119 +++++++------ test/integration/addresses.js | 19 +-- test/integration/bip32.js | 18 +- test/integration/cltv.js | 280 ++++++++++++++----------------- test/integration/csv.js | 158 ++++++++--------- test/integration/payments.js | 44 +++-- test/integration/transactions.js | 248 ++++++++++++--------------- 7 files changed, 412 insertions(+), 474 deletions(-) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index f392a8a..650a79c 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -1,99 +1,109 @@ const assert = require('assert') const bitcoin = require('../../') -const dhttp = require('dhttp/200') +const dhttpCallback = require('dhttp/200') +// use Promises +const dhttp = options => new Promise((resolve, reject) => { + return dhttpCallback(options, (err, data) => { + if (err) return reject(err) + else return resolve(data) + }) +}) const APIPASS = process.env.APIPASS || 'satoshi' const APIURL = 'https://regtest.bitbank.cc/1' const NETWORK = bitcoin.networks.testnet -function broadcast (txHex, callback) { - dhttp({ +function broadcast (txHex) { + return dhttp({ method: 'POST', url: APIURL + '/t/push', body: txHex - }, callback) + }) } -function mine (count, callback) { - dhttp({ +function mine (count) { + return dhttp({ method: 'POST', url: APIURL + '/r/generate?count=' + count + '&key=' + APIPASS - }, callback) + }) } -function height (callback) { - dhttp({ +function height () { + return dhttp({ method: 'GET', url: APIURL + '/b/best/height' - }, callback) + }) } -function faucet (address, value, callback) { - dhttp({ - method: 'POST', - url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS - }, function (err, txId) { - if (err) return callback(err) +async function faucet (address, value) { + let count = 0 + let _unspents = [] + const sleep = ms => new Promise(r => setTimeout(r, ms)) + do { + if (count > 0) { + if (count >= 5) throw new Error('Missing Inputs') + console.log('Missing Inputs, retry #' + count) + await sleep(200) + } + + const txId = await dhttp({ + method: 'POST', + url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS + }) - unspents(address, function (err, results) { - if (err) return callback(err) + await sleep(100) - const unspents = results.filter(x => x.txId === txId) - if (unspents.length === 0) return callback(new Error('Missing unspent')) + const results = await unspents(address) - callback(null, unspents.pop()) - }) - }) + _unspents = results.filter(x => x.txId === txId) + + count++ + } while (_unspents.length === 0) + + return _unspents.pop() } -function faucetComplex (output, value, callback) { +async function faucetComplex (output, value) { const keyPair = bitcoin.ECPair.makeRandom({ network: NETWORK }) const p2pkh = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: NETWORK }) - faucet(p2pkh.address, value * 2, (err, unspent) => { - if (err) return callback(err) + const unspent = await faucet(p2pkh.address, value * 2) - const txvb = new bitcoin.TransactionBuilder(NETWORK) - txvb.addInput(unspent.txId, unspent.vout, null, p2pkh.output) - txvb.addOutput(output, value) - txvb.sign(0, keyPair) - const txv = txvb.build() + const txvb = new bitcoin.TransactionBuilder(NETWORK) + txvb.addInput(unspent.txId, unspent.vout, null, p2pkh.output) + txvb.addOutput(output, value) + txvb.sign(0, keyPair) + const txv = txvb.build() - broadcast(txv.toHex(), function (err) { - if (err) return callback(err) + await broadcast(txv.toHex()) - return callback(null, { - txId: txv.getId(), - vout: 0, - value - }) - }) - }) + return { + txId: txv.getId(), + vout: 0, + value + } } -function fetch (txId, callback) { - dhttp({ +function fetch (txId) { + return dhttp({ method: 'GET', url: APIURL + '/t/' + txId + '/json' - }, callback) + }) } -function unspents (address, callback) { - dhttp({ +function unspents (address) { + return dhttp({ method: 'GET', url: APIURL + '/a/' + address + '/unspents' - }, callback) + }) } -function verify (txo, callback) { - fetch(txo.txId, function (err, tx) { - if (err) return callback(err) +async function verify (txo) { + const tx = await fetch(txo.txId) - const txoActual = tx.outs[txo.vout] - if (txo.address) assert.strictEqual(txoActual.address, txo.address) - if (txo.value) assert.strictEqual(txoActual.value, txo.value) - callback() - }) + const txoActual = tx.outs[txo.vout] + if (txo.address) assert.strictEqual(txoActual.address, txo.address) + if (txo.value) assert.strictEqual(txoActual.value, txo.value) } function getAddress (node, network) { @@ -108,6 +118,7 @@ function randomAddress () { module.exports = { broadcast, + dhttp, faucet, faucetComplex, fetch, diff --git a/test/integration/addresses.js b/test/integration/addresses.js index 7cf2612..f37dbc7 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -1,29 +1,26 @@ const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') -const dhttp = require('dhttp/200') +const dhttp = require('./_regtest').dhttp const TESTNET = bitcoin.networks.testnet describe('bitcoinjs-lib (addresses)', function () { - it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', function (done) { + it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', async function () { const keyPair = bitcoin.ECPair.makeRandom() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) // bitcoin P2PKH addresses start with a '1' assert.strictEqual(address.startsWith('1'), true) - dhttp({ + const result = await dhttp({ method: 'GET', url: 'https://blockchain.info/rawaddr/' + address - }, function (err, result) { - if (err) return done(err) - - // random private keys [probably!] have no transactions - assert.strictEqual(result.n_tx, 0) - assert.strictEqual(result.total_received, 0) - assert.strictEqual(result.total_sent, 0) - done() }) + + // random private keys [probably!] have no transactions + assert.strictEqual(result.n_tx, 0) + assert.strictEqual(result.total_received, 0) + assert.strictEqual(result.total_sent, 0) }) it('can import an address via WIF', function () { diff --git a/test/integration/bip32.js b/test/integration/bip32.js index 27a2da4..5f948fa 100644 --- a/test/integration/bip32.js +++ b/test/integration/bip32.js @@ -13,7 +13,7 @@ describe('bitcoinjs-lib (BIP32)', function () { const xpriv = 'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK' const node = bip32.fromBase58(xpriv, bitcoin.networks.testnet) - assert.equal(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7') + assert.strictEqual(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7') }) it('can export a BIP32 xpriv, then import it', function () { @@ -23,8 +23,8 @@ describe('bitcoinjs-lib (BIP32)', function () { const string = node.toBase58() const restored = bip32.fromBase58(string) - assert.equal(getAddress(node), getAddress(restored)) // same public key - assert.equal(node.toWIF(), restored.toWIF()) // same private key + assert.strictEqual(getAddress(node), getAddress(restored)) // same public key + assert.strictEqual(node.toWIF(), restored.toWIF()) // same private key }) it('can export a BIP32 xpub', function () { @@ -33,7 +33,7 @@ describe('bitcoinjs-lib (BIP32)', function () { const node = bip32.fromSeed(seed) const string = node.neutered().toBase58() - assert.equal(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n') + assert.strictEqual(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n') }) it('can create a BIP32, bitcoin, account 0, external address', function () { @@ -47,8 +47,8 @@ describe('bitcoinjs-lib (BIP32)', function () { .derive(0) .derive(0) - assert.equal(getAddress(child1), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7') - assert.equal(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7') + assert.strictEqual(getAddress(child1), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7') + assert.strictEqual(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7') }) it('can create a BIP44, bitcoin, account 0, external address', function () { @@ -63,8 +63,8 @@ describe('bitcoinjs-lib (BIP32)', function () { .derive(0) .derive(0) - assert.equal(getAddress(child1), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au') - assert.equal(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au') + assert.strictEqual(getAddress(child1), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au') + assert.strictEqual(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au') }) it('can create a BIP49, bitcoin testnet, account 0, external address', function () { @@ -79,7 +79,7 @@ describe('bitcoinjs-lib (BIP32)', function () { redeem: bitcoin.payments.p2wpkh({ pubkey: child.publicKey, network: bitcoin.networks.testnet }), network: bitcoin.networks.testnet }) - assert.equal(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2') + assert.strictEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2') }) it('can use BIP39 to generate BIP32 addresses', function () { diff --git a/test/integration/cltv.js b/test/integration/cltv.js index 8bf1c4a..66afb94 100644 --- a/test/integration/cltv.js +++ b/test/integration/cltv.js @@ -10,8 +10,8 @@ const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZs describe('bitcoinjs-lib (transactions w/ CLTV)', function () { // force update MTP - before(function (done) { - regtestUtils.mine(11, done) + before(async function () { + await regtestUtils.mine(11) }) const hashType = bitcoin.Transaction.SIGHASH_ALL @@ -38,188 +38,160 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { } // expiry past, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', function (done) { + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', async function () { // 3 hours ago const lockTime = bip65.encode({ utc: utcNow() - (3600 * 3) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest }) // fund the P2SH(CLTV) address - regtestUtils.faucet(address, 1e5, function (err, unspent) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.setLockTime(lockTime) - // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. - txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) - - // {Alice's signature} OP_TRUE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, redeemScript, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ - redeem: { - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.opcodes.OP_TRUE - ]), - output: redeemScript - } - }).input - tx.setInputScript(0, redeemScriptSig) - - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 7e4 - }, done) - }) + const unspent = await regtestUtils.faucet(address, 1e5) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. + txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) + + // {Alice's signature} OP_TRUE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, redeemScript, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + redeem: { + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.opcodes.OP_TRUE + ]), + output: redeemScript + } + }).input + tx.setInputScript(0, redeemScriptSig) + + await regtestUtils.broadcast(tx.toHex()) + + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 7e4 }) }) // expiry will pass, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', function (done) { - regtestUtils.height(function (err, height) { - if (err) return done(err) - - // 5 blocks from now - const lockTime = bip65.encode({ blocks: height + 5 }) - const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) - const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest }) - - // fund the P2SH(CLTV) address - regtestUtils.faucet(address, 1e5, function (err, unspent) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.setLockTime(lockTime) - // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. - txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) - - // {Alice's signature} OP_TRUE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, redeemScript, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ - redeem: { - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.opcodes.OP_TRUE - ]), - output: redeemScript - } - }).input - tx.setInputScript(0, redeemScriptSig) - - // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently - // ... - // into the future! - regtestUtils.mine(5, function (err) { - if (err) return done(err) - - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 7e4 - }, done) - }) - }) - }) + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async function () { + const height = await regtestUtils.height() + // 5 blocks from now + const lockTime = bip65.encode({ blocks: height + 5 }) + const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) + const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest }) + + // fund the P2SH(CLTV) address + const unspent = await regtestUtils.faucet(address, 1e5) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. + txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) + + // {Alice's signature} OP_TRUE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, redeemScript, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + redeem: { + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.opcodes.OP_TRUE + ]), + output: redeemScript + } + }).input + tx.setInputScript(0, redeemScriptSig) + + // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently + // ... + // into the future! + await regtestUtils.mine(5) + await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 7e4 }) }) // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE - it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', function (done) { + it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', async function () { // two hours ago const lockTime = bip65.encode({ utc: utcNow() - (3600 * 2) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest }) // fund the P2SH(CLTV) address - regtestUtils.faucet(address, 2e5, function (err, unspent) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.setLockTime(lockTime) - // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. - txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4) - - // {Alice's signature} {Bob's signature} OP_FALSE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, redeemScript, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ - redeem: { - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), - bitcoin.opcodes.OP_FALSE - ]), - output: redeemScript - } - }).input - tx.setInputScript(0, redeemScriptSig) - - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 8e4 - }, done) - }) + const unspent = await regtestUtils.faucet(address, 2e5) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. + txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4) + + // {Alice's signature} {Bob's signature} OP_FALSE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, redeemScript, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + redeem: { + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), + bitcoin.opcodes.OP_FALSE + ]), + output: redeemScript + } + }).input + tx.setInputScript(0, redeemScriptSig) + + await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 8e4 }) }) // expiry in the future, {Alice's signature} OP_TRUE - it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', function (done) { + it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async function () { // two hours from now const lockTime = bip65.encode({ utc: utcNow() + (3600 * 2) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) const { address } = bitcoin.payments.p2sh({ redeem: { output: redeemScript, network: regtest }, network: regtest }) // fund the P2SH(CLTV) address - regtestUtils.faucet(address, 2e4, function (err, unspent) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.setLockTime(lockTime) - // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. - txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) - - // {Alice's signature} OP_TRUE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, redeemScript, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ - redeem: { - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), - bitcoin.opcodes.OP_TRUE - ]), - output: redeemScript - } - }).input - tx.setInputScript(0, redeemScriptSig) - - regtestUtils.broadcast(tx.toHex(), function (err) { - assert.throws(function () { - if (err) throw err - }, /Error: non-final \(code 64\)/) - - done() - }) + const unspent = await regtestUtils.faucet(address, 2e4) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.setLockTime(lockTime) + // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable. + txb.addInput(unspent.txId, unspent.vout, 0xfffffffe) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) + + // {Alice's signature} OP_TRUE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, redeemScript, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + redeem: { + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), + bitcoin.opcodes.OP_TRUE + ]), + output: redeemScript + } + }).input + tx.setInputScript(0, redeemScriptSig) + + await regtestUtils.broadcast(tx.toHex()).catch(err => { + assert.throws(function () { + if (err) throw err + }, /Error: non-final \(code 64\)/) }) }) }) diff --git a/test/integration/csv.js b/test/integration/csv.js index 5996634..1ad8c90 100644 --- a/test/integration/csv.js +++ b/test/integration/csv.js @@ -10,8 +10,8 @@ const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZs describe('bitcoinjs-lib (transactions w/ CSV)', function () { // force update MTP - before(function (done) { - regtestUtils.mine(11, done) + before(async function () { + await regtestUtils.mine(11) }) const hashType = bitcoin.Transaction.SIGHASH_ALL @@ -35,66 +35,56 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { } // expiry will pass, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', function (done) { - regtestUtils.height(function (err, height) { - if (err) return done(err) - - // 5 blocks from now - const sequence = bip68.encode({ blocks: 5 }) - const p2sh = bitcoin.payments.p2sh({ - redeem: { - output: csvCheckSigOutput(alice, bob, sequence) - }, - network: regtest - }) - - // fund the P2SH(CSV) address - regtestUtils.faucet(p2sh.address, 1e5, function (err, unspent) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout, sequence) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) - - // {Alice's signature} OP_TRUE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ - network: regtest, - redeem: { - network: regtest, - output: p2sh.redeem.output, - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.opcodes.OP_TRUE - ]) - } - }).input - tx.setInputScript(0, redeemScriptSig) - - // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently - // ... - // into the future! - regtestUtils.mine(10, function (err) { - if (err) return done(err) - - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 7e4 - }, done) - }) - }) - }) + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async function () { + // 5 blocks from now + const sequence = bip68.encode({ blocks: 5 }) + const p2sh = bitcoin.payments.p2sh({ + redeem: { + output: csvCheckSigOutput(alice, bob, sequence) + }, + network: regtest + }) + + // fund the P2SH(CSV) address + const unspent = await regtestUtils.faucet(p2sh.address, 1e5) + + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout, sequence) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4) + + // {Alice's signature} OP_TRUE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + network: regtest, + redeem: { + network: regtest, + output: p2sh.redeem.output, + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.opcodes.OP_TRUE + ]) + } + }).input + tx.setInputScript(0, redeemScriptSig) + + // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently + // ... + // into the future! + await regtestUtils.mine(10) + + await regtestUtils.broadcast(tx.toHex()) + + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 7e4 }) }) // expiry in the future, {Alice's signature} OP_TRUE - it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', function (done) { + it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async function () { // two hours after confirmation const sequence = bip68.encode({ seconds: 7168 }) const p2sh = bitcoin.payments.p2sh({ @@ -105,37 +95,33 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { }) // fund the P2SH(CSV) address - regtestUtils.faucet(p2sh.address, 2e4, function (err, unspent) { - if (err) return done(err) + const unspent = await regtestUtils.faucet(p2sh.address, 2e4) - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout, sequence) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout, sequence) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) - // {Alice's signature} OP_TRUE - const tx = txb.buildIncomplete() - const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType) - const redeemScriptSig = bitcoin.payments.p2sh({ + // {Alice's signature} OP_TRUE + const tx = txb.buildIncomplete() + const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType) + const redeemScriptSig = bitcoin.payments.p2sh({ + network: regtest, + redeem: { network: regtest, - redeem: { - network: regtest, - output: p2sh.redeem.output, - input: bitcoin.script.compile([ - bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), - bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), - bitcoin.opcodes.OP_TRUE - ]) - } - }).input - tx.setInputScript(0, redeemScriptSig) - - regtestUtils.broadcast(tx.toHex(), function (err) { - assert.throws(function () { - if (err) throw err - }, /Error: non-BIP68-final \(code 64\)/) - - done() - }) + output: p2sh.redeem.output, + input: bitcoin.script.compile([ + bitcoin.script.signature.encode(alice.sign(signatureHash), hashType), + bitcoin.script.signature.encode(bob.sign(signatureHash), hashType), + bitcoin.opcodes.OP_TRUE + ]) + } + }).input + tx.setInputScript(0, redeemScriptSig) + + await regtestUtils.broadcast(tx.toHex()).catch(err => { + assert.throws(function () { + if (err) throw err + }, /Error: non-BIP68-final \(code 64\)/) }) }) }) diff --git a/test/integration/payments.js b/test/integration/payments.js index a8fb84e..2fcdbda 100644 --- a/test/integration/payments.js +++ b/test/integration/payments.js @@ -8,24 +8,22 @@ const keyPairs = [ bitcoin.ECPair.makeRandom({ network: NETWORK }) ] -function buildAndSign (depends, prevOutput, redeemScript, witnessScript, done) { - regtestUtils.faucetComplex(prevOutput, 5e4, (err, unspent) => { - if (err) return done(err) +async function buildAndSign (depends, prevOutput, redeemScript, witnessScript) { + const unspent = await regtestUtils.faucetComplex(prevOutput, 5e4) - const txb = new bitcoin.TransactionBuilder(NETWORK) - txb.addInput(unspent.txId, unspent.vout, null, prevOutput) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) + const txb = new bitcoin.TransactionBuilder(NETWORK) + txb.addInput(unspent.txId, unspent.vout, null, prevOutput) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) - if (depends.signatures) { - keyPairs.forEach((keyPair) => { - txb.sign(0, keyPair, redeemScript, null, unspent.value, witnessScript) - }) - } else if (depends.signature) { - txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, witnessScript) - } + if (depends.signatures) { + keyPairs.forEach((keyPair) => { + txb.sign(0, keyPair, redeemScript, null, unspent.value, witnessScript) + }) + } else if (depends.signature) { + txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, witnessScript) + } - regtestUtils.broadcast(txb.build().toHex(), done) - }) + return regtestUtils.broadcast(txb.build().toHex()) } ;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach((k) => { @@ -42,28 +40,28 @@ function buildAndSign (depends, prevOutput, redeemScript, witnessScript, done) { if (!output) throw new TypeError('Missing output') describe('bitcoinjs-lib (payments - ' + k + ')', function () { - it('can broadcast as an output, and be spent as an input', (done) => { - buildAndSign(depends, output, null, null, done) + it('can broadcast as an output, and be spent as an input', async () => { + await buildAndSign(depends, output, null, null) }) - it('can (as P2SH(' + k + ')) broadcast as an output, and be spent as an input', (done) => { + it('can (as P2SH(' + k + ')) broadcast as an output, and be spent as an input', async () => { const p2sh = bitcoin.payments.p2sh({ redeem: { output }, network: NETWORK }) - buildAndSign(depends, p2sh.output, p2sh.redeem.output, null, done) + await buildAndSign(depends, p2sh.output, p2sh.redeem.output, null) }) // NOTE: P2WPKH cannot be wrapped in P2WSH, consensus fail if (k === 'p2wpkh') return - it('can (as P2WSH(' + k + ')) broadcast as an output, and be spent as an input', (done) => { + it('can (as P2WSH(' + k + ')) broadcast as an output, and be spent as an input', async () => { const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK }) - buildAndSign(depends, p2wsh.output, null, p2wsh.redeem.output, done) + await buildAndSign(depends, p2wsh.output, null, p2wsh.redeem.output) }) - it('can (as P2SH(P2WSH(' + k + '))) broadcast as an output, and be spent as an input', (done) => { + it('can (as P2SH(P2WSH(' + k + '))) broadcast as an output, and be spent as an input', async () => { const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK }) const p2sh = bitcoin.payments.p2sh({ redeem: { output: p2wsh.output }, network: NETWORK }) - buildAndSign(depends, p2sh.output, p2sh.redeem.output, p2wsh.redeem.output, done) + await buildAndSign(depends, p2sh.output, p2sh.redeem.output, p2wsh.redeem.output) }) }) }) diff --git a/test/integration/transactions.js b/test/integration/transactions.js index f725241..a3836a7 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -43,7 +43,7 @@ describe('bitcoinjs-lib (transactions)', function () { assert.strictEqual(txb.build().toHex(), '01000000024c94e48a870b85f41228d33cf25213dfcc8dd796e7211ed6b1f9a014809dbbb5060000006a473044022041450c258ce7cac7da97316bf2ea1ce66d88967c4df94f3e91f4c2a30f5d08cb02203674d516e6bb2b0afd084c3551614bd9cec3c2945231245e891b145f2d6951f0012103e05ce435e462ec503143305feb6c00e06a3ad52fbf939e85c65f3a765bb7baacffffffff3077d9de049574c3af9bc9c09a7c9db80f2d94caaf63988c9166249b955e867d000000006b483045022100aeb5f1332c79c446d3f906e4499b2e678500580a3f90329edf1ba502eec9402e022072c8b863f8c8d6c26f4c691ac9a6610aa4200edc697306648ee844cfbc089d7a012103df7940ee7cddd2f97763f67e1fb13488da3fbdd7f9c68ec5ef0864074745a289ffffffff0220bf0200000000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac10980200000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000') }) - it('can create (and broadcast via 3PBP) a typical Transaction', function (done) { + it('can create (and broadcast via 3PBP) a typical Transaction', async () => { const alice1 = bitcoin.ECPair.makeRandom({ network: regtest }) const alice2 = bitcoin.ECPair.makeRandom({ network: regtest }) const aliceChange = bitcoin.ECPair.makeRandom({ network: regtest, rng: rng }) @@ -53,51 +53,45 @@ describe('bitcoinjs-lib (transactions)', function () { const aliceCpkh = bitcoin.payments.p2pkh({ pubkey: aliceChange.publicKey, network: regtest }) // give Alice 2 unspent outputs - regtestUtils.faucet(alice1pkh.address, 5e4, function (err, unspent0) { - if (err) return done(err) - - regtestUtils.faucet(alice2pkh.address, 7e4, function (err, unspent1) { - if (err) return done(err) - - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent0.txId, unspent0.vout) // alice1 unspent - txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent - txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend" - txb.addOutput(aliceCpkh.address, 1e4) // Alice's change - // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee - - // Alice signs each input with the respective private keys - txb.sign(0, alice1) - txb.sign(1, alice2) - - // build and broadcast our RegTest network - regtestUtils.broadcast(txb.build().toHex(), done) - // to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839 - }) - }) + const unspent0 = await regtestUtils.faucet(alice1pkh.address, 5e4) + + const unspent1 = await regtestUtils.faucet(alice2pkh.address, 7e4) + + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent0.txId, unspent0.vout) // alice1 unspent + txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent + txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend" + txb.addOutput(aliceCpkh.address, 1e4) // Alice's change + // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee + + // Alice signs each input with the respective private keys + txb.sign(0, alice1) + txb.sign(1, alice2) + + // build and broadcast our RegTest network + await regtestUtils.broadcast(txb.build().toHex()) + // to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839 }) - it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', function (done) { + it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', async () => { const keyPair = bitcoin.ECPair.makeRandom({ network: regtest }) const p2pkh = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: regtest }) - regtestUtils.faucet(p2pkh.address, 2e5, function (err, unspent) { - if (err) return done(err) + const unspent = await regtestUtils.faucet(p2pkh.address, 2e5) - const txb = new bitcoin.TransactionBuilder(regtest) - const data = Buffer.from('bitcoinjs-lib', 'utf8') - const embed = bitcoin.payments.embed({ data: [data] }) - txb.addInput(unspent.txId, unspent.vout) - txb.addOutput(embed.output, 1000) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5) - txb.sign(0, keyPair) + const txb = new bitcoin.TransactionBuilder(regtest) + const data = Buffer.from('bitcoinjs-lib', 'utf8') + const embed = bitcoin.payments.embed({ data: [data] }) + txb.addInput(unspent.txId, unspent.vout) + txb.addOutput(embed.output, 1000) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5) + txb.sign(0, keyPair) - // build and broadcast to the RegTest network - regtestUtils.broadcast(txb.build().toHex(), done) - }) + // build and broadcast to the RegTest network + await regtestUtils.broadcast(txb.build().toHex()) }) - it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', function (done) { + it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', async () => { const keyPairs = [ bitcoin.ECPair.makeRandom({ network: regtest }), bitcoin.ECPair.makeRandom({ network: regtest }), @@ -108,118 +102,102 @@ describe('bitcoinjs-lib (transactions)', function () { const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: pubkeys, network: regtest }) const p2sh = bitcoin.payments.p2sh({ redeem: p2ms, network: regtest }) - regtestUtils.faucet(p2sh.address, 2e4, function (err, unspent) { - if (err) return done(err) + const unspent = await regtestUtils.faucet(p2sh.address, 2e4) - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4) - txb.sign(0, keyPairs[0], p2sh.redeem.output) - txb.sign(0, keyPairs[2], p2sh.redeem.output) - const tx = txb.build() + txb.sign(0, keyPairs[0], p2sh.redeem.output) + txb.sign(0, keyPairs[2], p2sh.redeem.output) + const tx = txb.build() - // build and broadcast to the Bitcoin RegTest network - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) + // build and broadcast to the Bitcoin RegTest network + await regtestUtils.broadcast(tx.toHex()) - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 1e4 - }, done) - }) + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 1e4 }) }) - it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', function (done) { + it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', async () => { const keyPair = bitcoin.ECPair.makeRandom({ network: regtest }) const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest }) const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: regtest }) - regtestUtils.faucet(p2sh.address, 5e4, function (err, unspent) { - if (err) return done(err) + const unspent = await regtestUtils.faucet(p2sh.address, 5e4) - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) - txb.sign(0, keyPair, p2sh.redeem.output, null, unspent.value) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) + txb.sign(0, keyPair, p2sh.redeem.output, null, unspent.value) - const tx = txb.build() + const tx = txb.build() - // build and broadcast to the Bitcoin RegTest network - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) + // build and broadcast to the Bitcoin RegTest network + await regtestUtils.broadcast(tx.toHex()) - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 2e4 - }, done) - }) + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 2e4 }) }) - it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', function (done) { + it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', async () => { const keyPair = bitcoin.ECPair.makeRandom({ network: regtest }) const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: regtest }) - regtestUtils.faucetComplex(p2wpkh.address, 5e4, function (err, unspent) { - if (err) return done(err) - - // XXX: build the Transaction w/ a P2WPKH input - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout, null, p2wpkh.output) // NOTE: provide the prevOutScript! - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) - txb.sign(0, keyPair, null, null, unspent.value) // NOTE: no redeem script - const tx = txb.build() - - // build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 2e4 - }, done) - }) + const unspent = await regtestUtils.faucetComplex(p2wpkh.address, 5e4) + + // XXX: build the Transaction w/ a P2WPKH input + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout, null, p2wpkh.output) // NOTE: provide the prevOutScript! + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) + txb.sign(0, keyPair, null, null, unspent.value) // NOTE: no redeem script + const tx = txb.build() + + // build and broadcast (the P2WPKH transaction) to the Bitcoin RegTest network + await regtestUtils.broadcast(tx.toHex()) + + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 2e4 }) }) - it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', function (done) { + it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', async () => { const keyPair = bitcoin.ECPair.makeRandom({ network: regtest }) const p2pk = bitcoin.payments.p2pk({ pubkey: keyPair.publicKey, network: regtest }) const p2wsh = bitcoin.payments.p2wsh({ redeem: p2pk, network: regtest }) - regtestUtils.faucetComplex(p2wsh.address, 5e4, function (err, unspent) { - if (err) return done(err) - - // XXX: build the Transaction w/ a P2WSH input - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout, null, p2wsh.output) // NOTE: provide the prevOutScript! - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) - txb.sign(0, keyPair, null, null, 5e4, p2wsh.redeem.output) // NOTE: provide a witnessScript! - const tx = txb.build() - - // build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) - - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 2e4 - }, done) - }) + const unspent = await regtestUtils.faucetComplex(p2wsh.address, 5e4) + + // XXX: build the Transaction w/ a P2WSH input + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout, null, p2wsh.output) // NOTE: provide the prevOutScript! + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) + txb.sign(0, keyPair, null, null, 5e4, p2wsh.redeem.output) // NOTE: provide a witnessScript! + const tx = txb.build() + + // build and broadcast (the P2WSH transaction) to the Bitcoin RegTest network + await regtestUtils.broadcast(tx.toHex()) + + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 2e4 }) }) - it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input', function (done) { + it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input', async () => { const keyPairs = [ bitcoin.ECPair.makeRandom({ network: regtest }), bitcoin.ECPair.makeRandom({ network: regtest }), @@ -232,29 +210,25 @@ describe('bitcoinjs-lib (transactions)', function () { const p2wsh = bitcoin.payments.p2wsh({ redeem: p2ms, network: regtest }) const p2sh = bitcoin.payments.p2sh({ redeem: p2wsh, network: regtest }) - regtestUtils.faucet(p2sh.address, 6e4, function (err, unspent) { - if (err) return done(err) + const unspent = await regtestUtils.faucet(p2sh.address, 6e4) - const txb = new bitcoin.TransactionBuilder(regtest) - txb.addInput(unspent.txId, unspent.vout, null, p2sh.output) - txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4) - txb.sign(0, keyPairs[0], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) - txb.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) - txb.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) + const txb = new bitcoin.TransactionBuilder(regtest) + txb.addInput(unspent.txId, unspent.vout, null, p2sh.output) + txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4) + txb.sign(0, keyPairs[0], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) + txb.sign(0, keyPairs[2], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) + txb.sign(0, keyPairs[3], p2sh.redeem.output, null, unspent.value, p2wsh.redeem.output) - const tx = txb.build() + const tx = txb.build() - // build and broadcast to the Bitcoin RegTest network - regtestUtils.broadcast(tx.toHex(), function (err) { - if (err) return done(err) + // build and broadcast to the Bitcoin RegTest network + await regtestUtils.broadcast(tx.toHex()) - regtestUtils.verify({ - txId: tx.getId(), - address: regtestUtils.RANDOM_ADDRESS, - vout: 0, - value: 3e4 - }, done) - }) + await regtestUtils.verify({ + txId: tx.getId(), + address: regtestUtils.RANDOM_ADDRESS, + vout: 0, + value: 3e4 }) }) From 77bd66c22ffd19944db561e6cb9cbcc756e0e668 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 8 Apr 2019 15:24:19 +0900 Subject: [PATCH 160/183] Fix Bad Request errors from the client side --- test/integration/_regtest.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index 650a79c..81821c1 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -35,10 +35,17 @@ function height () { }) } +function _faucetRequest (address, value) { + return dhttp({ + method: 'POST', + url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS + }) +} + async function faucet (address, value) { let count = 0 let _unspents = [] - const sleep = ms => new Promise(r => setTimeout(r, ms)) + const sleep = ms => new Promise((resolve, reject) => setTimeout(resolve, ms)) do { if (count > 0) { if (count >= 5) throw new Error('Missing Inputs') @@ -46,10 +53,20 @@ async function faucet (address, value) { await sleep(200) } - const txId = await dhttp({ - method: 'POST', - url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS - }) + const txId = await _faucetRequest(address, value) + .then( + v => v, // Pass success value as is + async err => { + // Bad Request error is fixed by making sure height is >= 432 + const currentHeight = await height() + if (err.message === 'Bad Request' && currentHeight < 432) { + await mine(432 - currentHeight) + return _faucetRequest(address, value) + } else { + throw err + } + } + ) await sleep(100) From b27df612daaf2365d9d4fb3f5bd7fb6c5b0f9f80 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 8 Apr 2019 15:34:12 +0900 Subject: [PATCH 161/183] Randomize sleep times --- test/integration/_regtest.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index 81821c1..d2a3c7d 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -46,11 +46,12 @@ async function faucet (address, value) { let count = 0 let _unspents = [] const sleep = ms => new Promise((resolve, reject) => setTimeout(resolve, ms)) + const randInt = (min, max) => min + Math.floor((max - min + 1) * Math.random()) do { if (count > 0) { if (count >= 5) throw new Error('Missing Inputs') console.log('Missing Inputs, retry #' + count) - await sleep(200) + await sleep(randInt(150, 250)) } const txId = await _faucetRequest(address, value) @@ -68,7 +69,7 @@ async function faucet (address, value) { } ) - await sleep(100) + await sleep(randInt(50, 150)) const results = await unspents(address) From d9fd6d619a58378e0bb6536928068602d33d5450 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 8 Apr 2019 16:40:38 +0900 Subject: [PATCH 162/183] Fix race condition for two integration test jobs --- test/integration/_regtest.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index d2a3c7d..0ea6736 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -63,6 +63,8 @@ async function faucet (address, value) { if (err.message === 'Bad Request' && currentHeight < 432) { await mine(432 - currentHeight) return _faucetRequest(address, value) + } else if (err.message === 'Bad Request' && currentHeight >= 432) { + return _faucetRequest(address, value) } else { throw err } From d951423a352178fa8f1c8bb6898da783b9b75a28 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 8 Apr 2019 18:15:25 +0900 Subject: [PATCH 163/183] Fix TransactionBuilder types --- ts_src/transaction_builder.ts | 18 +++++++++--------- types/transaction_builder.d.ts | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 2367250..6a49b3f 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -134,8 +134,8 @@ export class TransactionBuilder { addInput( txHash: Buffer | string | Transaction, vout: number, - sequence: number, - prevOutScript: Buffer, + sequence?: number, + prevOutScript?: Buffer, ): number { if (!this.__canModifyInputs()) { throw new Error('No, this would invalidate signatures'); @@ -188,10 +188,10 @@ export class TransactionBuilder { sign( vin: number, keyPair: ECPairInterface, - redeemScript: Buffer, - hashType: number, - witnessValue: number, - witnessScript: Buffer, + redeemScript?: Buffer, + hashType?: number, + witnessValue?: number, + witnessScript?: Buffer, ): void { // TODO: remove keyPair.network matching in 4.0.0 if (keyPair.network && keyPair.network !== this.network) @@ -267,7 +267,7 @@ export class TransactionBuilder { } const signature = keyPair.sign(signatureHash); - input.signatures![i] = bscript.signature.encode(signature, hashType); + input.signatures![i] = bscript.signature.encode(signature, hashType!); return true; }); @@ -679,8 +679,8 @@ function expandOutput(script: Buffer, ourPubKey?: Buffer): TxbOutput { function prepareInput( input: TxbInput, ourPubKey: Buffer, - redeemScript: Buffer, - witnessScript: Buffer, + redeemScript?: Buffer, + witnessScript?: Buffer, ): TxbInput { if (redeemScript && witnessScript) { const p2wsh = payments.p2wsh({ diff --git a/types/transaction_builder.d.ts b/types/transaction_builder.d.ts index 16adee6..82c4ef0 100644 --- a/types/transaction_builder.d.ts +++ b/types/transaction_builder.d.ts @@ -12,11 +12,11 @@ export declare class TransactionBuilder { constructor(network?: Network, maximumFeeRate?: number); setLockTime(locktime: number): void; setVersion(version: number): void; - addInput(txHash: Buffer | string | Transaction, vout: number, sequence: number, prevOutScript: Buffer): number; + addInput(txHash: Buffer | string | Transaction, vout: number, sequence?: number, prevOutScript?: Buffer): number; addOutput(scriptPubKey: string | Buffer, value: number): number; build(): Transaction; buildIncomplete(): Transaction; - sign(vin: number, keyPair: ECPairInterface, redeemScript: Buffer, hashType: number, witnessValue: number, witnessScript: Buffer): void; + sign(vin: number, keyPair: ECPairInterface, redeemScript?: Buffer, hashType?: number, witnessValue?: number, witnessScript?: Buffer): void; private __addInputUnsafe; private __build; private __canModifyInputs; From 2381b6643f1466518e36a2e16757f656c87968d3 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 8 Apr 2019 18:17:04 +0900 Subject: [PATCH 164/183] 5.0.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e56b8d2..b57448e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.0", + "version": "5.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 69d704f..10088cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.0", + "version": "5.0.1", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "types": "./types/index.d.ts", From 16823e90131b7668575be9ada467a83a908b05e6 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 9 Apr 2019 12:09:43 +0900 Subject: [PATCH 165/183] Add APIURL env for endpoint --- test/integration/_regtest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index 0ea6736..e32e11b 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -10,7 +10,7 @@ const dhttp = options => new Promise((resolve, reject) => { }) const APIPASS = process.env.APIPASS || 'satoshi' -const APIURL = 'https://regtest.bitbank.cc/1' +const APIURL = process.env.APIURL || 'https://regtest.bitbank.cc/1' const NETWORK = bitcoin.networks.testnet function broadcast (txHex) { From dc1ef5958b7c7115e5c6960d6bccb2704f9c13cd Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 9 Apr 2019 15:09:50 +0900 Subject: [PATCH 166/183] Tests to arrow functions, use strict asserts, travis uses docker instead of regtest server --- .travis.yml | 8 +- test/address.js | 64 +++++----- test/bitcoin.core.js | 78 ++++++------ test/block.js | 84 ++++++------- test/bufferutils.js | 26 ++-- test/classify.js | 42 +++---- test/crypto.js | 10 +- test/ecpair.js | 102 ++++++++-------- test/integration/_regtest.js | 4 +- test/integration/addresses.js | 20 ++-- test/integration/bip32.js | 16 +-- test/integration/blocks.js | 4 +- test/integration/cltv.js | 14 +-- test/integration/csv.js | 10 +- test/integration/payments.js | 6 +- test/integration/transactions.js | 16 +-- test/payments.js | 26 ++-- test/payments.utils.js | 13 +- test/script.js | 70 +++++------ test/script_number.js | 14 +-- test/script_signature.js | 28 ++--- test/transaction.js | 124 +++++++++---------- test/transaction_builder.js | 200 +++++++++++++++---------------- test/types.js | 24 ++-- 24 files changed, 505 insertions(+), 498 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c1cfd3..7921fac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,11 @@ sudo: false language: node_js +services: + - docker +before_install: + - docker pull junderw/bitcoinjs-regtest-server + - docker run -d -p 127.0.0.1:8080:8080 junderw/bitcoinjs-regtest-server + - docker ps -a node_js: - "8" - "lts/*" @@ -15,5 +21,5 @@ matrix: env: TEST_SUITE=coverage env: - TEST_SUITE=unit - - TEST_SUITE=integration + - TEST_SUITE=integration APIURL=http://127.0.0.1:8080/1 script: npm run-script $TEST_SUITE diff --git a/test/address.js b/test/address.js index a0f4df0..be16879 100644 --- a/test/address.js +++ b/test/address.js @@ -16,12 +16,12 @@ const NETWORKS = Object.assign({ } }, require('../src/networks')) -describe('address', function () { - describe('fromBase58Check', function () { - fixtures.standard.forEach(function (f) { +describe('address', () => { + describe('fromBase58Check', () => { + fixtures.standard.forEach(f => { if (!f.base58check) return - it('decodes ' + f.base58check, function () { + it('decodes ' + f.base58check, () => { const decode = baddress.fromBase58Check(f.base58check) assert.strictEqual(decode.version, f.version) @@ -29,20 +29,20 @@ describe('address', function () { }) }) - fixtures.invalid.fromBase58Check.forEach(function (f) { - it('throws on ' + f.exception, function () { - assert.throws(function () { + fixtures.invalid.fromBase58Check.forEach(f => { + it('throws on ' + f.exception, () => { + assert.throws(() => { baddress.fromBase58Check(f.address) }, new RegExp(f.address + ' ' + f.exception)) }) }) }) - describe('fromBech32', function () { - fixtures.standard.forEach((f) => { + describe('fromBech32', () => { + fixtures.standard.forEach(f => { if (!f.bech32) return - it('decodes ' + f.bech32, function () { + it('decodes ' + f.bech32, () => { const actual = baddress.fromBech32(f.bech32) assert.strictEqual(actual.version, f.version) @@ -52,17 +52,17 @@ describe('address', function () { }) fixtures.invalid.bech32.forEach((f, i) => { - it('decode fails for ' + f.bech32 + '(' + f.exception + ')', function () { - assert.throws(function () { + it('decode fails for ' + f.bech32 + '(' + f.exception + ')', () => { + assert.throws(() => { baddress.fromBech32(f.address) }, new RegExp(f.exception)) }) }) }) - describe('fromOutputScript', function () { - fixtures.standard.forEach(function (f) { - it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () { + describe('fromOutputScript', () => { + fixtures.standard.forEach(f => { + it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => { const script = bscript.fromASM(f.script) const address = baddress.fromOutputScript(script, NETWORKS[f.network]) @@ -70,22 +70,22 @@ describe('address', function () { }) }) - fixtures.invalid.fromOutputScript.forEach(function (f) { - it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, function () { + fixtures.invalid.fromOutputScript.forEach(f => { + it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, () => { const script = bscript.fromASM(f.script) - assert.throws(function () { + assert.throws(() => { baddress.fromOutputScript(script) }, new RegExp(f.exception)) }) }) }) - describe('toBase58Check', function () { - fixtures.standard.forEach(function (f) { + describe('toBase58Check', () => { + fixtures.standard.forEach(f => { if (!f.base58check) return - it('encodes ' + f.hash + ' (' + f.network + ')', function () { + it('encodes ' + f.hash + ' (' + f.network + ')', () => { const address = baddress.toBase58Check(Buffer.from(f.hash, 'hex'), f.version) assert.strictEqual(address, f.base58check) @@ -93,39 +93,39 @@ describe('address', function () { }) }) - describe('toBech32', function () { + describe('toBech32', () => { fixtures.bech32.forEach((f, i) => { if (!f.bech32) return const data = Buffer.from(f.data, 'hex') - it('encode ' + f.address, function () { - assert.deepEqual(baddress.toBech32(data, f.version, f.prefix), f.address) + it('encode ' + f.address, () => { + assert.deepStrictEqual(baddress.toBech32(data, f.version, f.prefix), f.address) }) }) fixtures.invalid.bech32.forEach((f, i) => { if (!f.prefix || f.version === undefined || f.data === undefined) return - it('encode fails (' + f.exception, function () { - assert.throws(function () { + it('encode fails (' + f.exception, () => { + assert.throws(() => { baddress.toBech32(Buffer.from(f.data, 'hex'), f.version, f.prefix) }, new RegExp(f.exception)) }) }) }) - describe('toOutputScript', function () { - fixtures.standard.forEach(function (f) { - it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () { + describe('toOutputScript', () => { + fixtures.standard.forEach(f => { + it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => { const script = baddress.toOutputScript(f.base58check || f.bech32, NETWORKS[f.network]) assert.strictEqual(bscript.toASM(script), f.script) }) }) - fixtures.invalid.toOutputScript.forEach(function (f) { - it('throws when ' + f.exception, function () { - assert.throws(function () { + fixtures.invalid.toOutputScript.forEach(f => { + it('throws when ' + f.exception, () => { + assert.throws(() => { baddress.toOutputScript(f.address, f.network) }, new RegExp(f.address + ' ' + f.exception)) }) diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js index 560bf20..734c9a9 100644 --- a/test/bitcoin.core.js +++ b/test/bitcoin.core.js @@ -12,21 +12,21 @@ const sigHash = require('./fixtures/core/sighash.json') const sigNoncanonical = require('./fixtures/core/sig_noncanonical.json') const txValid = require('./fixtures/core/tx_valid.json') -describe('Bitcoin-core', function () { +describe('Bitcoin-core', () => { // base58EncodeDecode - describe('base58', function () { - base58EncodeDecode.forEach(function (f) { + describe('base58', () => { + base58EncodeDecode.forEach(f => { const fhex = f[0] const fb58 = f[1] - it('can decode ' + fb58, function () { + it('can decode ' + fb58, () => { const buffer = base58.decode(fb58) const actual = buffer.toString('hex') assert.strictEqual(actual, fhex) }) - it('can encode ' + fhex, function () { + it('can encode ' + fhex, () => { const buffer = Buffer.from(fhex, 'hex') const actual = base58.encode(buffer) @@ -36,13 +36,13 @@ describe('Bitcoin-core', function () { }) // base58KeysValid - describe('address.toBase58Check', function () { + describe('address.toBase58Check', () => { const typeMap = { 'pubkey': 'pubKeyHash', 'script': 'scriptHash' } - base58KeysValid.forEach(function (f) { + base58KeysValid.forEach(f => { const expected = f[0] const hash = Buffer.from(f[1], 'hex') const params = f[2] @@ -52,14 +52,14 @@ describe('Bitcoin-core', function () { const network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin const version = network[typeMap[params.addrType]] - it('can export ' + expected, function () { + it('can export ' + expected, () => { assert.strictEqual(bitcoin.address.toBase58Check(hash, version), expected) }) }) }) // base58KeysInvalid - describe('address.fromBase58Check', function () { + describe('address.fromBase58Check', () => { const allowedNetworks = [ bitcoin.networks.bitcoin.pubkeyhash, bitcoin.networks.bitcoin.scripthash, @@ -67,22 +67,22 @@ describe('Bitcoin-core', function () { bitcoin.networks.testnet.scripthash ] - base58KeysInvalid.forEach(function (f) { + base58KeysInvalid.forEach(f => { const string = f[0] - it('throws on ' + string, function () { - assert.throws(function () { + it('throws on ' + string, () => { + assert.throws(() => { const address = bitcoin.address.fromBase58Check(string) - assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network') + assert.notStrictEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network') }, /(Invalid (checksum|network))|(too (short|long))/) }) }) }) // base58KeysValid - describe('ECPair', function () { - base58KeysValid.forEach(function (f) { + describe('ECPair', () => { + base58KeysValid.forEach(f => { const string = f[0] const hex = f[1] const params = f[2] @@ -92,38 +92,38 @@ describe('Bitcoin-core', function () { const network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin const keyPair = bitcoin.ECPair.fromWIF(string, network) - it('fromWIF imports ' + string, function () { + it('fromWIF imports ' + string, () => { assert.strictEqual(keyPair.privateKey.toString('hex'), hex) assert.strictEqual(keyPair.compressed, params.isCompressed) }) - it('toWIF exports ' + hex + ' to ' + string, function () { + it('toWIF exports ' + hex + ' to ' + string, () => { assert.strictEqual(keyPair.toWIF(), string) }) }) }) // base58KeysInvalid - describe('ECPair.fromWIF', function () { + describe('ECPair.fromWIF', () => { const allowedNetworks = [ bitcoin.networks.bitcoin, bitcoin.networks.testnet ] - base58KeysInvalid.forEach(function (f) { + base58KeysInvalid.forEach(f => { const string = f[0] - it('throws on ' + string, function () { - assert.throws(function () { + it('throws on ' + string, () => { + assert.throws(() => { bitcoin.ECPair.fromWIF(string, allowedNetworks) }, /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/) }) }) }) - describe('Block.fromHex', function () { - blocksValid.forEach(function (f) { - it('can parse ' + f.id, function () { + describe('Block.fromHex', () => { + blocksValid.forEach(f => { + it('can parse ' + f.id, () => { const block = bitcoin.Block.fromHex(f.hex) assert.strictEqual(block.getId(), f.id) @@ -133,8 +133,8 @@ describe('Bitcoin-core', function () { }) // txValid - describe('Transaction.fromHex', function () { - txValid.forEach(function (f) { + describe('Transaction.fromHex', () => { + txValid.forEach(f => { // Objects that are only a single string are ignored if (f.length === 1) return @@ -142,17 +142,17 @@ describe('Bitcoin-core', function () { const fhex = f[1] // const verifyFlags = f[2] // TODO: do we need to test this? - it('can decode ' + fhex, function () { + it('can decode ' + fhex, () => { const transaction = bitcoin.Transaction.fromHex(fhex) - transaction.ins.forEach(function (txIn, i) { + transaction.ins.forEach((txIn, i) => { const input = inputs[i] // reverse because test data is reversed const prevOutHash = Buffer.from(input[0], 'hex').reverse() const prevOutIndex = input[1] - assert.deepEqual(txIn.hash, prevOutHash) + assert.deepStrictEqual(txIn.hash, prevOutHash) // we read UInt32, not Int32 assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex) @@ -162,8 +162,8 @@ describe('Bitcoin-core', function () { }) // sighash - describe('Transaction', function () { - sigHash.forEach(function (f) { + describe('Transaction', () => { + sigHash.forEach(f => { // Objects that are only a single string are ignored if (f.length === 1) return @@ -181,7 +181,7 @@ describe('Bitcoin-core', function () { const hashTypeName = hashTypes.join(' | ') - it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', function () { + it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', () => { const transaction = bitcoin.Transaction.fromHex(txHex) assert.strictEqual(transaction.toHex(), txHex) @@ -192,16 +192,16 @@ describe('Bitcoin-core', function () { const hash = transaction.hashForSignature(inIndex, script, hashType) // reverse because test data is reversed - assert.equal(hash.reverse().toString('hex'), expectedHash) + assert.strictEqual(hash.reverse().toString('hex'), expectedHash) }) }) }) - describe('script.signature.decode', function () { - sigCanonical.forEach(function (hex) { + describe('script.signature.decode', () => { + sigCanonical.forEach(hex => { const buffer = Buffer.from(hex, 'hex') - it('can parse ' + hex, function () { + it('can parse ' + hex, () => { const parsed = bitcoin.script.signature.decode(buffer) const actual = bitcoin.script.signature.encode(parsed.signature, parsed.hashType) @@ -209,15 +209,15 @@ describe('Bitcoin-core', function () { }) }) - sigNoncanonical.forEach(function (hex, i) { + sigNoncanonical.forEach((hex, i) => { if (i === 0) return if (i % 2 !== 0) return const description = sigNoncanonical[i - 1].slice(0, -1) const buffer = Buffer.from(hex, 'hex') - it('throws on ' + description, function () { - assert.throws(function () { + it('throws on ' + description, () => { + assert.throws(() => { bitcoin.script.signature.decode(buffer) }, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/) }) diff --git a/test/block.js b/test/block.js index e646737..d5e41af 100644 --- a/test/block.js +++ b/test/block.js @@ -4,29 +4,29 @@ const Block = require('..').Block const fixtures = require('./fixtures/block') -describe('Block', function () { - describe('version', function () { - it('should be interpreted as an int32le', function () { +describe('Block', () => { + describe('version', () => { + it('should be interpreted as an int32le', () => { const blockHex = 'ffffffff0000000000000000000000000000000000000000000000000000000000000000414141414141414141414141414141414141414141414141414141414141414101000000020000000300000000' const block = Block.fromHex(blockHex) - assert.equal(-1, block.version) - assert.equal(1, block.timestamp) + assert.strictEqual(-1, block.version) + assert.strictEqual(1, block.timestamp) }) }) - describe('calculateTarget', function () { - fixtures.targets.forEach(function (f) { - it('returns ' + f.expected + ' for 0x' + f.bits, function () { + describe('calculateTarget', () => { + fixtures.targets.forEach(f => { + it('returns ' + f.expected + ' for 0x' + f.bits, () => { const bits = parseInt(f.bits, 16) - assert.equal(Block.calculateTarget(bits).toString('hex'), f.expected) + assert.strictEqual(Block.calculateTarget(bits).toString('hex'), f.expected) }) }) }) - describe('fromBuffer/fromHex', function () { - fixtures.valid.forEach(function (f) { - it('imports ' + f.description, function () { + describe('fromBuffer/fromHex', () => { + fixtures.valid.forEach(f => { + it('imports ' + f.description, () => { const block = Block.fromHex(f.hex) assert.strictEqual(block.version, f.version) @@ -42,54 +42,54 @@ describe('Block', function () { }) }) - fixtures.invalid.forEach(function (f) { - it('throws on ' + f.exception, function () { - assert.throws(function () { + fixtures.invalid.forEach(f => { + it('throws on ' + f.exception, () => { + assert.throws(() => { Block.fromHex(f.hex) }, new RegExp(f.exception)) }) }) }) - describe('toBuffer/toHex', function () { - fixtures.valid.forEach(function (f) { + describe('toBuffer/toHex', () => { + fixtures.valid.forEach(f => { let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('exports ' + f.description, function () { + it('exports ' + f.description, () => { assert.strictEqual(block.toHex(true), f.hex.slice(0, 160)) assert.strictEqual(block.toHex(), f.hex) }) }) }) - describe('getHash/getId', function () { - fixtures.valid.forEach(function (f) { + describe('getHash/getId', () => { + fixtures.valid.forEach(f => { let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('returns ' + f.id + ' for ' + f.description, function () { + it('returns ' + f.id + ' for ' + f.description, () => { assert.strictEqual(block.getHash().toString('hex'), f.hash) assert.strictEqual(block.getId(), f.id) }) }) }) - describe('getUTCDate', function () { - fixtures.valid.forEach(function (f) { + describe('getUTCDate', () => { + fixtures.valid.forEach(f => { let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('returns UTC date of ' + f.id, function () { + it('returns UTC date of ' + f.id, () => { const utcDate = block.getUTCDate().getTime() assert.strictEqual(utcDate, f.timestamp * 1e3) @@ -97,59 +97,59 @@ describe('Block', function () { }) }) - describe('calculateMerkleRoot', function () { - it('should throw on zero-length transaction array', function () { - assert.throws(function () { + describe('calculateMerkleRoot', () => { + it('should throw on zero-length transaction array', () => { + assert.throws(() => { Block.calculateMerkleRoot([]) }, /Cannot compute merkle root for zero transactions/) }) - fixtures.valid.forEach(function (f) { + fixtures.valid.forEach(f => { if (f.hex.length === 160) return let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('returns ' + f.merkleRoot + ' for ' + f.id, function () { + it('returns ' + f.merkleRoot + ' for ' + f.id, () => { assert.strictEqual(Block.calculateMerkleRoot(block.transactions).toString('hex'), f.merkleRoot) }) if (f.witnessCommit) { - it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, function () { + it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, () => { assert.strictEqual(Block.calculateMerkleRoot(block.transactions, true).toString('hex'), f.witnessCommit) }) } }) }) - describe('checkTxRoots', function () { - fixtures.valid.forEach(function (f) { + describe('checkTxRoots', () => { + fixtures.valid.forEach(f => { if (f.hex.length === 160) return let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('returns ' + f.valid + ' for ' + f.id, function () { + it('returns ' + f.valid + ' for ' + f.id, () => { assert.strictEqual(block.checkTxRoots(), true) }) }) }) - describe('checkProofOfWork', function () { - fixtures.valid.forEach(function (f) { + describe('checkProofOfWork', () => { + fixtures.valid.forEach(f => { let block - beforeEach(function () { + beforeEach(() => { block = Block.fromHex(f.hex) }) - it('returns ' + f.valid + ' for ' + f.id, function () { + it('returns ' + f.valid + ' for ' + f.id, () => { assert.strictEqual(block.checkProofOfWork(), f.valid) }) }) diff --git a/test/bufferutils.js b/test/bufferutils.js index 5f2c39e..1a38406 100644 --- a/test/bufferutils.js +++ b/test/bufferutils.js @@ -4,10 +4,10 @@ const bufferutils = require('../src/bufferutils') const fixtures = require('./fixtures/bufferutils.json') -describe('bufferutils', function () { - describe('readUInt64LE', function () { - fixtures.valid.forEach(function (f) { - it('decodes ' + f.hex, function () { +describe('bufferutils', () => { + describe('readUInt64LE', () => { + fixtures.valid.forEach(f => { + it('decodes ' + f.hex, () => { const buffer = Buffer.from(f.hex, 'hex') const number = bufferutils.readUInt64LE(buffer, 0) @@ -15,20 +15,20 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.readUInt64LE.forEach(function (f) { - it('throws on ' + f.description, function () { + fixtures.invalid.readUInt64LE.forEach(f => { + it('throws on ' + f.description, () => { const buffer = Buffer.from(f.hex, 'hex') - assert.throws(function () { + assert.throws(() => { bufferutils.readUInt64LE(buffer, 0) }, new RegExp(f.exception)) }) }) }) - describe('writeUInt64LE', function () { - fixtures.valid.forEach(function (f) { - it('encodes ' + f.dec, function () { + describe('writeUInt64LE', () => { + fixtures.valid.forEach(f => { + it('encodes ' + f.dec, () => { const buffer = Buffer.alloc(8, 0) bufferutils.writeUInt64LE(buffer, f.dec, 0) @@ -36,11 +36,11 @@ describe('bufferutils', function () { }) }) - fixtures.invalid.readUInt64LE.forEach(function (f) { - it('throws on ' + f.description, function () { + fixtures.invalid.readUInt64LE.forEach(f => { + it('throws on ' + f.description, () => { const buffer = Buffer.alloc(8, 0) - assert.throws(function () { + assert.throws(() => { bufferutils.writeUInt64LE(buffer, f.dec, 0) }, new RegExp(f.exception)) }) diff --git a/test/classify.js b/test/classify.js index 3efcc74..86da74d 100644 --- a/test/classify.js +++ b/test/classify.js @@ -25,12 +25,12 @@ const tmap = { witnessCommitment } -describe('classify', function () { - describe('input', function () { - fixtures.valid.forEach(function (f) { +describe('classify', () => { + describe('input', () => { + fixtures.valid.forEach(f => { if (!f.input) return - it('classifies ' + f.input + ' as ' + f.type, function () { + it('classifies ' + f.input + ' as ' + f.type, () => { const input = bscript.fromASM(f.input) const type = classify.input(input) @@ -38,11 +38,11 @@ describe('classify', function () { }) }) - fixtures.valid.forEach(function (f) { + fixtures.valid.forEach(f => { if (!f.input) return if (!f.typeIncomplete) return - it('classifies incomplete ' + f.input + ' as ' + f.typeIncomplete, function () { + it('classifies incomplete ' + f.input + ' as ' + f.typeIncomplete, () => { const input = bscript.fromASM(f.input) const type = classify.input(input, true) @@ -51,11 +51,11 @@ describe('classify', function () { }) }) - describe('classifyOutput', function () { - fixtures.valid.forEach(function (f) { + describe('classifyOutput', () => { + fixtures.valid.forEach(f => { if (!f.output) return - it('classifies ' + f.output + ' as ' + f.type, function () { + it('classifies ' + f.output + ' as ' + f.type, () => { const output = bscript.fromASM(f.output) const type = classify.output(output) @@ -73,12 +73,12 @@ describe('classify', function () { 'multisig', 'nullData', 'witnessCommitment' - ].forEach(function (name) { + ].forEach(name => { const inputType = tmap[name].input const outputType = tmap[name].output - describe(name + '.input.check', function () { - fixtures.valid.forEach(function (f) { + describe(name + '.input.check', () => { + fixtures.valid.forEach(f => { if (name.toLowerCase() === classify.types.P2WPKH) return if (name.toLowerCase() === classify.types.P2WSH) return const expected = name.toLowerCase() === f.type.toLowerCase() @@ -86,14 +86,14 @@ describe('classify', function () { if (inputType && f.input) { const input = bscript.fromASM(f.input) - it('returns ' + expected + ' for ' + f.input, function () { + it('returns ' + expected + ' for ' + f.input, () => { assert.strictEqual(inputType.check(input), expected) }) if (f.typeIncomplete) { const expectedIncomplete = name.toLowerCase() === f.typeIncomplete - it('returns ' + expected + ' for ' + f.input, function () { + it('returns ' + expected + ' for ' + f.input, () => { assert.strictEqual(inputType.check(input, true), expectedIncomplete) }) } @@ -102,10 +102,10 @@ describe('classify', function () { if (!(fixtures.invalid[name])) return - fixtures.invalid[name].inputs.forEach(function (f) { + fixtures.invalid[name].inputs.forEach(f => { if (!f.input && !f.inputHex) return - it('returns false for ' + f.description + ' (' + (f.input || f.inputHex) + ')', function () { + it('returns false for ' + f.description + ' (' + (f.input || f.inputHex) + ')', () => { let input if (f.input) { @@ -119,12 +119,12 @@ describe('classify', function () { }) }) - describe(name + '.output.check', function () { - fixtures.valid.forEach(function (f) { + describe(name + '.output.check', () => { + fixtures.valid.forEach(f => { const expected = name.toLowerCase() === f.type if (outputType && f.output) { - it('returns ' + expected + ' for ' + f.output, function () { + it('returns ' + expected + ' for ' + f.output, () => { const output = bscript.fromASM(f.output) if (name.toLowerCase() === 'nulldata' && f.type === classify.types.WITNESS_COMMITMENT) return @@ -136,10 +136,10 @@ describe('classify', function () { if (!(fixtures.invalid[name])) return - fixtures.invalid[name].outputs.forEach(function (f) { + fixtures.invalid[name].outputs.forEach(f => { if (!f.output && !f.outputHex) return - it('returns false for ' + f.description + ' (' + (f.output || f.outputHex) + ')', function () { + it('returns false for ' + f.description + ' (' + (f.output || f.outputHex) + ')', () => { let output if (f.output) { diff --git a/test/crypto.js b/test/crypto.js index 3f7802a..14b4f33 100644 --- a/test/crypto.js +++ b/test/crypto.js @@ -4,14 +4,14 @@ const bcrypto = require('../src/crypto') const fixtures = require('./fixtures/crypto') -describe('crypto', function () { - ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(function (algorithm) { - describe(algorithm, function () { - fixtures.forEach(function (f) { +describe('crypto', () => { + ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => { + describe(algorithm, () => { + fixtures.forEach(f => { const fn = bcrypto[algorithm] const expected = f[algorithm] - it('returns ' + expected + ' for ' + f.hex, function () { + it('returns ' + expected + ' for ' + f.hex, () => { const data = Buffer.from(f.hex, 'hex') const actual = fn(data).toString('hex') diff --git a/test/ecpair.js b/test/ecpair.js index de5c485..ce32683 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -19,15 +19,15 @@ const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000 const GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex') const GROUP_ORDER_LESS_1 = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', 'hex') -describe('ECPair', function () { - describe('getPublicKey', function () { +describe('ECPair', () => { + describe('getPublicKey', () => { let keyPair - beforeEach(function () { + beforeEach(() => { keyPair = ECPair.fromPrivateKey(ONE) }) - it('calls pointFromScalar lazily', hoodwink(function () { + it('calls pointFromScalar lazily', hoodwink(() => { assert.strictEqual(keyPair.__Q, undefined) // .publicKey forces the memoization @@ -36,14 +36,14 @@ describe('ECPair', function () { })) }) - describe('fromPrivateKey', function () { - it('defaults to compressed', function () { + describe('fromPrivateKey', () => { + it('defaults to compressed', () => { const keyPair = ECPair.fromPrivateKey(ONE) assert.strictEqual(keyPair.compressed, true) }) - it('supports the uncompressed option', function () { + it('supports the uncompressed option', () => { const keyPair = ECPair.fromPrivateKey(ONE, { compressed: false }) @@ -51,7 +51,7 @@ describe('ECPair', function () { assert.strictEqual(keyPair.compressed, false) }) - it('supports the network option', function () { + it('supports the network option', () => { const keyPair = ECPair.fromPrivateKey(ONE, { compressed: false, network: NETWORKS.testnet @@ -60,8 +60,8 @@ describe('ECPair', function () { assert.strictEqual(keyPair.network, NETWORKS.testnet) }) - fixtures.valid.forEach(function (f) { - it('derives public key for ' + f.WIF, function () { + fixtures.valid.forEach(f => { + it('derives public key for ' + f.WIF, () => { const d = Buffer.from(f.d, 'hex') const keyPair = ECPair.fromPrivateKey(d, { compressed: f.compressed @@ -71,30 +71,30 @@ describe('ECPair', function () { }) }) - fixtures.invalid.fromPrivateKey.forEach(function (f) { - it('throws ' + f.exception, function () { + fixtures.invalid.fromPrivateKey.forEach(f => { + it('throws ' + f.exception, () => { const d = Buffer.from(f.d, 'hex') - assert.throws(function () { + assert.throws(() => { ECPair.fromPrivateKey(d, f.options) }, new RegExp(f.exception)) }) }) }) - describe('fromPublicKey', function () { - fixtures.invalid.fromPublicKey.forEach(function (f) { - it('throws ' + f.exception, function () { + describe('fromPublicKey', () => { + fixtures.invalid.fromPublicKey.forEach(f => { + it('throws ' + f.exception, () => { const Q = Buffer.from(f.Q, 'hex') - assert.throws(function () { + assert.throws(() => { ECPair.fromPublicKey(Q, f.options) }, new RegExp(f.exception)) }) }) }) - describe('fromWIF', function () { - fixtures.valid.forEach(function (f) { - it('imports ' + f.WIF + ' (' + f.network + ')', function () { + describe('fromWIF', () => { + fixtures.valid.forEach(f => { + it('imports ' + f.WIF + ' (' + f.network + ')', () => { const network = NETWORKS[f.network] const keyPair = ECPair.fromWIF(f.WIF, network) @@ -104,8 +104,8 @@ describe('ECPair', function () { }) }) - fixtures.valid.forEach(function (f) { - it('imports ' + f.WIF + ' (via list of networks)', function () { + fixtures.valid.forEach(f => { + it('imports ' + f.WIF + ' (via list of networks)', () => { const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) assert.strictEqual(keyPair.privateKey.toString('hex'), f.d) @@ -114,9 +114,9 @@ describe('ECPair', function () { }) }) - fixtures.invalid.fromWIF.forEach(function (f) { - it('throws on ' + f.WIF, function () { - assert.throws(function () { + fixtures.invalid.fromWIF.forEach(f => { + it('throws on ' + f.WIF, () => { + assert.throws(() => { const networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST ECPair.fromWIF(f.WIF, networks) @@ -125,9 +125,9 @@ describe('ECPair', function () { }) }) - describe('toWIF', function () { - fixtures.valid.forEach(function (f) { - it('exports ' + f.WIF, function () { + describe('toWIF', () => { + fixtures.valid.forEach(f => { + it('exports ' + f.WIF, () => { const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) const result = keyPair.toWIF() assert.strictEqual(result, f.WIF) @@ -135,13 +135,13 @@ describe('ECPair', function () { }) }) - describe('makeRandom', function () { + describe('makeRandom', () => { const d = Buffer.alloc(32, 4) const exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' - describe('uses randombytes RNG', function () { - it('generates a ECPair', function () { - const stub = { randombytes: function () { return d } } + describe('uses randombytes RNG', () => { + it('generates a ECPair', () => { + const stub = { randombytes: () => { return d } } const ProxiedECPair = proxyquire('../src/ecpair', stub) const keyPair = ProxiedECPair.makeRandom() @@ -149,22 +149,22 @@ describe('ECPair', function () { }) }) - it('allows a custom RNG to be used', function () { + it('allows a custom RNG to be used', () => { const keyPair = ECPair.makeRandom({ - rng: function (size) { return d.slice(0, size) } + rng: size => { return d.slice(0, size) } }) assert.strictEqual(keyPair.toWIF(), exWIF) }) - it('retains the same defaults as ECPair constructor', function () { + it('retains the same defaults as ECPair constructor', () => { const keyPair = ECPair.makeRandom() assert.strictEqual(keyPair.compressed, true) assert.strictEqual(keyPair.network, NETWORKS.bitcoin) }) - it('supports the options parameter', function () { + it('supports the options parameter', () => { const keyPair = ECPair.makeRandom({ compressed: false, network: NETWORKS.testnet @@ -174,18 +174,18 @@ describe('ECPair', function () { assert.strictEqual(keyPair.network, NETWORKS.testnet) }) - it('throws if d is bad length', function () { + it('throws if d is bad length', () => { function rng () { return Buffer.alloc(28) } - assert.throws(function () { + assert.throws(() => { ECPair.makeRandom({ rng: rng }) }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 28\)/) }) it('loops until d is within interval [1, n) : 1', hoodwink(function () { - const rng = this.stub(function () { + const rng = this.stub(() => { if (rng.calls === 0) return ZERO // 0 return ONE // >0 }, 2) @@ -194,7 +194,7 @@ describe('ECPair', function () { })) it('loops until d is within interval [1, n) : n - 1', hoodwink(function () { - const rng = this.stub(function () { + const rng = this.stub(() => { if (rng.calls === 0) return ZERO // <1 if (rng.calls === 1) return GROUP_ORDER // >n-1 return GROUP_ORDER_LESS_1 // n-1 @@ -204,9 +204,9 @@ describe('ECPair', function () { })) }) - describe('.network', function () { - fixtures.valid.forEach(function (f) { - it('returns ' + f.network + ' for ' + f.WIF, function () { + describe('.network', () => { + fixtures.valid.forEach(f => { + it('returns ' + f.network + ' for ' + f.WIF, () => { const network = NETWORKS[f.network] const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) @@ -215,20 +215,20 @@ describe('ECPair', function () { }) }) - describe('tinysecp wrappers', function () { + describe('tinysecp wrappers', () => { let keyPair let hash let signature - beforeEach(function () { + beforeEach(() => { keyPair = ECPair.makeRandom() hash = ZERO signature = Buffer.alloc(64, 1) }) - describe('signing', function () { + describe('signing', () => { it('wraps tinysecp.sign', hoodwink(function () { - this.mock(tinysecp, 'sign', function (h, d) { + this.mock(tinysecp, 'sign', (h, d) => { assert.strictEqual(h, hash) assert.strictEqual(d, keyPair.privateKey) return signature @@ -237,18 +237,18 @@ describe('ECPair', function () { assert.strictEqual(keyPair.sign(hash), signature) })) - it('throws if no private key is found', function () { + it('throws if no private key is found', () => { delete keyPair.__D - assert.throws(function () { + assert.throws(() => { keyPair.sign(hash) }, /Missing private key/) }) }) - describe('verify', function () { + describe('verify', () => { it('wraps tinysecp.verify', hoodwink(function () { - this.mock(tinysecp, 'verify', function (h, q, s) { + this.mock(tinysecp, 'verify', (h, q, s) => { assert.strictEqual(h, hash) assert.strictEqual(q, keyPair.publicKey) assert.strictEqual(s, signature) diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index e32e11b..abfee1a 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -47,7 +47,7 @@ async function faucet (address, value) { let _unspents = [] const sleep = ms => new Promise((resolve, reject) => setTimeout(resolve, ms)) const randInt = (min, max) => min + Math.floor((max - min + 1) * Math.random()) - do { + while (_unspents.length === 0) { if (count > 0) { if (count >= 5) throw new Error('Missing Inputs') console.log('Missing Inputs, retry #' + count) @@ -78,7 +78,7 @@ async function faucet (address, value) { _unspents = results.filter(x => x.txId === txId) count++ - } while (_unspents.length === 0) + } return _unspents.pop() } diff --git a/test/integration/addresses.js b/test/integration/addresses.js index f37dbc7..1d28020 100644 --- a/test/integration/addresses.js +++ b/test/integration/addresses.js @@ -4,8 +4,8 @@ const bitcoin = require('../../') const dhttp = require('./_regtest').dhttp const TESTNET = bitcoin.networks.testnet -describe('bitcoinjs-lib (addresses)', function () { - it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', async function () { +describe('bitcoinjs-lib (addresses)', () => { + it('can generate a random address [and support the retrieval of transactions for that address (via 3PBP)', async () => { const keyPair = bitcoin.ECPair.makeRandom() const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) @@ -23,14 +23,14 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(result.total_sent, 0) }) - it('can import an address via WIF', function () { + it('can import an address via WIF', () => { const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }) assert.strictEqual(address, '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH') }) - it('can generate a P2SH, pay-to-multisig (2-of-3) address', function () { + it('can generate a P2SH, pay-to-multisig (2-of-3) address', () => { const pubkeys = [ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', @@ -43,14 +43,14 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') }) - it('can generate a SegWit address', function () { + it('can generate a SegWit address', () => { const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) assert.strictEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4') }) - it('can generate a SegWit address (via P2SH)', function () { + it('can generate a SegWit address (via P2SH)', () => { const keyPair = bitcoin.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn') const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }) @@ -59,7 +59,7 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN') }) - it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', function () { + it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', () => { const pubkeys = [ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', @@ -73,7 +73,7 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address, 'bc1q75f6dv4q8ug7zhujrsp5t0hzf33lllnr3fe7e2pra3v24mzl8rrqtp3qul') }) - it('can generate a P2SH(P2WSH(...)), pay-to-multisig (2-of-2) address', function () { + it('can generate a P2SH(P2WSH(...)), pay-to-multisig (2-of-2) address', () => { const pubkeys = [ '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9' @@ -88,7 +88,7 @@ describe('bitcoinjs-lib (addresses)', function () { }) // examples using other network information - it('can generate a Testnet address', function () { + it('can generate a Testnet address', () => { const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET }) const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET }) @@ -96,7 +96,7 @@ describe('bitcoinjs-lib (addresses)', function () { assert.strictEqual(address.startsWith('m') || address.startsWith('n'), true) }) - it('can generate a Litecoin address', function () { + it('can generate a Litecoin address', () => { // WARNING: although possible, bitcoinjs is NOT necessarily compatible with Litecoin const LITECOIN = { messagePrefix: '\x19Litecoin Signed Message:\n', diff --git a/test/integration/bip32.js b/test/integration/bip32.js index 5f948fa..255669c 100644 --- a/test/integration/bip32.js +++ b/test/integration/bip32.js @@ -8,15 +8,15 @@ function getAddress (node, network) { return bitcoin.payments.p2pkh({ pubkey: node.publicKey, network }).address } -describe('bitcoinjs-lib (BIP32)', function () { - it('can import a BIP32 testnet xpriv and export to WIF', function () { +describe('bitcoinjs-lib (BIP32)', () => { + it('can import a BIP32 testnet xpriv and export to WIF', () => { const xpriv = 'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK' const node = bip32.fromBase58(xpriv, bitcoin.networks.testnet) assert.strictEqual(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7') }) - it('can export a BIP32 xpriv, then import it', function () { + it('can export a BIP32 xpriv, then import it', () => { const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost' const seed = bip39.mnemonicToSeed(mnemonic) const node = bip32.fromSeed(seed) @@ -27,7 +27,7 @@ describe('bitcoinjs-lib (BIP32)', function () { assert.strictEqual(node.toWIF(), restored.toWIF()) // same private key }) - it('can export a BIP32 xpub', function () { + it('can export a BIP32 xpub', () => { const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost' const seed = bip39.mnemonicToSeed(mnemonic) const node = bip32.fromSeed(seed) @@ -36,7 +36,7 @@ describe('bitcoinjs-lib (BIP32)', function () { assert.strictEqual(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n') }) - it('can create a BIP32, bitcoin, account 0, external address', function () { + it('can create a BIP32, bitcoin, account 0, external address', () => { const path = "m/0'/0/0" const root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex')) @@ -51,7 +51,7 @@ describe('bitcoinjs-lib (BIP32)', function () { assert.strictEqual(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7') }) - it('can create a BIP44, bitcoin, account 0, external address', function () { + it('can create a BIP44, bitcoin, account 0, external address', () => { const root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex')) const child1 = root.derivePath("m/44'/0'/0'/0/0") @@ -67,7 +67,7 @@ describe('bitcoinjs-lib (BIP32)', function () { assert.strictEqual(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au') }) - it('can create a BIP49, bitcoin testnet, account 0, external address', function () { + it('can create a BIP49, bitcoin testnet, account 0, external address', () => { const mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' const seed = bip39.mnemonicToSeed(mnemonic) const root = bip32.fromSeed(seed) @@ -82,7 +82,7 @@ describe('bitcoinjs-lib (BIP32)', function () { assert.strictEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2') }) - it('can use BIP39 to generate BIP32 addresses', function () { + it('can use BIP39 to generate BIP32 addresses', () => { // var mnemonic = bip39.generateMnemonic() const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost' assert(bip39.validateMnemonic(mnemonic)) diff --git a/test/integration/blocks.js b/test/integration/blocks.js index 915fd65..044862d 100644 --- a/test/integration/blocks.js +++ b/test/integration/blocks.js @@ -4,8 +4,8 @@ const { describe, it } = require('mocha') const assert = require('assert') const bitcoin = require('../../') -describe('bitcoinjs-lib (blocks)', function () { - it('can extract a height from a CoinBase transaction', function () { +describe('bitcoinjs-lib (blocks)', () => { + it('can extract a height from a CoinBase transaction', () => { // from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6 const txHex = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98fd16761d220400000000000000aa340000d49f0000ffffffff02b07fc366000000001976a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12bf1e400120000000000000000000000000000000000000000000000000000000000000000000000000' const tx = bitcoin.Transaction.fromHex(txHex) diff --git a/test/integration/cltv.js b/test/integration/cltv.js index 66afb94..b2fd478 100644 --- a/test/integration/cltv.js +++ b/test/integration/cltv.js @@ -8,9 +8,9 @@ const bip65 = require('bip65') const alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest) const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest) -describe('bitcoinjs-lib (transactions w/ CLTV)', function () { +describe('bitcoinjs-lib (transactions w/ CLTV)', () => { // force update MTP - before(async function () { + before(async () => { await regtestUtils.mine(11) }) @@ -38,7 +38,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { } // expiry past, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', async function () { + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', async () => { // 3 hours ago const lockTime = bip65.encode({ utc: utcNow() - (3600 * 3) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) @@ -77,7 +77,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { }) // expiry will pass, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async function () { + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async () => { const height = await regtestUtils.height() // 5 blocks from now const lockTime = bip65.encode({ blocks: height + 5 }) @@ -120,7 +120,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { }) // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE - it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', async function () { + it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', async () => { // two hours ago const lockTime = bip65.encode({ utc: utcNow() - (3600 * 2) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) @@ -159,7 +159,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { }) // expiry in the future, {Alice's signature} OP_TRUE - it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async function () { + it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async () => { // two hours from now const lockTime = bip65.encode({ utc: utcNow() + (3600 * 2) }) const redeemScript = cltvCheckSigOutput(alice, bob, lockTime) @@ -189,7 +189,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () { tx.setInputScript(0, redeemScriptSig) await regtestUtils.broadcast(tx.toHex()).catch(err => { - assert.throws(function () { + assert.throws(() => { if (err) throw err }, /Error: non-final \(code 64\)/) }) diff --git a/test/integration/csv.js b/test/integration/csv.js index 1ad8c90..8833412 100644 --- a/test/integration/csv.js +++ b/test/integration/csv.js @@ -8,9 +8,9 @@ const bip68 = require('bip68') const alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest) const bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest) -describe('bitcoinjs-lib (transactions w/ CSV)', function () { +describe('bitcoinjs-lib (transactions w/ CSV)', () => { // force update MTP - before(async function () { + before(async () => { await regtestUtils.mine(11) }) @@ -35,7 +35,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { } // expiry will pass, {Alice's signature} OP_TRUE - it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async function () { + it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', async () => { // 5 blocks from now const sequence = bip68.encode({ blocks: 5 }) const p2sh = bitcoin.payments.p2sh({ @@ -84,7 +84,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { }) // expiry in the future, {Alice's signature} OP_TRUE - it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async function () { + it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', async () => { // two hours after confirmation const sequence = bip68.encode({ seconds: 7168 }) const p2sh = bitcoin.payments.p2sh({ @@ -119,7 +119,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () { tx.setInputScript(0, redeemScriptSig) await regtestUtils.broadcast(tx.toHex()).catch(err => { - assert.throws(function () { + assert.throws(() => { if (err) throw err }, /Error: non-BIP68-final \(code 64\)/) }) diff --git a/test/integration/payments.js b/test/integration/payments.js index 2fcdbda..66b0a13 100644 --- a/test/integration/payments.js +++ b/test/integration/payments.js @@ -16,7 +16,7 @@ async function buildAndSign (depends, prevOutput, redeemScript, witnessScript) { txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4) if (depends.signatures) { - keyPairs.forEach((keyPair) => { + keyPairs.forEach(keyPair => { txb.sign(0, keyPair, redeemScript, null, unspent.value, witnessScript) }) } else if (depends.signature) { @@ -26,7 +26,7 @@ async function buildAndSign (depends, prevOutput, redeemScript, witnessScript) { return regtestUtils.broadcast(txb.build().toHex()) } -;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach((k) => { +;['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach(k => { const fixtures = require('../fixtures/' + k) const { depends } = fixtures.dynamic const fn = bitcoin.payments[k] @@ -39,7 +39,7 @@ async function buildAndSign (depends, prevOutput, redeemScript, witnessScript) { const { output } = fn(base) if (!output) throw new TypeError('Missing output') - describe('bitcoinjs-lib (payments - ' + k + ')', function () { + describe('bitcoinjs-lib (payments - ' + k + ')', () => { it('can broadcast as an output, and be spent as an input', async () => { await buildAndSign(depends, output, null, null) }) diff --git a/test/integration/transactions.js b/test/integration/transactions.js index a3836a7..c096b87 100644 --- a/test/integration/transactions.js +++ b/test/integration/transactions.js @@ -8,8 +8,8 @@ function rng () { return Buffer.from('YT8dAtK4d16A3P1z+TpwB2jJ4aFH3g9M1EioIBkLEV4=', 'base64') } -describe('bitcoinjs-lib (transactions)', function () { - it('can create a 1-to-1 Transaction', function () { +describe('bitcoinjs-lib (transactions)', () => { + it('can create a 1-to-1 Transaction', () => { const alice = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') const txb = new bitcoin.TransactionBuilder() @@ -24,7 +24,7 @@ describe('bitcoinjs-lib (transactions)', function () { assert.strictEqual(txb.build().toHex(), '01000000019d344070eac3fe6e394a16d06d7704a7d5c0a10eb2a2c16bc98842b7cc20d561000000006b48304502210088828c0bdfcdca68d8ae0caeb6ec62cd3fd5f9b2191848edae33feb533df35d302202e0beadd35e17e7f83a733f5277028a9b453d525553e3f5d2d7a7aa8010a81d60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e02e0000000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000') }) - it('can create a 2-to-2 Transaction', function () { + it('can create a 2-to-2 Transaction', () => { const alice = bitcoin.ECPair.fromWIF('L1Knwj9W3qK3qMKdTvmg3VfzUs3ij2LETTFhxza9LfD5dngnoLG1') const bob = bitcoin.ECPair.fromWIF('KwcN2pT3wnRAurhy7qMczzbkpY5nXMW2ubh696UBc1bcwctTx26z') @@ -232,17 +232,17 @@ describe('bitcoinjs-lib (transactions)', function () { }) }) - it('can verify Transaction (P2PKH) signatures', function () { + it('can verify Transaction (P2PKH) signatures', () => { const txHex = '010000000321c5f7e7bc98b3feda84aad36a5c99a02bcb8823a2f3eccbcd5da209698b5c20000000006b48304502210099e021772830207cf7c55b69948d3b16b4dcbf1f55a9cd80ebf8221a169735f9022064d33f11d62cd28240b3862afc0b901adc9f231c7124dd19bdb30367b61964c50121032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63dffffffff8a75ce85441ddb3f342708ee33cc8ed418b07d9ba9e0e7c4e1cccfe9f52d8a88000000006946304302207916c23dae212c95a920423902fa44e939fb3d542f4478a7b46e9cde53705800021f0d74e9504146e404c1b8f9cba4dff2d4782e3075491c9ed07ce4a7d1c4461a01210216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2affffffffdfef93f69fe32e944fad79fa8f882b3a155d80383252348caba1a77a5abbf7ef000000006b483045022100faa6e9ca289b46c64764a624c59ac30d9abcf1d4a04c4de9089e67cbe0d300a502206930afa683f6807502de5c2431bf9a1fd333c8a2910a76304df0f3d23d83443f0121039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18fffffffff01ff4b0000000000001976a9146c86476d1d85cd60116cd122a274e6a570a5a35c88acc96d0700' const keyPairs = [ '032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d', '0216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2a', '039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18f' - ].map(function (q) { return bitcoin.ECPair.fromPublicKey(Buffer.from(q, 'hex')) }) + ].map(q => { return bitcoin.ECPair.fromPublicKey(Buffer.from(q, 'hex')) }) const tx = bitcoin.Transaction.fromHex(txHex) - tx.ins.forEach(function (input, i) { + tx.ins.forEach((input, i) => { const keyPair = keyPairs[i] const p2pkh = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, @@ -256,7 +256,7 @@ describe('bitcoinjs-lib (transactions)', function () { }) }) - it('can verify Transaction (P2SH(P2WPKH)) signatures', function () { + it('can verify Transaction (P2SH(P2WPKH)) signatures', () => { const utxos = { 'f72d1d83ac40fcedd01415751556a905844ab5f44bbb7728565ebb91b1590109:0': { value: 50000 @@ -266,7 +266,7 @@ describe('bitcoinjs-lib (transactions)', function () { const txHex = '02000000000101090159b191bb5e562877bb4bf4b54a8405a95615751514d0edfc40ac831d2df7000000001716001435a179e5516947a39ae9c8a25e9fe62c0fc598edffffffff01204e0000000000001976a91431d43308d3c886d53e9ae8a45728370571ff456988ac0247304402206ec41f685b997a51f325b07ee852e82a535f6b52ef54485cc133e05168aa052a022070bafa86108acb51c77b2b259ae8fb7fd1efa10fef804fcfe9b13c2db719acf5012103fb03e9d0a9af86cbed94225dbb8bb70f6b82109bce0a61ddcf41dab6cbb4871100000000' const tx = bitcoin.Transaction.fromHex(txHex) - tx.ins.forEach(function (input, i) { + tx.ins.forEach((input, i) => { const txId = Buffer.from(input.hash).reverse().toString('hex') const utxo = utxos[`${txId}:${i}`] if (!utxo) throw new Error('Missing utxo') diff --git a/test/payments.js b/test/payments.js index a4f07bb..5619cdb 100644 --- a/test/payments.js +++ b/test/payments.js @@ -2,8 +2,8 @@ const { describe, it } = require('mocha') const assert = require('assert') const u = require('./payments.utils') -;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) { - describe(p, function () { +;['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(p => { + describe(p, () => { let fn let payment = require('../src/payments/' + p) if (p === 'embed') { @@ -13,15 +13,15 @@ const u = require('./payments.utils') } const fixtures = require('./fixtures/' + p) - fixtures.valid.forEach(function (f, i) { - it(f.description + ' as expected', function () { + fixtures.valid.forEach((f, i) => { + it(f.description + ' as expected', () => { const args = u.preform(f.arguments) const actual = fn(args, f.options) u.equate(actual, f.expected, f.arguments) }) - it(f.description + ' as expected (no validation)', function () { + it(f.description + ' as expected (no validation)', () => { const args = u.preform(f.arguments) const actual = fn(args, Object.assign({}, f.options, { validate: false @@ -31,11 +31,11 @@ const u = require('./payments.utils') }) }) - fixtures.invalid.forEach(function (f) { - it('throws ' + f.exception + (f.description ? ('for ' + f.description) : ''), function () { + fixtures.invalid.forEach(f => { + it('throws ' + f.exception + (f.description ? ('for ' + f.description) : ''), () => { const args = u.preform(f.arguments) - assert.throws(function () { + assert.throws(() => { fn(args, f.options) }, new RegExp(f.exception)) }) @@ -45,23 +45,23 @@ const u = require('./payments.utils') if (!fixtures.dynamic) return const { depends, details } = fixtures.dynamic - details.forEach(function (f) { + details.forEach(f => { const detail = u.preform(f) const disabled = {} - if (f.disabled) f.disabled.forEach(function (k) { disabled[k] = true }) + if (f.disabled) f.disabled.forEach(k => { disabled[k] = true }) for (let key in depends) { if (key in disabled) continue const dependencies = depends[key] - dependencies.forEach(function (dependency) { + dependencies.forEach(dependency => { if (!Array.isArray(dependency)) dependency = [dependency] const args = {} - dependency.forEach(function (d) { u.from(d, detail, args) }) + dependency.forEach(d => { u.from(d, detail, args) }) const expected = u.from(key, detail) - it(f.description + ', ' + key + ' derives from ' + JSON.stringify(dependency), function () { + it(f.description + ', ' + key + ' derives from ' + JSON.stringify(dependency), () => { u.equate(fn(args), expected) }) }) diff --git a/test/payments.utils.js b/test/payments.utils.js index 485bf03..15414c4 100644 --- a/test/payments.utils.js +++ b/test/payments.utils.js @@ -39,7 +39,7 @@ function carryOver (a, b) { function equateBase (a, b, context) { if ('output' in b) t.strictEqual(tryASM(a.output), tryASM(b.output), `Inequal ${context}output`) if ('input' in b) t.strictEqual(tryASM(a.input), tryASM(b.input), `Inequal ${context}input`) - if ('witness' in b) t.deepEqual(tryHex(a.witness), tryHex(b.witness), `Inequal ${context}witness`) + if ('witness' in b) t.deepStrictEqual(tryHex(a.witness), tryHex(b.witness), `Inequal ${context}witness`) } function equate (a, b, args) { @@ -58,19 +58,20 @@ function equate (a, b, args) { equateBase(a, b, '') if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.') - if (b.network) t.deepEqual(a.network, BNETWORKS[b.network], 'Inequal *.network') + if (b.network) t.deepStrictEqual(a.network, BNETWORKS[b.network], 'Inequal *.network') // contextual if (b.signature === null) b.signature = undefined + if (b.signatures === null) b.signatures = undefined if ('address' in b) t.strictEqual(a.address, b.address, 'Inequal *.address') if ('hash' in b) t.strictEqual(tryHex(a.hash), tryHex(b.hash), 'Inequal *.hash') if ('pubkey' in b) t.strictEqual(tryHex(a.pubkey), tryHex(b.pubkey), 'Inequal *.pubkey') if ('signature' in b) t.strictEqual(tryHex(a.signature), tryHex(b.signature), 'Inequal signature') if ('m' in b) t.strictEqual(a.m, b.m, 'Inequal *.m') if ('n' in b) t.strictEqual(a.n, b.n, 'Inequal *.n') - if ('pubkeys' in b) t.deepEqual(tryHex(a.pubkeys), tryHex(b.pubkeys), 'Inequal *.pubkeys') - if ('signatures' in b) t.deepEqual(tryHex(a.signatures), tryHex(b.signatures), 'Inequal *.signatures') - if ('data' in b) t.deepEqual(tryHex(a.data), tryHex(b.data), 'Inequal *.data') + if ('pubkeys' in b) t.deepStrictEqual(tryHex(a.pubkeys), tryHex(b.pubkeys), 'Inequal *.pubkeys') + if ('signatures' in b) t.deepStrictEqual(tryHex(a.signatures), tryHex(b.signatures), 'Inequal *.signatures') + if ('data' in b) t.deepStrictEqual(tryHex(a.data), tryHex(b.data), 'Inequal *.data') } function preform (x) { @@ -94,7 +95,7 @@ function preform (x) { if (x.pubkey) x.pubkey = Buffer.from(x.pubkey, 'hex') if (x.signature) x.signature = Buffer.from(x.signature, 'hex') if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex) - if (x.signatures) x.signatures = x.signatures.map(function (y) { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') }) + if (x.signatures) x.signatures = x.signatures.map(y => { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') }) if (x.redeem) { x.redeem = Object.assign({}, x.redeem) if (typeof x.redeem.input === 'string') x.redeem.input = asmToBuffer(x.redeem.input) diff --git a/test/script.js b/test/script.js index c2a60ad..d003558 100644 --- a/test/script.js +++ b/test/script.js @@ -6,44 +6,44 @@ const minimalData = require('minimaldata') const fixtures = require('./fixtures/script.json') const fixtures2 = require('./fixtures/templates.json') -describe('script', function () { +describe('script', () => { // TODO - describe('isCanonicalPubKey', function () { - it('rejects if not provided a Buffer', function () { + describe('isCanonicalPubKey', () => { + it('rejects if not provided a Buffer', () => { assert.strictEqual(false, bscript.isCanonicalPubKey(0)) }) - it('rejects smaller than 33', function () { + it('rejects smaller than 33', () => { for (var i = 0; i < 33; i++) { assert.strictEqual(false, bscript.isCanonicalPubKey(Buffer.from('', i))) } }) }) - describe.skip('isCanonicalScriptSignature', function () { + describe.skip('isCanonicalScriptSignature', () => { }) - describe('fromASM/toASM', function () { - fixtures.valid.forEach(function (f) { - it('encodes/decodes ' + f.asm, function () { + describe('fromASM/toASM', () => { + fixtures.valid.forEach(f => { + it('encodes/decodes ' + f.asm, () => { const script = bscript.fromASM(f.asm) assert.strictEqual(bscript.toASM(script), f.asm) }) }) - fixtures.invalid.fromASM.forEach(function (f) { - it('throws ' + f.description, function () { - assert.throws(function () { + fixtures.invalid.fromASM.forEach(f => { + it('throws ' + f.description, () => { + assert.throws(() => { bscript.fromASM(f.script) }, new RegExp(f.description)) }) }) }) - describe('fromASM/toASM (templates)', function () { - fixtures2.valid.forEach(function (f) { + describe('fromASM/toASM (templates)', () => { + fixtures2.valid.forEach(f => { if (f.inputHex) { const ih = bscript.toASM(Buffer.from(f.inputHex, 'hex')) - it('encodes/decodes ' + ih, function () { + it('encodes/decodes ' + ih, () => { const script = bscript.fromASM(f.input) assert.strictEqual(script.toString('hex'), f.inputHex) assert.strictEqual(bscript.toASM(script), f.input) @@ -51,7 +51,7 @@ describe('script', function () { } if (f.outputHex) { - it('encodes/decodes ' + f.output, function () { + it('encodes/decodes ' + f.output, () => { const script = bscript.fromASM(f.output) assert.strictEqual(script.toString('hex'), f.outputHex) assert.strictEqual(bscript.toASM(script), f.output) @@ -60,9 +60,9 @@ describe('script', function () { }) }) - describe('isPushOnly', function () { - fixtures.valid.forEach(function (f) { - it('returns ' + !!f.stack + ' for ' + f.asm, function () { + describe('isPushOnly', () => { + fixtures.valid.forEach(f => { + it('returns ' + !!f.stack + ' for ' + f.asm, () => { const script = bscript.fromASM(f.asm) const chunks = bscript.decompile(script) @@ -71,26 +71,26 @@ describe('script', function () { }) }) - describe('toStack', function () { - fixtures.valid.forEach(function (f) { - it('returns ' + !!f.stack + ' for ' + f.asm, function () { + describe('toStack', () => { + fixtures.valid.forEach(f => { + it('returns ' + !!f.stack + ' for ' + f.asm, () => { if (!f.stack || !f.asm) return const script = bscript.fromASM(f.asm) const stack = bscript.toStack(script) - assert.deepEqual(stack.map(function (x) { + assert.deepStrictEqual(stack.map(x => { return x.toString('hex') }), f.stack) - assert.equal(bscript.toASM(bscript.compile(stack)), f.asm, 'should rebuild same script from stack') + assert.strictEqual(bscript.toASM(bscript.compile(stack)), f.asm, 'should rebuild same script from stack') }) }) }) - describe('compile (via fromASM)', function () { - fixtures.valid.forEach(function (f) { - it('(' + f.type + ') compiles ' + f.asm, function () { + describe('compile (via fromASM)', () => { + fixtures.valid.forEach(f => { + it('(' + f.type + ') compiles ' + f.asm, () => { const scriptSig = bscript.fromASM(f.asm) assert.strictEqual(scriptSig.toString('hex'), f.script) @@ -104,9 +104,9 @@ describe('script', function () { }) }) - describe('decompile', function () { - fixtures.valid.forEach(function (f) { - it('decompiles ' + f.asm, function () { + describe('decompile', () => { + fixtures.valid.forEach(f => { + it('decompiles ' + f.asm, () => { const chunks = bscript.decompile(Buffer.from(f.script, 'hex')) assert.strictEqual(bscript.compile(chunks).toString('hex'), f.script) @@ -123,8 +123,8 @@ describe('script', function () { }) }) - fixtures.invalid.decompile.forEach(function (f) { - it('fails to decompile ' + f.script + ', because "' + f.description + '"', function () { + fixtures.invalid.decompile.forEach(f => { + it('fails to decompile ' + f.script + ', because "' + f.description + '"', () => { const chunks = bscript.decompile(Buffer.from(f.script, 'hex')) assert.strictEqual(chunks, null) @@ -132,9 +132,9 @@ describe('script', function () { }) }) - describe('SCRIPT_VERIFY_MINIMALDATA policy', function () { - fixtures.valid.forEach(function (f) { - it('compliant for ' + f.type + ' scriptSig ' + f.asm, function () { + describe('SCRIPT_VERIFY_MINIMALDATA policy', () => { + fixtures.valid.forEach(f => { + it('compliant for ' + f.type + ' scriptSig ' + f.asm, () => { const script = Buffer.from(f.script, 'hex') assert(minimalData(script)) @@ -142,7 +142,7 @@ describe('script', function () { }) function testEncodingForSize (i) { - it('compliant for data PUSH of length ' + i, function () { + it('compliant for data PUSH of length ' + i, () => { const buffer = Buffer.alloc(i) const script = bscript.compile([buffer]) diff --git a/test/script_number.js b/test/script_number.js index bc8f395..d5b97e2 100644 --- a/test/script_number.js +++ b/test/script_number.js @@ -3,10 +3,10 @@ const assert = require('assert') const scriptNumber = require('../src/script_number') const fixtures = require('./fixtures/script_number.json') -describe('script-number', function () { - describe('decode', function () { - fixtures.forEach(function (f) { - it(f.hex + ' returns ' + f.number, function () { +describe('script-number', () => { + describe('decode', () => { + fixtures.forEach(f => { + it(f.hex + ' returns ' + f.number, () => { const actual = scriptNumber.decode(Buffer.from(f.hex, 'hex'), f.bytes) assert.strictEqual(actual, f.number) @@ -14,9 +14,9 @@ describe('script-number', function () { }) }) - describe('encode', function () { - fixtures.forEach(function (f) { - it(f.number + ' returns ' + f.hex, function () { + describe('encode', () => { + fixtures.forEach(f => { + it(f.number + ' returns ' + f.hex, () => { const actual = scriptNumber.encode(f.number) assert.strictEqual(actual.toString('hex'), f.hex) diff --git a/test/script_signature.js b/test/script_signature.js index cee69bd..6888ca5 100644 --- a/test/script_signature.js +++ b/test/script_signature.js @@ -4,7 +4,7 @@ const bscriptSig = require('../src/script').signature const Buffer = require('safe-buffer').Buffer const fixtures = require('./fixtures/signature.json') -describe('Script Signatures', function () { +describe('Script Signatures', () => { function fromRaw (signature) { return Buffer.concat([ Buffer.from(signature.r, 'hex'), @@ -19,43 +19,43 @@ describe('Script Signatures', function () { } } - describe('encode', function () { - fixtures.valid.forEach(function (f) { - it('encodes ' + f.hex, function () { + describe('encode', () => { + fixtures.valid.forEach(f => { + it('encodes ' + f.hex, () => { const buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType) assert.strictEqual(buffer.toString('hex'), f.hex) }) }) - fixtures.invalid.forEach(function (f) { + fixtures.invalid.forEach(f => { if (!f.raw) return - it('throws ' + f.exception, function () { + it('throws ' + f.exception, () => { const signature = fromRaw(f.raw) - assert.throws(function () { + assert.throws(() => { bscriptSig.encode(signature, f.hashType) }, new RegExp(f.exception)) }) }) }) - describe('decode', function () { - fixtures.valid.forEach(function (f) { - it('decodes ' + f.hex, function () { + describe('decode', () => { + fixtures.valid.forEach(f => { + it('decodes ' + f.hex, () => { const decode = bscriptSig.decode(Buffer.from(f.hex, 'hex')) - assert.deepEqual(toRaw(decode.signature), f.raw) + assert.deepStrictEqual(toRaw(decode.signature), f.raw) assert.strictEqual(decode.hashType, f.hashType) }) }) - fixtures.invalid.forEach(function (f) { - it('throws on ' + f.hex, function () { + fixtures.invalid.forEach(f => { + it('throws on ' + f.hex, () => { const buffer = Buffer.from(f.hex, 'hex') - assert.throws(function () { + assert.throws(() => { bscriptSig.decode(buffer) }, new RegExp(f.exception)) }) diff --git a/test/transaction.js b/test/transaction.js index d923ce2..3fa9243 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -4,13 +4,13 @@ const bscript = require('../src/script') const fixtures = require('./fixtures/transaction') const Transaction = require('..').Transaction -describe('Transaction', function () { +describe('Transaction', () => { function fromRaw (raw, noWitness) { const tx = new Transaction() tx.version = raw.version tx.locktime = raw.locktime - raw.ins.forEach(function (txIn, i) { + raw.ins.forEach((txIn, i) => { const txHash = Buffer.from(txIn.hash, 'hex') let scriptSig @@ -23,7 +23,7 @@ describe('Transaction', function () { tx.addInput(txHash, txIn.index, txIn.sequence, scriptSig) if (!noWitness && txIn.witness) { - const witness = txIn.witness.map(function (x) { + const witness = txIn.witness.map(x => { return Buffer.from(x, 'hex') }) @@ -31,7 +31,7 @@ describe('Transaction', function () { } }) - raw.outs.forEach(function (txOut) { + raw.outs.forEach(txOut => { let script if (txOut.data) { @@ -46,19 +46,19 @@ describe('Transaction', function () { return tx } - describe('fromBuffer/fromHex', function () { + describe('fromBuffer/fromHex', () => { function importExport (f) { const id = f.id || f.hash const txHex = f.hex || f.txHex - it('imports ' + f.description + ' (' + id + ')', function () { + it('imports ' + f.description + ' (' + id + ')', () => { const actual = Transaction.fromHex(txHex) assert.strictEqual(actual.toHex(), txHex) }) if (f.whex) { - it('imports ' + f.description + ' (' + id + ') as witness', function () { + it('imports ' + f.description + ' (' + id + ') as witness', () => { const actual = Transaction.fromHex(f.whex) assert.strictEqual(actual.toHex(), f.whex) @@ -70,38 +70,38 @@ describe('Transaction', function () { fixtures.hashForSignature.forEach(importExport) fixtures.hashForWitnessV0.forEach(importExport) - fixtures.invalid.fromBuffer.forEach(function (f) { - it('throws on ' + f.exception, function () { - assert.throws(function () { + fixtures.invalid.fromBuffer.forEach(f => { + it('throws on ' + f.exception, () => { + assert.throws(() => { Transaction.fromHex(f.hex) }, new RegExp(f.exception)) }) }) - it('.version should be interpreted as an int32le', function () { + it('.version should be interpreted as an int32le', () => { const txHex = 'ffffffff0000ffffffff' const tx = Transaction.fromHex(txHex) - assert.equal(-1, tx.version) - assert.equal(0xffffffff, tx.locktime) + assert.strictEqual(-1, tx.version) + assert.strictEqual(0xffffffff, tx.locktime) }) }) - describe('toBuffer/toHex', function () { - fixtures.valid.forEach(function (f) { - it('exports ' + f.description + ' (' + f.id + ')', function () { + describe('toBuffer/toHex', () => { + fixtures.valid.forEach(f => { + it('exports ' + f.description + ' (' + f.id + ')', () => { const actual = fromRaw(f.raw, true) assert.strictEqual(actual.toHex(), f.hex) }) if (f.whex) { - it('exports ' + f.description + ' (' + f.id + ') as witness', function () { + it('exports ' + f.description + ' (' + f.id + ') as witness', () => { const wactual = fromRaw(f.raw) assert.strictEqual(wactual.toHex(), f.whex) }) } }) - it('accepts target Buffer and offset parameters', function () { + it('accepts target Buffer and offset parameters', () => { const f = fixtures.valid[0] const actual = fromRaw(f.raw) const byteLength = actual.byteLength() @@ -114,31 +114,31 @@ describe('Transaction', function () { assert.strictEqual(b.length, byteLength) assert.strictEqual(a.toString('hex'), f.hex) assert.strictEqual(b.toString('hex'), f.hex) - assert.deepEqual(a, b) - assert.deepEqual(a, target.slice(0, byteLength)) - assert.deepEqual(b, target.slice(byteLength)) + assert.deepStrictEqual(a, b) + assert.deepStrictEqual(a, target.slice(0, byteLength)) + assert.deepStrictEqual(b, target.slice(byteLength)) }) }) - describe('hasWitnesses', function () { - fixtures.valid.forEach(function (f) { - it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), function () { + describe('hasWitnesses', () => { + fixtures.valid.forEach(f => { + it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), () => { assert.strictEqual(Transaction.fromHex(f.whex ? f.whex : f.hex).hasWitnesses(), !!f.whex) }) }) }) - describe('weight/virtualSize', function () { - it('computes virtual size', function () { - fixtures.valid.forEach(function (f) { + describe('weight/virtualSize', () => { + it('computes virtual size', () => { + fixtures.valid.forEach(f => { const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex) assert.strictEqual(transaction.virtualSize(), f.virtualSize) }) }) - it('computes weight', function () { - fixtures.valid.forEach(function (f) { + it('computes weight', () => { + fixtures.valid.forEach(f => { const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex) assert.strictEqual(transaction.weight(), f.weight) @@ -146,19 +146,19 @@ describe('Transaction', function () { }) }) - describe('addInput', function () { + describe('addInput', () => { let prevTxHash - beforeEach(function () { + beforeEach(() => { prevTxHash = Buffer.from('ffffffff00ffff000000000000000000000000000000000000000000101010ff', 'hex') }) - it('returns an index', function () { + it('returns an index', () => { const tx = new Transaction() assert.strictEqual(tx.addInput(prevTxHash, 0), 0) assert.strictEqual(tx.addInput(prevTxHash, 0), 1) }) - it('defaults to empty script, witness and 0xffffffff SEQUENCE number', function () { + it('defaults to empty script, witness and 0xffffffff SEQUENCE number', () => { const tx = new Transaction() tx.addInput(prevTxHash, 0) @@ -167,49 +167,49 @@ describe('Transaction', function () { assert.strictEqual(tx.ins[0].sequence, 0xffffffff) }) - fixtures.invalid.addInput.forEach(function (f) { - it('throws on ' + f.exception, function () { + fixtures.invalid.addInput.forEach(f => { + it('throws on ' + f.exception, () => { const tx = new Transaction() const hash = Buffer.from(f.hash, 'hex') - assert.throws(function () { + assert.throws(() => { tx.addInput(hash, f.index) }, new RegExp(f.exception)) }) }) }) - describe('addOutput', function () { - it('returns an index', function () { + describe('addOutput', () => { + it('returns an index', () => { const tx = new Transaction() assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 0) assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 1) }) }) - describe('clone', function () { - fixtures.valid.forEach(function (f) { + describe('clone', () => { + fixtures.valid.forEach(f => { let actual let expected - beforeEach(function () { + beforeEach(() => { expected = Transaction.fromHex(f.hex) actual = expected.clone() }) - it('should have value equality', function () { - assert.deepEqual(actual, expected) + it('should have value equality', () => { + assert.deepStrictEqual(actual, expected) }) - it('should not have reference equality', function () { - assert.notEqual(actual, expected) + it('should not have reference equality', () => { + assert.notStrictEqual(actual, expected) }) }) }) - describe('getHash/getId', function () { + describe('getHash/getId', () => { function verify (f) { - it('should return the id for ' + f.id + '(' + f.description + ')', function () { + it('should return the id for ' + f.id + '(' + f.description + ')', () => { const tx = Transaction.fromHex(f.whex || f.hex) assert.strictEqual(tx.getHash().toString('hex'), f.hash) @@ -220,9 +220,9 @@ describe('Transaction', function () { fixtures.valid.forEach(verify) }) - describe('isCoinbase', function () { + describe('isCoinbase', () => { function verify (f) { - it('should return ' + f.coinbase + ' for ' + f.id + '(' + f.description + ')', function () { + it('should return ' + f.coinbase + ' for ' + f.id + '(' + f.description + ')', () => { const tx = Transaction.fromHex(f.hex) assert.strictEqual(tx.isCoinbase(), f.coinbase) @@ -232,8 +232,8 @@ describe('Transaction', function () { fixtures.valid.forEach(verify) }) - describe('hashForSignature', function () { - it('does not use Witness serialization', function () { + describe('hashForSignature', () => { + it('does not use Witness serialization', () => { const randScript = Buffer.from('6a', 'hex') const tx = new Transaction() @@ -241,24 +241,24 @@ describe('Transaction', function () { tx.addOutput(randScript, 5000000000) const original = tx.__toBuffer - tx.__toBuffer = function (a, b, c) { + tx.__toBuffer = (a, b, c) => { if (c !== false) throw new Error('hashForSignature MUST pass false') return original.call(this, a, b, c) } - assert.throws(function () { + assert.throws(() => { tx.__toBuffer(undefined, undefined, true) }, /hashForSignature MUST pass false/) // assert hashForSignature does not pass false - assert.doesNotThrow(function () { + assert.doesNotThrow(() => { tx.hashForSignature(0, randScript, 1) }) }) - fixtures.hashForSignature.forEach(function (f) { - it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : f.script), function () { + fixtures.hashForSignature.forEach(f => { + it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : f.script), () => { const tx = Transaction.fromHex(f.txHex) const script = bscript.fromASM(f.script) @@ -267,9 +267,9 @@ describe('Transaction', function () { }) }) - describe('hashForWitnessV0', function () { - fixtures.hashForWitnessV0.forEach(function (f) { - it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : ''), function () { + describe('hashForWitnessV0', () => { + fixtures.hashForWitnessV0.forEach(f => { + it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : ''), () => { const tx = Transaction.fromHex(f.txHex) const script = bscript.fromASM(f.script) @@ -278,9 +278,9 @@ describe('Transaction', function () { }) }) - describe('setWitness', function () { - it('only accepts a a witness stack (Array of Buffers)', function () { - assert.throws(function () { + describe('setWitness', () => { + it('only accepts a a witness stack (Array of Buffers)', () => { + assert.throws(() => { (new Transaction()).setWitness(0, 'foobar') }, /Expected property "1" of type \[Buffer], got String "foobar"/) }) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 3f84b19..28aa545 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -15,9 +15,9 @@ function constructSign (f, txb) { const network = NETWORKS[f.network] const stages = f.stages && f.stages.concat() - f.inputs.forEach(function (input, index) { + f.inputs.forEach((input, index) => { if (!input.signs) return - input.signs.forEach(function (sign) { + input.signs.forEach(sign => { const keyPair = ECPair.fromWIF(sign.keyPair, network) let redeemScript let witnessScript @@ -55,7 +55,7 @@ function construct (f, dontSign) { if (Number.isFinite(f.version)) txb.setVersion(f.version) if (f.locktime !== undefined) txb.setLockTime(f.locktime) - f.inputs.forEach(function (input) { + f.inputs.forEach(input => { let prevTx if (input.txRaw) { const constructed = construct(input.txRaw) @@ -75,7 +75,7 @@ function construct (f, dontSign) { txb.addInput(prevTx, input.vout, input.sequence, prevTxScript) }) - f.outputs.forEach(function (output) { + f.outputs.forEach(output => { if (output.address) { txb.addOutput(output.address, output.value) } else { @@ -87,20 +87,20 @@ function construct (f, dontSign) { return constructSign(f, txb) } -describe('TransactionBuilder', function () { +describe('TransactionBuilder', () => { // constants const keyPair = ECPair.fromPrivateKey(Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex')) const scripts = [ '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', '1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP' - ].map(function (x) { + ].map(x => { return baddress.toOutputScript(x) }) const txHash = Buffer.from('0e7cea811c0be9f73c0aca591034396e7264473fc25c1ca45195d7417b36cbe2', 'hex') - describe('fromTransaction', function () { - fixtures.valid.build.forEach(function (f) { - it('returns TransactionBuilder, with ' + f.description, function () { + describe('fromTransaction', () => { + fixtures.valid.build.forEach(f => { + it('returns TransactionBuilder, with ' + f.description, () => { const network = NETWORKS[f.network || 'bitcoin'] const tx = Transaction.fromHex(f.txHex) @@ -112,82 +112,82 @@ describe('TransactionBuilder', function () { }) }) - fixtures.valid.fromTransaction.forEach(function (f) { - it('returns TransactionBuilder, with ' + f.description, function () { + fixtures.valid.fromTransaction.forEach(f => { + it('returns TransactionBuilder, with ' + f.description, () => { const tx = new Transaction() - f.inputs.forEach(function (input) { + f.inputs.forEach(input => { const txHash2 = Buffer.from(input.txId, 'hex').reverse() tx.addInput(txHash2, input.vout, undefined, bscript.fromASM(input.scriptSig)) }) - f.outputs.forEach(function (output) { + f.outputs.forEach(output => { tx.addOutput(bscript.fromASM(output.script), output.value) }) const txb = TransactionBuilder.fromTransaction(tx) const txAfter = f.incomplete ? txb.buildIncomplete() : txb.build() - txAfter.ins.forEach(function (input, i) { - assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter) + txAfter.ins.forEach((input, i) => { + assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSigAfter) }) - txAfter.outs.forEach(function (output, i) { - assert.equal(bscript.toASM(output.script), f.outputs[i].script) + txAfter.outs.forEach((output, i) => { + assert.strictEqual(bscript.toASM(output.script), f.outputs[i].script) }) }) }) - fixtures.valid.fromTransactionSequential.forEach(function (f) { - it('with ' + f.description, function () { + fixtures.valid.fromTransactionSequential.forEach(f => { + it('with ' + f.description, () => { const network = NETWORKS[f.network] const tx = Transaction.fromHex(f.txHex) const txb = TransactionBuilder.fromTransaction(tx, network) - tx.ins.forEach(function (input, i) { - assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSig) + tx.ins.forEach((input, i) => { + assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSig) }) constructSign(f, txb) const txAfter = f.incomplete ? txb.buildIncomplete() : txb.build() - txAfter.ins.forEach(function (input, i) { - assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter) + txAfter.ins.forEach((input, i) => { + assert.strictEqual(bscript.toASM(input.script), f.inputs[i].scriptSigAfter) }) - assert.equal(txAfter.toHex(), f.txHexAfter) + assert.strictEqual(txAfter.toHex(), f.txHexAfter) }) }) - it('classifies transaction inputs', function () { + it('classifies transaction inputs', () => { const tx = Transaction.fromHex(fixtures.valid.classification.hex) const txb = TransactionBuilder.fromTransaction(tx) - txb.__INPUTS.forEach(function (i) { + txb.__INPUTS.forEach(i => { assert.strictEqual(i.prevOutType, 'scripthash') assert.strictEqual(i.redeemScriptType, 'multisig') }) }) - fixtures.invalid.fromTransaction.forEach(function (f) { - it('throws ' + f.exception, function () { + fixtures.invalid.fromTransaction.forEach(f => { + it('throws ' + f.exception, () => { const tx = Transaction.fromHex(f.txHex) - assert.throws(function () { + assert.throws(() => { TransactionBuilder.fromTransaction(tx) }, new RegExp(f.exception)) }) }) }) - describe('addInput', function () { + describe('addInput', () => { let txb - beforeEach(function () { + beforeEach(() => { txb = new TransactionBuilder() }) - it('accepts a txHash, index [and sequence number]', function () { + it('accepts a txHash, index [and sequence number]', () => { const vin = txb.addInput(txHash, 1, 54) assert.strictEqual(vin, 0) @@ -198,7 +198,7 @@ describe('TransactionBuilder', function () { assert.strictEqual(txb.__INPUTS[0].prevOutScript, undefined) }) - it('accepts a txHash, index [, sequence number and scriptPubKey]', function () { + it('accepts a txHash, index [, sequence number and scriptPubKey]', () => { const vin = txb.addInput(txHash, 1, 54, scripts[1]) assert.strictEqual(vin, 0) @@ -209,7 +209,7 @@ describe('TransactionBuilder', function () { assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1]) }) - it('accepts a prevTx, index [and sequence number]', function () { + it('accepts a prevTx, index [and sequence number]', () => { const prevTx = new Transaction() prevTx.addOutput(scripts[0], 0) prevTx.addOutput(scripts[1], 1) @@ -218,116 +218,116 @@ describe('TransactionBuilder', function () { assert.strictEqual(vin, 0) const txIn = txb.__TX.ins[0] - assert.deepEqual(txIn.hash, prevTx.getHash()) + assert.deepStrictEqual(txIn.hash, prevTx.getHash()) assert.strictEqual(txIn.index, 1) assert.strictEqual(txIn.sequence, 54) assert.strictEqual(txb.__INPUTS[0].prevOutScript, scripts[1]) }) - it('returns the input index', function () { + it('returns the input index', () => { assert.strictEqual(txb.addInput(txHash, 0), 0) assert.strictEqual(txb.addInput(txHash, 1), 1) }) - it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { + it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', () => { txb.addInput(txHash, 0) txb.addOutput(scripts[0], 1000) txb.sign(0, keyPair) - assert.throws(function () { + assert.throws(() => { txb.addInput(txHash, 0) }, /No, this would invalidate signatures/) }) }) - describe('addOutput', function () { + describe('addOutput', () => { let txb - beforeEach(function () { + beforeEach(() => { txb = new TransactionBuilder() }) - it('accepts an address string and value', function () { + it('accepts an address string and value', () => { const { address } = payments.p2pkh({ pubkey: keyPair.publicKey }) const vout = txb.addOutput(address, 1000) assert.strictEqual(vout, 0) const txout = txb.__TX.outs[0] - assert.deepEqual(txout.script, scripts[0]) + assert.deepStrictEqual(txout.script, scripts[0]) assert.strictEqual(txout.value, 1000) }) - it('accepts a ScriptPubKey and value', function () { + it('accepts a ScriptPubKey and value', () => { const vout = txb.addOutput(scripts[0], 1000) assert.strictEqual(vout, 0) const txout = txb.__TX.outs[0] - assert.deepEqual(txout.script, scripts[0]) + assert.deepStrictEqual(txout.script, scripts[0]) assert.strictEqual(txout.value, 1000) }) - it('throws if address is of the wrong network', function () { - assert.throws(function () { + it('throws if address is of the wrong network', () => { + assert.throws(() => { txb.addOutput('2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9', 1000) }, /2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9 has no matching Script/) }) - it('add second output after signed first input with SIGHASH_NONE', function () { + it('add second output after signed first input with SIGHASH_NONE', () => { txb.addInput(txHash, 0) txb.addOutput(scripts[0], 2000) txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE) - assert.equal(txb.addOutput(scripts[1], 9000), 1) + assert.strictEqual(txb.addOutput(scripts[1], 9000), 1) }) - it('add first output after signed first input with SIGHASH_NONE', function () { + it('add first output after signed first input with SIGHASH_NONE', () => { txb.addInput(txHash, 0) txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE) - assert.equal(txb.addOutput(scripts[0], 2000), 0) + assert.strictEqual(txb.addOutput(scripts[0], 2000), 0) }) - it('add second output after signed first input with SIGHASH_SINGLE', function () { + it('add second output after signed first input with SIGHASH_SINGLE', () => { txb.addInput(txHash, 0) txb.addOutput(scripts[0], 2000) txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE) - assert.equal(txb.addOutput(scripts[1], 9000), 1) + assert.strictEqual(txb.addOutput(scripts[1], 9000), 1) }) - it('add first output after signed first input with SIGHASH_SINGLE', function () { + it('add first output after signed first input with SIGHASH_SINGLE', () => { txb.addInput(txHash, 0) txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE) - assert.throws(function () { + assert.throws(() => { txb.addOutput(scripts[0], 2000) }, /No, this would invalidate signatures/) }) - it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { + it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', () => { txb.addInput(txHash, 0) txb.addOutput(scripts[0], 2000) txb.sign(0, keyPair) - assert.throws(function () { + assert.throws(() => { txb.addOutput(scripts[1], 9000) }, /No, this would invalidate signatures/) }) }) - describe('setLockTime', function () { - it('throws if if there exist any scriptSigs', function () { + describe('setLockTime', () => { + it('throws if if there exist any scriptSigs', () => { const txb = new TransactionBuilder() txb.addInput(txHash, 0) txb.addOutput(scripts[0], 100) txb.sign(0, keyPair) - assert.throws(function () { + assert.throws(() => { txb.setLockTime(65535) }, /No, this would invalidate signatures/) }) }) - describe('sign', function () { - it('supports the alternative abstract interface { publicKey, sign }', function () { + describe('sign', () => { + it('supports the alternative abstract interface { publicKey, sign }', () => { const keyPair = { - publicKey: ECPair.makeRandom({ rng: function () { return Buffer.alloc(32, 1) } }).publicKey, - sign: function (hash) { return Buffer.alloc(64, 0x5f) } + publicKey: ECPair.makeRandom({ rng: () => { return Buffer.alloc(32, 1) } }).publicKey, + sign: hash => { return Buffer.alloc(64, 0x5f) } } const txb = new TransactionBuilder() @@ -335,16 +335,16 @@ describe('TransactionBuilder', function () { txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1) txb.addOutput('1111111111111111111114oLvT2', 100000) txb.sign(0, keyPair) - assert.equal(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f02205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078fffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') + assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f02205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078fffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') }) - fixtures.invalid.sign.forEach(function (f) { - it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), function () { + fixtures.invalid.sign.forEach(f => { + it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), () => { const txb = construct(f, true) let threw = false - f.inputs.forEach(function (input, index) { - input.signs.forEach(function (sign) { + f.inputs.forEach((input, index) => { + input.signs.forEach(sign => { const keyPairNetwork = NETWORKS[sign.network || f.network] const keyPair2 = ECPair.fromWIF(sign.keyPair, keyPairNetwork) let redeemScript @@ -359,7 +359,7 @@ describe('TransactionBuilder', function () { } if (sign.throws) { - assert.throws(function () { + assert.throws(() => { txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript) }, new RegExp(f.exception)) threw = true @@ -369,14 +369,14 @@ describe('TransactionBuilder', function () { }) }) - assert.equal(threw, true) + assert.strictEqual(threw, true) }) }) }) - describe('build', function () { - fixtures.valid.build.forEach(function (f) { - it('builds "' + f.description + '"', function () { + describe('build', () => { + fixtures.valid.build.forEach(f => { + it('builds "' + f.description + '"', () => { const txb = construct(f) const tx = f.incomplete ? txb.buildIncomplete() : txb.build() @@ -385,10 +385,10 @@ describe('TransactionBuilder', function () { }) // TODO: remove duplicate test code - fixtures.invalid.build.forEach(function (f) { - describe('for ' + (f.description || f.exception), function () { - it('throws ' + f.exception, function () { - assert.throws(function () { + fixtures.invalid.build.forEach(f => { + describe('for ' + (f.description || f.exception), () => { + it('throws ' + f.exception, () => { + assert.throws(() => { let txb if (f.txHex) { txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex)) @@ -402,8 +402,8 @@ describe('TransactionBuilder', function () { // if throws on incomplete too, enforce that if (f.incomplete) { - it('throws ' + f.exception, function () { - assert.throws(function () { + it('throws ' + f.exception, () => { + assert.throws(() => { let txb if (f.txHex) { txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex)) @@ -415,7 +415,7 @@ describe('TransactionBuilder', function () { }, new RegExp(f.exception)) }) } else { - it('does not throw if buildIncomplete', function () { + it('does not throw if buildIncomplete', () => { let txb if (f.txHex) { txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex)) @@ -429,7 +429,7 @@ describe('TransactionBuilder', function () { }) }) - it('for incomplete with 0 signatures', function () { + it('for incomplete with 0 signatures', () => { const randomTxData = '0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000' const randomAddress = '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH' @@ -441,7 +441,7 @@ describe('TransactionBuilder', function () { assert(tx) }) - it('for incomplete P2SH with 0 signatures', function () { + it('for incomplete P2SH with 0 signatures', () => { const inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000017a91471a8ec07ff69c6c4fee489184c462a9b1b9237488700000000', 'hex') // arbitrary P2SH input const inpTx = Transaction.fromBuffer(inp) @@ -452,7 +452,7 @@ describe('TransactionBuilder', function () { txb.buildIncomplete() }) - it('for incomplete P2WPKH with 0 signatures', function () { + it('for incomplete P2WPKH with 0 signatures', () => { const inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a8040000001600141a15805e1f4040c9f68ccc887fca2e63547d794b00000000', 'hex') const inpTx = Transaction.fromBuffer(inp) @@ -463,7 +463,7 @@ describe('TransactionBuilder', function () { txb.buildIncomplete() }) - it('for incomplete P2WSH with 0 signatures', function () { + it('for incomplete P2WSH with 0 signatures', () => { const inpTx = Transaction.fromBuffer(Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000022002072df76fcc0b231b94bdf7d8c25d7eef4716597818d211e19ade7813bff7a250200000000', 'hex')) const txb = new TransactionBuilder(NETWORKS.testnet) @@ -474,17 +474,17 @@ describe('TransactionBuilder', function () { }) }) - describe('multisig', function () { - fixtures.valid.multisig.forEach(function (f) { - it(f.description, function () { + describe('multisig', () => { + fixtures.valid.multisig.forEach(f => { + it(f.description, () => { const network = NETWORKS[f.network] let txb = construct(f, true) let tx - f.inputs.forEach(function (input, i) { + f.inputs.forEach((input, i) => { const redeemScript = bscript.fromASM(input.redeemScript) - input.signs.forEach(function (sign) { + input.signs.forEach(sign => { // rebuild the transaction each-time after the first if (tx) { // manually override the scriptSig? @@ -513,10 +513,10 @@ describe('TransactionBuilder', function () { }) }) - describe('various edge case', function () { + describe('various edge case', () => { const network = NETWORKS.testnet - it('should warn of high fee for segwit transaction based on VSize, not Size', function () { + it('should warn of high fee for segwit transaction based on VSize, not Size', () => { const rawtx = '01000000000104fdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a' + '1df90000000000fffffffffdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a1df9' + '0100000000ffffffffa2ef7aaab316a3e5b5b0a78d1d35c774b95a079f9f0c762277a49caf1f26bca40000' + @@ -538,12 +538,12 @@ describe('TransactionBuilder', function () { txb.__INPUTS[2].value = 248920 txb.__INPUTS[3].value = 248920 - assert.throws(function () { + assert.throws(() => { txb.build() }, new RegExp('Transaction has absurd fees')) }) - it('should classify witness inputs with witness = true during multisigning', function () { + it('should classify witness inputs with witness = true during multisigning', () => { const keyPair = ECPair.fromWIF('cRAwuVuVSBZMPu7hdrYvMCZ8eevzmkExjFbaBLhqnDdrezxN3nTS', network) const witnessScript = Buffer.from('522102bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e22102d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea1952ae', 'hex') const redeemScript = Buffer.from('002024376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af', 'hex') @@ -558,13 +558,13 @@ describe('TransactionBuilder', function () { const tx = txb.buildIncomplete() // Only input is segwit, so txid should be accurate with the final tx - assert.equal(tx.getId(), 'f15d0a65b21b4471405b21a099f8b18e1ae4d46d55efbd0f4766cf11ad6cb821') + assert.strictEqual(tx.getId(), 'f15d0a65b21b4471405b21a099f8b18e1ae4d46d55efbd0f4766cf11ad6cb821') const txHex = tx.toHex() TransactionBuilder.fromTransaction(Transaction.fromHex(txHex)) }) - it('should handle badly pre-filled OP_0s', function () { + it('should handle badly pre-filled OP_0s', () => { // OP_0 is used where a signature is missing const redeemScripSig = bscript.fromASM('OP_0 OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae') const redeemScript = bscript.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG') @@ -580,11 +580,11 @@ describe('TransactionBuilder', function () { txb.sign(0, keyPair2, redeemScript) const tx2 = txb.build() - assert.equal(tx2.getId(), 'eab59618a564e361adef6d918bd792903c3d41bcf1220137364fb847880467f9') - assert.equal(bscript.toASM(tx2.ins[0].script), 'OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae') + assert.strictEqual(tx2.getId(), 'eab59618a564e361adef6d918bd792903c3d41bcf1220137364fb847880467f9') + assert.strictEqual(bscript.toASM(tx2.ins[0].script), 'OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae') }) - it('should not classify blank scripts as nonstandard', function () { + it('should not classify blank scripts as nonstandard', () => { let txb = new TransactionBuilder() txb.setVersion(1) txb.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0) @@ -596,14 +596,14 @@ describe('TransactionBuilder', function () { txb.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) txb.sign(0, keyPair) const txId = txb.build().getId() - assert.equal(txId, '54f097315acbaedb92a95455da3368eb45981cdae5ffbc387a9afc872c0f29b3') + assert.strictEqual(txId, '54f097315acbaedb92a95455da3368eb45981cdae5ffbc387a9afc872c0f29b3') // and, repeat txb = TransactionBuilder.fromTransaction(Transaction.fromHex(incomplete)) txb.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) txb.sign(0, keyPair) const txId2 = txb.build().getId() - assert.equal(txId, txId2) + assert.strictEqual(txId, txId2) }) }) }) diff --git a/test/types.js b/test/types.js index d245d53..8911ca1 100644 --- a/test/types.js +++ b/test/types.js @@ -3,38 +3,38 @@ const assert = require('assert') const types = require('../src/types') const typeforce = require('typeforce') -describe('types', function () { - describe('Buffer Hash160/Hash256', function () { +describe('types', () => { + describe('Buffer Hash160/Hash256', () => { const buffer20byte = Buffer.alloc(20) const buffer32byte = Buffer.alloc(32) - it('return true for valid size', function () { + it('return true for valid size', () => { assert(types.Hash160bit(buffer20byte)) assert(types.Hash256bit(buffer32byte)) }) - it('return true for oneOf', function () { - assert.doesNotThrow(function () { + it('return true for oneOf', () => { + assert.doesNotThrow(() => { typeforce(types.oneOf(types.Hash160bit, types.Hash256bit), buffer32byte) }) - assert.doesNotThrow(function () { + assert.doesNotThrow(() => { typeforce(types.oneOf(types.Hash256bit, types.Hash160bit), buffer32byte) }) }) - it('throws for invalid size', function () { - assert.throws(function () { + it('throws for invalid size', () => { + assert.throws(() => { types.Hash160bit(buffer32byte) }, /Expected Buffer\(Length: 20\), got Buffer\(Length: 32\)/) - assert.throws(function () { + assert.throws(() => { types.Hash256bit(buffer20byte) }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 20\)/) }) }) - describe('Satoshi', function () { + describe('Satoshi', () => { [ { value: -1, result: false }, { value: 0, result: true }, @@ -42,8 +42,8 @@ describe('types', function () { { value: 20999999 * 1e8, result: true }, { value: 21000000 * 1e8, result: true }, { value: 21000001 * 1e8, result: false } - ].forEach(function (f) { - it('returns ' + f.result + ' for valid for ' + f.value, function () { + ].forEach(f => { + it('returns ' + f.result + ' for valid for ' + f.value, () => { assert.strictEqual(types.Satoshi(f.value), f.result) }) }) From c77db1a14f3b08de38a068f28cef13bfe70b865c Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 9 Apr 2019 15:19:05 +0900 Subject: [PATCH 167/183] Only run docker in integration with cache --- .travis.yml | 8 +++++--- test/integration/_regtest.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7921fac..bb87738 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,11 @@ language: node_js services: - docker before_install: - - docker pull junderw/bitcoinjs-regtest-server - - docker run -d -p 127.0.0.1:8080:8080 junderw/bitcoinjs-regtest-server - - docker ps -a + - if [ $TEST_SUITE = "integration" ]; then + docker pull junderw/bitcoinjs-regtest-server && + docker run -d -p 127.0.0.1:8080:8080 junderw/bitcoinjs-regtest-server && + docker ps -a; + fi node_js: - "8" - "lts/*" diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js index abfee1a..8be864a 100644 --- a/test/integration/_regtest.js +++ b/test/integration/_regtest.js @@ -71,7 +71,7 @@ async function faucet (address, value) { } ) - await sleep(randInt(50, 150)) + await sleep(randInt(10, 40)) const results = await unspents(address) From 329809fa4a10f1c9725c09d2f4e43e6b1860bf6d Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 11 Apr 2019 15:55:33 +0900 Subject: [PATCH 168/183] Fix address.*OutputScript and ECPairOptions rng --- ts_src/address.ts | 4 ++-- ts_src/ecpair.ts | 2 +- types/address.d.ts | 4 ++-- types/ecpair.d.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ts_src/address.ts b/ts_src/address.ts index 0c0cda5..ad791ad 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -64,7 +64,7 @@ export function toBech32( return bech32.encode(prefix, words); } -export function fromOutputScript(output: Buffer, network: Network): string { +export function fromOutputScript(output: Buffer, network?: Network): string { // TODO: Network network = network || networks.bitcoin; @@ -84,7 +84,7 @@ export function fromOutputScript(output: Buffer, network: Network): string { throw new Error(bscript.toASM(output) + ' has no matching Address'); } -export function toOutputScript(address: string, network: Network): Buffer { +export function toOutputScript(address: string, network?: Network): Buffer { network = network || networks.bitcoin; let decodeBase58: Base58CheckResult | undefined; diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 9e56919..3941afa 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -16,7 +16,7 @@ const isOptions = typeforce.maybe( interface ECPairOptions { compressed?: boolean; network?: Network; - rng?(arg0: Buffer): Buffer; + rng?(arg0: number): Buffer; } export interface ECPairInterface { diff --git a/types/address.d.ts b/types/address.d.ts index 1da68ac..be0e00a 100644 --- a/types/address.d.ts +++ b/types/address.d.ts @@ -13,5 +13,5 @@ export declare function fromBase58Check(address: string): Base58CheckResult; export declare function fromBech32(address: string): Bech32Result; export declare function toBase58Check(hash: Buffer, version: number): string; export declare function toBech32(data: Buffer, version: number, prefix: string): string; -export declare function fromOutputScript(output: Buffer, network: Network): string; -export declare function toOutputScript(address: string, network: Network): Buffer; +export declare function fromOutputScript(output: Buffer, network?: Network): string; +export declare function toOutputScript(address: string, network?: Network): Buffer; diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index 33535bd..a5ae716 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -3,7 +3,7 @@ import { Network } from './networks'; interface ECPairOptions { compressed?: boolean; network?: Network; - rng?(arg0: Buffer): Buffer; + rng?(arg0: number): Buffer; } export interface ECPairInterface { compressed: boolean; From f6f33595f6fdb319ef38ac6a5adc10259b4dad2b Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 11 Apr 2019 16:05:02 +0900 Subject: [PATCH 169/183] 5.0.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b57448e..f56a619 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.1", + "version": "5.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 10088cd..591e98a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.1", + "version": "5.0.2", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "types": "./types/index.d.ts", From 3b402d00c61fc50a290a8d3f6bfb3749b8c13e63 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 12 Apr 2019 17:44:55 +0900 Subject: [PATCH 170/183] Add low R grinding option --- src/ecpair.js | 19 +++++++++++++++++-- ts_src/ecpair.ts | 18 ++++++++++++++++-- types/ecpair.d.ts | 2 +- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/ecpair.js b/src/ecpair.js index 2026c63..6bb7eb9 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -35,10 +35,25 @@ class ECPair { throw new Error('Missing private key'); return wif.encode(this.network.wif, this.__D, this.compressed); } - sign(hash) { + sign(hash, lowR = false) { if (!this.__D) throw new Error('Missing private key'); - return ecc.sign(hash, this.__D); + if (lowR === false) { + return ecc.sign(hash, this.__D); + } + else { + let sig = ecc.sign(hash, this.__D); + const extraData = Buffer.alloc(32, 0); + let counter = 0; + // if first try is lowR, skip the loop + // for second try and on, add extra entropy counting up + while (sig[0] > 0x7f) { + counter++; + extraData.writeUIntLE(counter, 0, 6); + sig = ecc.signWithEntropy(hash, this.__D, extraData); + } + return sig; + } } verify(hash, signature) { return ecc.verify(hash, this.publicKey, signature); diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 3941afa..7245d0d 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -61,9 +61,23 @@ class ECPair implements ECPairInterface { return wif.encode(this.network.wif, this.__D, this.compressed); } - sign(hash: Buffer): Buffer { + sign(hash: Buffer, lowR: boolean = false): Buffer { if (!this.__D) throw new Error('Missing private key'); - return ecc.sign(hash, this.__D); + if (lowR === false) { + return ecc.sign(hash, this.__D); + } else { + let sig = ecc.sign(hash, this.__D); + const extraData = Buffer.alloc(32, 0); + let counter = 0; + // if first try is lowR, skip the loop + // for second try and on, add extra entropy counting up + while (sig[0] > 0x7f) { + counter++; + extraData.writeUIntLE(counter, 0, 6); + sig = ecc.signWithEntropy(hash, this.__D, extraData); + } + return sig; + } } verify(hash: Buffer, signature: Buffer): Buffer { diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index a5ae716..2f9bbc4 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -24,7 +24,7 @@ declare class ECPair implements ECPairInterface { readonly privateKey: Buffer | undefined; readonly publicKey: Buffer | undefined; toWIF(): string; - sign(hash: Buffer): Buffer; + sign(hash: Buffer, lowR?: boolean): Buffer; verify(hash: Buffer, signature: Buffer): Buffer; } declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair; From ccd439b80519a198326f077b24870b1027c01ba6 Mon Sep 17 00:00:00 2001 From: junderw Date: Fri, 12 Apr 2019 17:55:45 +0900 Subject: [PATCH 171/183] Modify interface --- ts_src/ecpair.ts | 2 +- types/ecpair.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 7245d0d..649aa37 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -25,7 +25,7 @@ export interface ECPairInterface { privateKey?: Buffer; publicKey?: Buffer; toWIF(): string; - sign(hash: Buffer): Buffer; + sign(hash: Buffer, lowR?: boolean): Buffer; verify(hash: Buffer, signature: Buffer): Buffer; getPublicKey?(): Buffer; } diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index 2f9bbc4..87ebff4 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -11,7 +11,7 @@ export interface ECPairInterface { privateKey?: Buffer; publicKey?: Buffer; toWIF(): string; - sign(hash: Buffer): Buffer; + sign(hash: Buffer, lowR?: boolean): Buffer; verify(hash: Buffer, signature: Buffer): Buffer; getPublicKey?(): Buffer; } From b5577607d4496a6774d9e1f126f312d634ca3b55 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 15 Apr 2019 15:28:01 +0900 Subject: [PATCH 172/183] Add tests for low R signing --- package-lock.json | 14 +++++++------- package.json | 2 +- test/ecpair.js | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index f56a619..8b225f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -731,9 +731,9 @@ "dev": true }, "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" }, "nyc": { "version": "13.3.0", @@ -1911,15 +1911,15 @@ } }, "tiny-secp256k1": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.0.1.tgz", - "integrity": "sha512-Wz2kMPWtCI5XBftFeF3bUL8uz2+VlasniKwOkRPjvL7h1QVd9rbhrve/HWUu747kJKzVf1XHonzcdM4Ut8fvww==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.0.tgz", + "integrity": "sha512-DIl0SCUIVcPrk/oOiq8/YgQ69Beayw4XSW2icyXJN8xfKMmxo5XM8gXVG1Ex+rYsHg2xuEpNFeeU6J4CtqQFrA==", "requires": { "bindings": "^1.3.0", "bn.js": "^4.11.8", "create-hmac": "^1.1.7", "elliptic": "^6.4.0", - "nan": "^2.10.0" + "nan": "^2.12.1" } }, "to-fast-properties": { diff --git a/package.json b/package.json index 591e98a..eff2d63 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "merkle-lib": "^2.0.10", "pushdata-bitcoin": "^1.0.1", "randombytes": "^2.0.1", - "tiny-secp256k1": "^1.0.0", + "tiny-secp256k1": "^1.1.0", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" diff --git a/test/ecpair.js b/test/ecpair.js index ce32683..e067ddd 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -259,4 +259,26 @@ describe('ECPair', () => { })) }) }) + describe('optional low R signing', () => { + const sig = Buffer.from('95a6619140fca3366f1d3b013b0367c4f86e39508a50fdce' + + 'e5245fbb8bd60aa6086449e28cf15387cf9f85100bfd0838624ca96759e59f65c10a00' + + '16b86f5229', 'hex') + const sigLowR = Buffer.from('6a2660c226e8055afad317eeba918a304be79208d505' + + '3bc5ea4a5e4c5892b4a061c717c5284ae5202d721c0e49b4717b79966280906b1d3b52' + + '95d1fdde963c35', 'hex') + const lowRKeyPair = ECPair.fromWIF('L3nThUzbAwpUiBAjR5zCu66ybXSPMr2zZ3ikp' + + 'ScpTPiYTxBynfZu') + const dataToSign = Buffer.from('b6c5c548a7f6164c8aa7af5350901626ebd69f9ae' + + '2c1ecf8871f5088ec204cfe', 'hex') + + it('signs with normal R by default', () => { + const signed = lowRKeyPair.sign(dataToSign) + assert.deepStrictEqual(sig, signed) + }) + + it('signs with low R when true is passed', () => { + const signed = lowRKeyPair.sign(dataToSign, true) + assert.deepStrictEqual(sigLowR, signed) + }) + }) }) From 352e9ef0a3a2be01f9c85a077d85563812890ed4 Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 15 Apr 2019 17:27:28 +0900 Subject: [PATCH 173/183] Add low R signing to TransactionBuilder --- src/transaction_builder.js | 11 ++++++++++- test/transaction_builder.js | 19 +++++++++++++++++++ ts_src/transaction_builder.ts | 13 ++++++++++++- types/transaction_builder.d.ts | 2 ++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index d3b2673..cf27404 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -29,6 +29,7 @@ class TransactionBuilder { this.__INPUTS = []; this.__TX = new transaction_1.Transaction(); this.__TX.version = 2; + this.__USE_LOW_R = false; } static fromTransaction(transaction, network) { const txb = new TransactionBuilder(network); @@ -53,6 +54,14 @@ class TransactionBuilder { }); return txb; } + setLowR(setting) { + typeforce(typeforce.maybe(typeforce.Boolean), setting); + if (setting === undefined) { + setting = true; + } + this.__USE_LOW_R = setting; + return setting; + } setLockTime(locktime) { typeforce(types.UInt32, locktime); // if any signatures exist, throw @@ -159,7 +168,7 @@ class TransactionBuilder { if (ourPubKey.length !== 33 && input.hasWitness) { throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH'); } - const signature = keyPair.sign(signatureHash); + const signature = keyPair.sign(signatureHash, this.__USE_LOW_R); input.signatures[i] = bscript.signature.encode(signature, hashType); return true; }); diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 28aa545..1af8272 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -338,6 +338,25 @@ describe('TransactionBuilder', () => { assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f02205f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078fffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') }) + it('supports low R signature signing', () => { + let txb = new TransactionBuilder() + txb.setVersion(1) + txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1) + txb.addOutput('1111111111111111111114oLvT2', 100000) + txb.sign(0, keyPair) + // high R + assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006b483045022100b872677f35c9c14ad9c41d83649fb049250f32574e0b2547d67e209ed14ff05d022059b36ad058be54e887a1a311d5c393cb4941f6b93a0b090845ec67094de8972b01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') + + txb = new TransactionBuilder() + txb.setVersion(1) + txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1) + txb.addOutput('1111111111111111111114oLvT2', 100000) + txb.setLowR() + txb.sign(0, keyPair) + // low R + assert.strictEqual(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a473044022012a601efa8756ebe83e9ac7a7db061c3147e3b49d8be67685799fe51a4c8c62f02204d568d301d5ce14af390d566d4fd50e7b8ee48e71ec67786c029e721194dae3601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000') + }) + fixtures.invalid.sign.forEach(f => { it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), () => { const txb = construct(f, true) diff --git a/ts_src/transaction_builder.ts b/ts_src/transaction_builder.ts index 6a49b3f..0665719 100644 --- a/ts_src/transaction_builder.ts +++ b/ts_src/transaction_builder.ts @@ -94,6 +94,7 @@ export class TransactionBuilder { private __PREV_TX_SET: { [index: string]: boolean }; private __INPUTS: TxbInput[]; private __TX: Transaction; + private __USE_LOW_R: boolean; // WARNING: maximumFeeRate is __NOT__ to be relied on, // it's just another potential safety mechanism (safety in-depth) @@ -105,6 +106,16 @@ export class TransactionBuilder { this.__INPUTS = []; this.__TX = new Transaction(); this.__TX.version = 2; + this.__USE_LOW_R = false; + } + + setLowR(setting?: boolean): boolean { + typeforce(typeforce.maybe(typeforce.Boolean), setting); + if (setting === undefined) { + setting = true; + } + this.__USE_LOW_R = setting; + return setting; } setLockTime(locktime: number): void { @@ -266,7 +277,7 @@ export class TransactionBuilder { ); } - const signature = keyPair.sign(signatureHash); + const signature = keyPair.sign(signatureHash, this.__USE_LOW_R); input.signatures![i] = bscript.signature.encode(signature, hashType!); return true; }); diff --git a/types/transaction_builder.d.ts b/types/transaction_builder.d.ts index 82c4ef0..f993807 100644 --- a/types/transaction_builder.d.ts +++ b/types/transaction_builder.d.ts @@ -9,7 +9,9 @@ export declare class TransactionBuilder { private __PREV_TX_SET; private __INPUTS; private __TX; + private __USE_LOW_R; constructor(network?: Network, maximumFeeRate?: number); + setLowR(setting?: boolean): boolean; setLockTime(locktime: number): void; setVersion(version: number): void; addInput(txHash: Buffer | string | Transaction, vout: number, sequence?: number, prevOutScript?: Buffer): number; From e28e04427e0ba072cf4af5b08300eaa45aadcfcd Mon Sep 17 00:00:00 2001 From: junderw Date: Sun, 21 Apr 2019 21:30:21 +0900 Subject: [PATCH 174/183] Use Prettier to make JS easier to read/audit --- package.json | 5 +- src/address.js | 145 +-- src/block.js | 444 +++---- src/bufferutils.js | 58 +- src/classify.js | 110 +- src/crypto.js | 39 +- src/ecpair.js | 149 ++- src/index.js | 26 +- src/networks.js | 58 +- src/payments/embed.js | 82 +- src/payments/index.js | 18 +- src/payments/lazy.js | 47 +- src/payments/p2ms.js | 254 ++-- src/payments/p2pk.js | 129 +- src/payments/p2pkh.js | 254 ++-- src/payments/p2sh.js | 329 +++-- src/payments/p2wpkh.js | 242 ++-- src/payments/p2wsh.js | 321 +++-- src/script.js | 264 ++-- src/script_number.js | 108 +- src/script_signature.js | 77 +- src/templates/multisig/index.js | 8 +- src/templates/multisig/input.js | 30 +- src/templates/multisig/output.js | 49 +- src/templates/nulldata.js | 12 +- src/templates/pubkey/index.js | 8 +- src/templates/pubkey/input.js | 13 +- src/templates/pubkey/output.js | 20 +- src/templates/pubkeyhash/index.js | 8 +- src/templates/pubkeyhash/input.js | 18 +- src/templates/pubkeyhash/output.js | 26 +- src/templates/scripthash/index.js | 8 +- src/templates/scripthash/input.js | 82 +- src/templates/scripthash/output.js | 22 +- src/templates/witnesscommitment/index.js | 6 +- src/templates/witnesscommitment/output.js | 38 +- src/templates/witnesspubkeyhash/index.js | 8 +- src/templates/witnesspubkeyhash/input.js | 20 +- src/templates/witnesspubkeyhash/output.js | 18 +- src/templates/witnessscripthash/index.js | 8 +- src/templates/witnessscripthash/input.js | 61 +- src/templates/witnessscripthash/output.js | 18 +- src/transaction.js | 882 ++++++------- src/transaction_builder.js | 1379 +++++++++++---------- src/types.js | 28 +- 45 files changed, 2964 insertions(+), 2965 deletions(-) diff --git a/package.json b/package.json index 591e98a..d9fe283 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,13 @@ "bitcoinjs" ], "scripts": { - "build": "tsc -p ./tsconfig.json", + "build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs", + "clean": "rm -rf src/", "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", "format": "npm run prettier -- --write", + "formatjs": "npm run prettierjs -- --write > /dev/null 2>&1", "format:ci": "npm run prettier -- --check", "gitdiff:ci": "npm run build && git diff --exit-code", "integration": "npm run build && npm run nobuild:integration", @@ -30,6 +32,7 @@ "nobuild:integration": "mocha --timeout 50000 test/integration/", "nobuild:unit": "mocha", "prettier": "prettier 'ts_src/**/*.ts' --ignore-path ./.prettierignore", + "prettierjs": "prettier 'src/**/*.js' --ignore-path ./.prettierignore", "test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage", "unit": "npm run build && npm run nobuild:unit" }, diff --git a/src/address.js b/src/address.js index b0be0e1..e15c55e 100644 --- a/src/address.js +++ b/src/address.js @@ -1,100 +1,91 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const networks = require("./networks"); -const payments = require("./payments"); -const bscript = require("./script"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const networks = require('./networks'); +const payments = require('./payments'); +const bscript = require('./script'); +const types = require('./types'); const bech32 = require('bech32'); const bs58check = require('bs58check'); const typeforce = require('typeforce'); function fromBase58Check(address) { - const payload = bs58check.decode(address); - // TODO: 4.0.0, move to "toOutputScript" - if (payload.length < 21) - throw new TypeError(address + ' is too short'); - if (payload.length > 21) - throw new TypeError(address + ' is too long'); - const version = payload.readUInt8(0); - const hash = payload.slice(1); - return { version, hash }; + const payload = bs58check.decode(address); + // TODO: 4.0.0, move to "toOutputScript" + if (payload.length < 21) throw new TypeError(address + ' is too short'); + if (payload.length > 21) throw new TypeError(address + ' is too long'); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; } exports.fromBase58Check = fromBase58Check; function fromBech32(address) { - const result = bech32.decode(address); - const data = bech32.fromWords(result.words.slice(1)); - return { - version: result.words[0], - prefix: result.prefix, - data: Buffer.from(data), - }; + const result = bech32.decode(address); + const data = bech32.fromWords(result.words.slice(1)); + return { + version: result.words[0], + prefix: result.prefix, + data: Buffer.from(data), + }; } exports.fromBech32 = fromBech32; function toBase58Check(hash, version) { - typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(version, 0); - hash.copy(payload, 1); - return bs58check.encode(payload); + typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(version, 0); + hash.copy(payload, 1); + return bs58check.encode(payload); } exports.toBase58Check = toBase58Check; function toBech32(data, version, prefix) { - const words = bech32.toWords(data); - words.unshift(version); - return bech32.encode(prefix, words); + const words = bech32.toWords(data); + words.unshift(version); + return bech32.encode(prefix, words); } exports.toBech32 = toBech32; function fromOutputScript(output, network) { - // TODO: Network - network = network || networks.bitcoin; - try { - return payments.p2pkh({ output, network }).address; - } - catch (e) { } - try { - return payments.p2sh({ output, network }).address; - } - catch (e) { } - try { - return payments.p2wpkh({ output, network }).address; - } - catch (e) { } - try { - return payments.p2wsh({ output, network }).address; - } - catch (e) { } - throw new Error(bscript.toASM(output) + ' has no matching Address'); + // TODO: Network + network = network || networks.bitcoin; + try { + return payments.p2pkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2sh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wpkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wsh({ output, network }).address; + } catch (e) {} + throw new Error(bscript.toASM(output) + ' has no matching Address'); } exports.fromOutputScript = fromOutputScript; function toOutputScript(address, network) { - network = network || networks.bitcoin; - let decodeBase58; - let decodeBech32; + network = network || networks.bitcoin; + let decodeBase58; + let decodeBech32; + try { + decodeBase58 = fromBase58Check(address); + } catch (e) {} + if (decodeBase58) { + if (decodeBase58.version === network.pubKeyHash) + return payments.p2pkh({ hash: decodeBase58.hash }).output; + if (decodeBase58.version === network.scriptHash) + return payments.p2sh({ hash: decodeBase58.hash }).output; + } else { try { - decodeBase58 = fromBase58Check(address); - } - catch (e) { } - if (decodeBase58) { - if (decodeBase58.version === network.pubKeyHash) - return payments.p2pkh({ hash: decodeBase58.hash }).output; - if (decodeBase58.version === network.scriptHash) - return payments.p2sh({ hash: decodeBase58.hash }).output; - } - else { - try { - decodeBech32 = fromBech32(address); - } - catch (e) { } - if (decodeBech32) { - if (decodeBech32.prefix !== network.bech32) - throw new Error(address + ' has an invalid prefix'); - if (decodeBech32.version === 0) { - if (decodeBech32.data.length === 20) - return payments.p2wpkh({ hash: decodeBech32.data }).output; - if (decodeBech32.data.length === 32) - return payments.p2wsh({ hash: decodeBech32.data }).output; - } - } + decodeBech32 = fromBech32(address); + } catch (e) {} + if (decodeBech32) { + if (decodeBech32.prefix !== network.bech32) + throw new Error(address + ' has an invalid prefix'); + if (decodeBech32.version === 0) { + if (decodeBech32.data.length === 20) + return payments.p2wpkh({ hash: decodeBech32.data }).output; + if (decodeBech32.data.length === 32) + return payments.p2wsh({ hash: decodeBech32.data }).output; + } } - throw new Error(address + ' has no matching Script'); + } + throw new Error(address + ' has no matching Script'); } exports.toOutputScript = toOutputScript; diff --git a/src/block.js b/src/block.js index da17193..22449fd 100644 --- a/src/block.js +++ b/src/block.js @@ -1,222 +1,242 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bufferutils_1 = require("./bufferutils"); -const bcrypto = require("./crypto"); -const transaction_1 = require("./transaction"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bufferutils_1 = require('./bufferutils'); +const bcrypto = require('./crypto'); +const transaction_1 = require('./transaction'); +const types = require('./types'); const fastMerkleRoot = require('merkle-lib/fastRoot'); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); -const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); -const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); +const errorMerkleNoTxes = new TypeError( + 'Cannot compute merkle root for zero transactions', +); +const errorWitnessNotSegwit = new TypeError( + 'Cannot compute witness commit for non-segwit block', +); class Block { - constructor() { - this.version = 1; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.timestamp = 0; - this.witnessCommit = undefined; - this.bits = 0; - this.nonce = 0; - this.transactions = undefined; - } - static fromBuffer(buffer) { - if (buffer.length < 80) - throw new Error('Buffer too small (< 80 bytes)'); - let offset = 0; - const readSlice = (n) => { - offset += n; - return buffer.slice(offset - n, offset); - }; - const readUInt32 = () => { - const i = buffer.readUInt32LE(offset); - offset += 4; - return i; - }; - const readInt32 = () => { - const i = buffer.readInt32LE(offset); - offset += 4; - return i; - }; - const block = new Block(); - block.version = readInt32(); - block.prevHash = readSlice(32); - block.merkleRoot = readSlice(32); - block.timestamp = readUInt32(); - block.bits = readUInt32(); - block.nonce = readUInt32(); - if (buffer.length === 80) - return block; - const readVarInt = () => { - const vi = varuint.decode(buffer, offset); - offset += varuint.decode.bytes; - return vi; - }; - const readTransaction = () => { - const tx = transaction_1.Transaction.fromBuffer(buffer.slice(offset), true); - offset += tx.byteLength(); - return tx; - }; - const nTransactions = readVarInt(); - block.transactions = []; - for (let i = 0; i < nTransactions; ++i) { - const tx = readTransaction(); - block.transactions.push(tx); - } - const witnessCommit = block.getWitnessCommit(); - // This Block contains a witness commit - if (witnessCommit) - block.witnessCommit = witnessCommit; - return block; - } - static fromHex(hex) { - return Block.fromBuffer(Buffer.from(hex, 'hex')); - } - static calculateTarget(bits) { - const exponent = ((bits & 0xff000000) >> 24) - 3; - const mantissa = bits & 0x007fffff; - const target = Buffer.alloc(32, 0); - target.writeUIntBE(mantissa, 29 - exponent, 3); - return target; - } - static calculateMerkleRoot(transactions, forWitness) { - typeforce([{ getHash: types.Function }], transactions); - if (transactions.length === 0) - throw errorMerkleNoTxes; - if (forWitness && !txesHaveWitnessCommit(transactions)) - throw errorWitnessNotSegwit; - const hashes = transactions.map(transaction => transaction.getHash(forWitness)); - const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); - return forWitness - ? bcrypto.hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) - : rootHash; - } - getWitnessCommit() { - if (!txesHaveWitnessCommit(this.transactions)) - return null; - // The merkle root for the witness data is in an OP_RETURN output. - // There is no rule for the index of the output, so use filter to find it. - // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed - // If multiple commits are found, the output with highest index is assumed. - const witnessCommits = this.transactions[0].outs.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex'))).map(out => out.script.slice(6, 38)); - if (witnessCommits.length === 0) - return null; - // Use the commit with the highest output (should only be one though) - const result = witnessCommits[witnessCommits.length - 1]; - if (!(result instanceof Buffer && result.length === 32)) - return null; - return result; - } - hasWitnessCommit() { - if (this.witnessCommit instanceof Buffer && - this.witnessCommit.length === 32) - return true; - if (this.getWitnessCommit() !== null) - return true; - return false; - } - hasWitness() { - return anyTxHasWitness(this.transactions); - } - byteLength(headersOnly) { - if (headersOnly || !this.transactions) - return 80; - return (80 + - varuint.encodingLength(this.transactions.length) + - this.transactions.reduce((a, x) => a + x.byteLength(), 0)); - } - getHash() { - return bcrypto.hash256(this.toBuffer(true)); - } - getId() { - return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); - } - getUTCDate() { - const date = new Date(0); // epoch - date.setUTCSeconds(this.timestamp); - return date; - } - // TODO: buffer, offset compatibility - toBuffer(headersOnly) { - const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); - let offset = 0; - const writeSlice = (slice) => { - slice.copy(buffer, offset); - offset += slice.length; - }; - const writeInt32 = (i) => { - buffer.writeInt32LE(i, offset); - offset += 4; - }; - const writeUInt32 = (i) => { - buffer.writeUInt32LE(i, offset); - offset += 4; - }; - writeInt32(this.version); - writeSlice(this.prevHash); - writeSlice(this.merkleRoot); - writeUInt32(this.timestamp); - writeUInt32(this.bits); - writeUInt32(this.nonce); - if (headersOnly || !this.transactions) - return buffer; - varuint.encode(this.transactions.length, buffer, offset); - offset += varuint.encode.bytes; - this.transactions.forEach(tx => { - const txSize = tx.byteLength(); // TODO: extract from toBuffer? - tx.toBuffer(buffer, offset); - offset += txSize; - }); - return buffer; - } - toHex(headersOnly) { - return this.toBuffer(headersOnly).toString('hex'); - } - checkTxRoots() { - // If the Block has segwit transactions but no witness commit, - // there's no way it can be valid, so fail the check. - const hasWitnessCommit = this.hasWitnessCommit(); - if (!hasWitnessCommit && this.hasWitness()) - return false; - return (this.__checkMerkleRoot() && - (hasWitnessCommit ? this.__checkWitnessCommit() : true)); - } - checkProofOfWork() { - const hash = bufferutils_1.reverseBuffer(this.getHash()); - const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0; - } - __checkMerkleRoot() { - if (!this.transactions) - throw errorMerkleNoTxes; - const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - return this.merkleRoot.compare(actualMerkleRoot) === 0; - } - __checkWitnessCommit() { - if (!this.transactions) - throw errorMerkleNoTxes; - if (!this.hasWitnessCommit()) - throw errorWitnessNotSegwit; - const actualWitnessCommit = Block.calculateMerkleRoot(this.transactions, true); - return this.witnessCommit.compare(actualWitnessCommit) === 0; - } + constructor() { + this.version = 1; + this.prevHash = undefined; + this.merkleRoot = undefined; + this.timestamp = 0; + this.witnessCommit = undefined; + this.bits = 0; + this.nonce = 0; + this.transactions = undefined; + } + static fromBuffer(buffer) { + if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); + let offset = 0; + const readSlice = n => { + offset += n; + return buffer.slice(offset - n, offset); + }; + const readUInt32 = () => { + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; + }; + const readInt32 = () => { + const i = buffer.readInt32LE(offset); + offset += 4; + return i; + }; + const block = new Block(); + block.version = readInt32(); + block.prevHash = readSlice(32); + block.merkleRoot = readSlice(32); + block.timestamp = readUInt32(); + block.bits = readUInt32(); + block.nonce = readUInt32(); + if (buffer.length === 80) return block; + const readVarInt = () => { + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; + }; + const readTransaction = () => { + const tx = transaction_1.Transaction.fromBuffer( + buffer.slice(offset), + true, + ); + offset += tx.byteLength(); + return tx; + }; + const nTransactions = readVarInt(); + block.transactions = []; + for (let i = 0; i < nTransactions; ++i) { + const tx = readTransaction(); + block.transactions.push(tx); + } + const witnessCommit = block.getWitnessCommit(); + // This Block contains a witness commit + if (witnessCommit) block.witnessCommit = witnessCommit; + return block; + } + static fromHex(hex) { + return Block.fromBuffer(Buffer.from(hex, 'hex')); + } + static calculateTarget(bits) { + const exponent = ((bits & 0xff000000) >> 24) - 3; + const mantissa = bits & 0x007fffff; + const target = Buffer.alloc(32, 0); + target.writeUIntBE(mantissa, 29 - exponent, 3); + return target; + } + static calculateMerkleRoot(transactions, forWitness) { + typeforce([{ getHash: types.Function }], transactions); + if (transactions.length === 0) throw errorMerkleNoTxes; + if (forWitness && !txesHaveWitnessCommit(transactions)) + throw errorWitnessNotSegwit; + const hashes = transactions.map(transaction => + transaction.getHash(forWitness), + ); + const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); + return forWitness + ? bcrypto.hash256( + Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + ) + : rootHash; + } + getWitnessCommit() { + if (!txesHaveWitnessCommit(this.transactions)) return null; + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + const witnessCommits = this.transactions[0].outs + .filter(out => + out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + ) + .map(out => out.script.slice(6, 38)); + if (witnessCommits.length === 0) return null; + // Use the commit with the highest output (should only be one though) + const result = witnessCommits[witnessCommits.length - 1]; + if (!(result instanceof Buffer && result.length === 32)) return null; + return result; + } + hasWitnessCommit() { + if ( + this.witnessCommit instanceof Buffer && + this.witnessCommit.length === 32 + ) + return true; + if (this.getWitnessCommit() !== null) return true; + return false; + } + hasWitness() { + return anyTxHasWitness(this.transactions); + } + byteLength(headersOnly) { + if (headersOnly || !this.transactions) return 80; + return ( + 80 + + varuint.encodingLength(this.transactions.length) + + this.transactions.reduce((a, x) => a + x.byteLength(), 0) + ); + } + getHash() { + return bcrypto.hash256(this.toBuffer(true)); + } + getId() { + return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); + } + getUTCDate() { + const date = new Date(0); // epoch + date.setUTCSeconds(this.timestamp); + return date; + } + // TODO: buffer, offset compatibility + toBuffer(headersOnly) { + const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); + let offset = 0; + const writeSlice = slice => { + slice.copy(buffer, offset); + offset += slice.length; + }; + const writeInt32 = i => { + buffer.writeInt32LE(i, offset); + offset += 4; + }; + const writeUInt32 = i => { + buffer.writeUInt32LE(i, offset); + offset += 4; + }; + writeInt32(this.version); + writeSlice(this.prevHash); + writeSlice(this.merkleRoot); + writeUInt32(this.timestamp); + writeUInt32(this.bits); + writeUInt32(this.nonce); + if (headersOnly || !this.transactions) return buffer; + varuint.encode(this.transactions.length, buffer, offset); + offset += varuint.encode.bytes; + this.transactions.forEach(tx => { + const txSize = tx.byteLength(); // TODO: extract from toBuffer? + tx.toBuffer(buffer, offset); + offset += txSize; + }); + return buffer; + } + toHex(headersOnly) { + return this.toBuffer(headersOnly).toString('hex'); + } + checkTxRoots() { + // If the Block has segwit transactions but no witness commit, + // there's no way it can be valid, so fail the check. + const hasWitnessCommit = this.hasWitnessCommit(); + if (!hasWitnessCommit && this.hasWitness()) return false; + return ( + this.__checkMerkleRoot() && + (hasWitnessCommit ? this.__checkWitnessCommit() : true) + ); + } + checkProofOfWork() { + const hash = bufferutils_1.reverseBuffer(this.getHash()); + const target = Block.calculateTarget(this.bits); + return hash.compare(target) <= 0; + } + __checkMerkleRoot() { + if (!this.transactions) throw errorMerkleNoTxes; + const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); + return this.merkleRoot.compare(actualMerkleRoot) === 0; + } + __checkWitnessCommit() { + if (!this.transactions) throw errorMerkleNoTxes; + if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; + const actualWitnessCommit = Block.calculateMerkleRoot( + this.transactions, + true, + ); + return this.witnessCommit.compare(actualWitnessCommit) === 0; + } } exports.Block = Block; function txesHaveWitnessCommit(transactions) { - return (transactions instanceof Array && - transactions[0] && - transactions[0].ins && - transactions[0].ins instanceof Array && - transactions[0].ins[0] && - transactions[0].ins[0].witness && - transactions[0].ins[0].witness instanceof Array && - transactions[0].ins[0].witness.length > 0); + return ( + transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0 + ); } function anyTxHasWitness(transactions) { - return (transactions instanceof Array && - transactions.some(tx => typeof tx === 'object' && - tx.ins instanceof Array && - tx.ins.some(input => typeof input === 'object' && - input.witness instanceof Array && - input.witness.length > 0))); + return ( + transactions instanceof Array && + transactions.some( + tx => + typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some( + input => + typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0, + ), + ) + ); } diff --git a/src/bufferutils.js b/src/bufferutils.js index f768250..54ce1c9 100644 --- a/src/bufferutils.js +++ b/src/bufferutils.js @@ -1,42 +1,40 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); // https://github.com/feross/buffer/blob/master/index.js#L1127 function verifuint(value, max) { - if (typeof value !== 'number') - throw new Error('cannot write a non-number as a number'); - if (value < 0) - throw new Error('specified a negative value for writing an unsigned value'); - if (value > max) - throw new Error('RangeError: value out of range'); - if (Math.floor(value) !== value) - throw new Error('value has a fractional component'); + if (typeof value !== 'number') + throw new Error('cannot write a non-number as a number'); + if (value < 0) + throw new Error('specified a negative value for writing an unsigned value'); + if (value > max) throw new Error('RangeError: value out of range'); + if (Math.floor(value) !== value) + throw new Error('value has a fractional component'); } function readUInt64LE(buffer, offset) { - const a = buffer.readUInt32LE(offset); - let b = buffer.readUInt32LE(offset + 4); - b *= 0x100000000; - verifuint(b + a, 0x001fffffffffffff); - return b + a; + const a = buffer.readUInt32LE(offset); + let b = buffer.readUInt32LE(offset + 4); + b *= 0x100000000; + verifuint(b + a, 0x001fffffffffffff); + return b + a; } exports.readUInt64LE = readUInt64LE; function writeUInt64LE(buffer, value, offset) { - verifuint(value, 0x001fffffffffffff); - buffer.writeInt32LE(value & -1, offset); - buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); - return offset + 8; + verifuint(value, 0x001fffffffffffff); + buffer.writeInt32LE(value & -1, offset); + buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); + return offset + 8; } exports.writeUInt64LE = writeUInt64LE; function reverseBuffer(buffer) { - if (buffer.length < 1) - return buffer; - let j = buffer.length - 1; - let tmp = 0; - for (let i = 0; i < buffer.length / 2; i++) { - tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - j--; - } - return buffer; + if (buffer.length < 1) return buffer; + let j = buffer.length - 1; + let tmp = 0; + for (let i = 0; i < buffer.length / 2; i++) { + tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + j--; + } + return buffer; } exports.reverseBuffer = reverseBuffer; diff --git a/src/classify.js b/src/classify.js index 7d8e57d..70c600c 100644 --- a/src/classify.js +++ b/src/classify.js @@ -1,75 +1,59 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const script_1 = require("./script"); -const multisig = require("./templates/multisig"); -const nullData = require("./templates/nulldata"); -const pubKey = require("./templates/pubkey"); -const pubKeyHash = require("./templates/pubkeyhash"); -const scriptHash = require("./templates/scripthash"); -const witnessCommitment = require("./templates/witnesscommitment"); -const witnessPubKeyHash = require("./templates/witnesspubkeyhash"); -const witnessScriptHash = require("./templates/witnessscripthash"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const script_1 = require('./script'); +const multisig = require('./templates/multisig'); +const nullData = require('./templates/nulldata'); +const pubKey = require('./templates/pubkey'); +const pubKeyHash = require('./templates/pubkeyhash'); +const scriptHash = require('./templates/scripthash'); +const witnessCommitment = require('./templates/witnesscommitment'); +const witnessPubKeyHash = require('./templates/witnesspubkeyhash'); +const witnessScriptHash = require('./templates/witnessscripthash'); const types = { - P2MS: 'multisig', - NONSTANDARD: 'nonstandard', - NULLDATA: 'nulldata', - P2PK: 'pubkey', - P2PKH: 'pubkeyhash', - P2SH: 'scripthash', - P2WPKH: 'witnesspubkeyhash', - P2WSH: 'witnessscripthash', - WITNESS_COMMITMENT: 'witnesscommitment', + P2MS: 'multisig', + NONSTANDARD: 'nonstandard', + NULLDATA: 'nulldata', + P2PK: 'pubkey', + P2PKH: 'pubkeyhash', + P2SH: 'scripthash', + P2WPKH: 'witnesspubkeyhash', + P2WSH: 'witnessscripthash', + WITNESS_COMMITMENT: 'witnesscommitment', }; exports.types = types; function classifyOutput(script) { - if (witnessPubKeyHash.output.check(script)) - return types.P2WPKH; - if (witnessScriptHash.output.check(script)) - return types.P2WSH; - if (pubKeyHash.output.check(script)) - return types.P2PKH; - if (scriptHash.output.check(script)) - return types.P2SH; - // XXX: optimization, below functions .decompile before use - const chunks = script_1.decompile(script); - if (!chunks) - throw new TypeError('Invalid script'); - if (multisig.output.check(chunks)) - return types.P2MS; - if (pubKey.output.check(chunks)) - return types.P2PK; - if (witnessCommitment.output.check(chunks)) - return types.WITNESS_COMMITMENT; - if (nullData.output.check(chunks)) - return types.NULLDATA; - return types.NONSTANDARD; + if (witnessPubKeyHash.output.check(script)) return types.P2WPKH; + if (witnessScriptHash.output.check(script)) return types.P2WSH; + if (pubKeyHash.output.check(script)) return types.P2PKH; + if (scriptHash.output.check(script)) return types.P2SH; + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) throw new TypeError('Invalid script'); + if (multisig.output.check(chunks)) return types.P2MS; + if (pubKey.output.check(chunks)) return types.P2PK; + if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT; + if (nullData.output.check(chunks)) return types.NULLDATA; + return types.NONSTANDARD; } exports.output = classifyOutput; function classifyInput(script, allowIncomplete) { - // XXX: optimization, below functions .decompile before use - const chunks = script_1.decompile(script); - if (!chunks) - throw new TypeError('Invalid script'); - if (pubKeyHash.input.check(chunks)) - return types.P2PKH; - if (scriptHash.input.check(chunks, allowIncomplete)) - return types.P2SH; - if (multisig.input.check(chunks, allowIncomplete)) - return types.P2MS; - if (pubKey.input.check(chunks)) - return types.P2PK; - return types.NONSTANDARD; + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) throw new TypeError('Invalid script'); + if (pubKeyHash.input.check(chunks)) return types.P2PKH; + if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH; + if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS; + if (pubKey.input.check(chunks)) return types.P2PK; + return types.NONSTANDARD; } exports.input = classifyInput; function classifyWitness(script, allowIncomplete) { - // XXX: optimization, below functions .decompile before use - const chunks = script_1.decompile(script); - if (!chunks) - throw new TypeError('Invalid script'); - if (witnessPubKeyHash.input.check(chunks)) - return types.P2WPKH; - if (witnessScriptHash.input.check(chunks, allowIncomplete)) - return types.P2WSH; - return types.NONSTANDARD; + // XXX: optimization, below functions .decompile before use + const chunks = script_1.decompile(script); + if (!chunks) throw new TypeError('Invalid script'); + if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH; + if (witnessScriptHash.input.check(chunks, allowIncomplete)) + return types.P2WSH; + return types.NONSTANDARD; } exports.witness = classifyWitness; diff --git a/src/crypto.js b/src/crypto.js index 38ec4f9..e7dd596 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -1,36 +1,35 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); const createHash = require('create-hash'); function ripemd160(buffer) { - try { - return createHash('rmd160') - .update(buffer) - .digest(); - } - catch (err) { - return createHash('ripemd160') - .update(buffer) - .digest(); - } + try { + return createHash('rmd160') + .update(buffer) + .digest(); + } catch (err) { + return createHash('ripemd160') + .update(buffer) + .digest(); + } } exports.ripemd160 = ripemd160; function sha1(buffer) { - return createHash('sha1') - .update(buffer) - .digest(); + return createHash('sha1') + .update(buffer) + .digest(); } exports.sha1 = sha1; function sha256(buffer) { - return createHash('sha256') - .update(buffer) - .digest(); + return createHash('sha256') + .update(buffer) + .digest(); } exports.sha256 = sha256; function hash160(buffer) { - return ripemd160(sha256(buffer)); + return ripemd160(sha256(buffer)); } exports.hash160 = hash160; function hash256(buffer) { - return sha256(sha256(buffer)); + return sha256(sha256(buffer)); } exports.hash256 = hash256; diff --git a/src/ecpair.js b/src/ecpair.js index 2026c63..9acdd3c 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -1,98 +1,91 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const NETWORKS = require("./networks"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const NETWORKS = require('./networks'); +const types = require('./types'); const ecc = require('tiny-secp256k1'); const randomBytes = require('randombytes'); const typeforce = require('typeforce'); const wif = require('wif'); -const isOptions = typeforce.maybe(typeforce.compile({ +const isOptions = typeforce.maybe( + typeforce.compile({ compressed: types.maybe(types.Boolean), network: types.maybe(types.Network), -})); + }), +); class ECPair { - constructor(__D, __Q, options) { - this.__D = __D; - this.__Q = __Q; - if (options === undefined) - options = {}; - this.compressed = - options.compressed === undefined ? true : options.compressed; - this.network = options.network || NETWORKS.bitcoin; - if (__Q !== undefined) - this.__Q = ecc.pointCompress(__Q, this.compressed); - } - get privateKey() { - return this.__D; - } - get publicKey() { - if (!this.__Q) - this.__Q = ecc.pointFromScalar(this.__D, this.compressed); - return this.__Q; - } - toWIF() { - if (!this.__D) - throw new Error('Missing private key'); - return wif.encode(this.network.wif, this.__D, this.compressed); - } - sign(hash) { - if (!this.__D) - throw new Error('Missing private key'); - return ecc.sign(hash, this.__D); - } - verify(hash, signature) { - return ecc.verify(hash, this.publicKey, signature); - } + constructor(__D, __Q, options) { + this.__D = __D; + this.__Q = __Q; + if (options === undefined) options = {}; + this.compressed = + options.compressed === undefined ? true : options.compressed; + this.network = options.network || NETWORKS.bitcoin; + if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); + } + get privateKey() { + return this.__D; + } + get publicKey() { + if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); + return this.__Q; + } + toWIF() { + if (!this.__D) throw new Error('Missing private key'); + return wif.encode(this.network.wif, this.__D, this.compressed); + } + sign(hash) { + if (!this.__D) throw new Error('Missing private key'); + return ecc.sign(hash, this.__D); + } + verify(hash, signature) { + return ecc.verify(hash, this.publicKey, signature); + } } function fromPrivateKey(buffer, options) { - typeforce(types.Buffer256bit, buffer); - if (!ecc.isPrivate(buffer)) - throw new TypeError('Private key not in range [1, n)'); - typeforce(isOptions, options); - return new ECPair(buffer, undefined, options); + typeforce(types.Buffer256bit, buffer); + if (!ecc.isPrivate(buffer)) + throw new TypeError('Private key not in range [1, n)'); + typeforce(isOptions, options); + return new ECPair(buffer, undefined, options); } exports.fromPrivateKey = fromPrivateKey; function fromPublicKey(buffer, options) { - typeforce(ecc.isPoint, buffer); - typeforce(isOptions, options); - return new ECPair(undefined, buffer, options); + typeforce(ecc.isPoint, buffer); + typeforce(isOptions, options); + return new ECPair(undefined, buffer, options); } exports.fromPublicKey = fromPublicKey; function fromWIF(wifString, network) { - const decoded = wif.decode(wifString); - const version = decoded.version; - // list of networks? - if (types.Array(network)) { - network = network - .filter((x) => { - return version === x.wif; - }) - .pop(); - if (!network) - throw new Error('Unknown network version'); - // otherwise, assume a network object (or default to bitcoin) - } - else { - network = network || NETWORKS.bitcoin; - if (version !== network.wif) - throw new Error('Invalid network version'); - } - return fromPrivateKey(decoded.privateKey, { - compressed: decoded.compressed, - network: network, - }); + const decoded = wif.decode(wifString); + const version = decoded.version; + // list of networks? + if (types.Array(network)) { + network = network + .filter(x => { + return version === x.wif; + }) + .pop(); + if (!network) throw new Error('Unknown network version'); + // otherwise, assume a network object (or default to bitcoin) + } else { + network = network || NETWORKS.bitcoin; + if (version !== network.wif) throw new Error('Invalid network version'); + } + return fromPrivateKey(decoded.privateKey, { + compressed: decoded.compressed, + network: network, + }); } exports.fromWIF = fromWIF; function makeRandom(options) { - typeforce(isOptions, options); - if (options === undefined) - options = {}; - const rng = options.rng || randomBytes; - let d; - do { - d = rng(32); - typeforce(types.Buffer256bit, d); - } while (!ecc.isPrivate(d)); - return fromPrivateKey(d, options); + typeforce(isOptions, options); + if (options === undefined) options = {}; + const rng = options.rng || randomBytes; + let d; + do { + d = rng(32); + typeforce(types.Buffer256bit, d); + } while (!ecc.isPrivate(d)); + return fromPrivateKey(d, options); } exports.makeRandom = makeRandom; diff --git a/src/index.js b/src/index.js index 73ac6f4..499380e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,24 +1,24 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bip32 = require("bip32"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bip32 = require('bip32'); exports.bip32 = bip32; -const address = require("./address"); +const address = require('./address'); exports.address = address; -const crypto = require("./crypto"); +const crypto = require('./crypto'); exports.crypto = crypto; -const ECPair = require("./ecpair"); +const ECPair = require('./ecpair'); exports.ECPair = ECPair; -const networks = require("./networks"); +const networks = require('./networks'); exports.networks = networks; -const payments = require("./payments"); +const payments = require('./payments'); exports.payments = payments; -const script = require("./script"); +const script = require('./script'); exports.script = script; -var block_1 = require("./block"); +var block_1 = require('./block'); exports.Block = block_1.Block; -var script_1 = require("./script"); +var script_1 = require('./script'); exports.opcodes = script_1.OPS; -var transaction_1 = require("./transaction"); +var transaction_1 = require('./transaction'); exports.Transaction = transaction_1.Transaction; -var transaction_builder_1 = require("./transaction_builder"); +var transaction_builder_1 = require('./transaction_builder'); exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; diff --git a/src/networks.js b/src/networks.js index 298808d..0c31fe1 100644 --- a/src/networks.js +++ b/src/networks.js @@ -1,35 +1,35 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); exports.bitcoin = { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'bc', - bip32: { - public: 0x0488b21e, - private: 0x0488ade4, - }, - pubKeyHash: 0x00, - scriptHash: 0x05, - wif: 0x80, + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4, + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80, }; exports.regtest = { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'bcrt', - bip32: { - public: 0x043587cf, - private: 0x04358394, - }, - pubKeyHash: 0x6f, - scriptHash: 0xc4, - wif: 0xef, + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, }; exports.testnet = { - messagePrefix: '\x18Bitcoin Signed Message:\n', - bech32: 'tb', - bip32: { - public: 0x043587cf, - private: 0x04358394, - }, - pubKeyHash: 0x6f, - scriptHash: 0xc4, - wif: 0xef, + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, }; diff --git a/src/payments/embed.js b/src/payments/embed.js index 800c8de..3ddceb9 100644 --- a/src/payments/embed.js +++ b/src/payments/embed.js @@ -1,51 +1,49 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; function stacksEqual(a, b) { - if (a.length !== b.length) - return false; - return a.every((x, i) => { - return x.equals(b[i]); - }); + if (a.length !== b.length) return false; + return a.every((x, i) => { + return x.equals(b[i]); + }); } // output: OP_RETURN ... function p2data(a, opts) { - if (!a.data && !a.output) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - data: typef.maybe(typef.arrayOf(typef.Buffer)), - }, a); - const network = a.network || networks_1.bitcoin; - const o = { network }; - lazy.prop(o, 'output', () => { - if (!a.data) - return; - return bscript.compile([OPS.OP_RETURN].concat(a.data)); - }); - lazy.prop(o, 'data', () => { - if (!a.output) - return; - return bscript.decompile(a.output).slice(1); - }); - // extended validation - if (opts.validate) { - if (a.output) { - const chunks = bscript.decompile(a.output); - if (chunks[0] !== OPS.OP_RETURN) - throw new TypeError('Output is invalid'); - if (!chunks.slice(1).every(typef.Buffer)) - throw new TypeError('Output is invalid'); - if (a.data && !stacksEqual(a.data, o.data)) - throw new TypeError('Data mismatch'); - } + if (!a.data && !a.output) throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + data: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'output', () => { + if (!a.data) return; + return bscript.compile([OPS.OP_RETURN].concat(a.data)); + }); + lazy.prop(o, 'data', () => { + if (!a.output) return; + return bscript.decompile(a.output).slice(1); + }); + // extended validation + if (opts.validate) { + if (a.output) { + const chunks = bscript.decompile(a.output); + if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); + if (!chunks.slice(1).every(typef.Buffer)) + throw new TypeError('Output is invalid'); + if (a.data && !stacksEqual(a.data, o.data)) + throw new TypeError('Data mismatch'); } - return Object.assign(o, a); + } + return Object.assign(o, a); } exports.p2data = p2data; diff --git a/src/payments/index.js b/src/payments/index.js index f21762d..ddab977 100644 --- a/src/payments/index.js +++ b/src/payments/index.js @@ -1,18 +1,18 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const embed_1 = require("./embed"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const embed_1 = require('./embed'); exports.embed = embed_1.p2data; -const p2ms_1 = require("./p2ms"); +const p2ms_1 = require('./p2ms'); exports.p2ms = p2ms_1.p2ms; -const p2pk_1 = require("./p2pk"); +const p2pk_1 = require('./p2pk'); exports.p2pk = p2pk_1.p2pk; -const p2pkh_1 = require("./p2pkh"); +const p2pkh_1 = require('./p2pkh'); exports.p2pkh = p2pkh_1.p2pkh; -const p2sh_1 = require("./p2sh"); +const p2sh_1 = require('./p2sh'); exports.p2sh = p2sh_1.p2sh; -const p2wpkh_1 = require("./p2wpkh"); +const p2wpkh_1 = require('./p2wpkh'); exports.p2wpkh = p2wpkh_1.p2wpkh; -const p2wsh_1 = require("./p2wsh"); +const p2wsh_1 = require('./p2wsh'); exports.p2wsh = p2wsh_1.p2wsh; // TODO // witness commitment diff --git a/src/payments/lazy.js b/src/payments/lazy.js index d8494fd..1a71521 100644 --- a/src/payments/lazy.js +++ b/src/payments/lazy.js @@ -1,32 +1,31 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); function prop(object, name, f) { - Object.defineProperty(object, name, { + Object.defineProperty(object, name, { + configurable: true, + enumerable: true, + get() { + const _value = f.call(this); + this[name] = _value; + return _value; + }, + set(_value) { + Object.defineProperty(this, name, { configurable: true, enumerable: true, - get() { - const _value = f.call(this); - this[name] = _value; - return _value; - }, - set(_value) { - Object.defineProperty(this, name, { - configurable: true, - enumerable: true, - value: _value, - writable: true, - }); - }, - }); + value: _value, + writable: true, + }); + }, + }); } exports.prop = prop; function value(f) { - let _value; - return () => { - if (_value !== undefined) - return _value; - _value = f(); - return _value; - }; + let _value; + return () => { + if (_value !== undefined) return _value; + _value = f(); + return _value; + }; } exports.value = value; diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js index 5e48432..1e7c6ba 100644 --- a/src/payments/p2ms.js +++ b/src/payments/p2ms.js @@ -1,141 +1,141 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const OPS = bscript.OPS; const typef = require('typeforce'); const ecc = require('tiny-secp256k1'); const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 function stacksEqual(a, b) { - if (a.length !== b.length) - return false; - return a.every((x, i) => { - return x.equals(b[i]); - }); + if (a.length !== b.length) return false; + return a.every((x, i) => { + return x.equals(b[i]); + }); } // input: OP_0 [signatures ...] // output: m [pubKeys ...] n OP_CHECKMULTISIG function p2ms(a, opts) { - if (!a.input && - !a.output && - !(a.pubkeys && a.m !== undefined) && - !a.signatures) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - function isAcceptableSignature(x) { - return (bscript.isCanonicalScriptSignature(x) || - (opts.allowIncomplete && x === OPS.OP_0) !== undefined); + if ( + !a.input && + !a.output && + !(a.pubkeys && a.m !== undefined) && + !a.signatures + ) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + function isAcceptableSignature(x) { + return ( + bscript.isCanonicalScriptSignature(x) || + (opts.allowIncomplete && x === OPS.OP_0) !== undefined + ); + } + typef( + { + network: typef.maybe(typef.Object), + m: typef.maybe(typef.Number), + n: typef.maybe(typef.Number), + output: typef.maybe(typef.Buffer), + pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), + signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + input: typef.maybe(typef.Buffer), + }, + a, + ); + const network = a.network || networks_1.bitcoin; + const o = { network }; + let chunks = []; + let decoded = false; + function decode(output) { + if (decoded) return; + decoded = true; + chunks = bscript.decompile(output); + o.m = chunks[0] - OP_INT_BASE; + o.n = chunks[chunks.length - 2] - OP_INT_BASE; + o.pubkeys = chunks.slice(1, -2); + } + lazy.prop(o, 'output', () => { + if (!a.m) return; + if (!o.n) return; + if (!a.pubkeys) return; + return bscript.compile( + [].concat( + OP_INT_BASE + a.m, + a.pubkeys, + OP_INT_BASE + o.n, + OPS.OP_CHECKMULTISIG, + ), + ); + }); + lazy.prop(o, 'm', () => { + if (!o.output) return; + decode(o.output); + return o.m; + }); + lazy.prop(o, 'n', () => { + if (!o.pubkeys) return; + return o.pubkeys.length; + }); + lazy.prop(o, 'pubkeys', () => { + if (!a.output) return; + decode(a.output); + return o.pubkeys; + }); + lazy.prop(o, 'signatures', () => { + if (!a.input) return; + return bscript.decompile(a.input).slice(1); + }); + lazy.prop(o, 'input', () => { + if (!a.signatures) return; + return bscript.compile([OPS.OP_0].concat(a.signatures)); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + // extended validation + if (opts.validate) { + if (a.output) { + decode(a.output); + if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + if (!typef.Number(chunks[chunks.length - 2])) + throw new TypeError('Output is invalid'); + if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) + throw new TypeError('Output is invalid'); + if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) + throw new TypeError('Output is invalid'); + if (!o.pubkeys.every(x => ecc.isPoint(x))) + throw new TypeError('Output is invalid'); + if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); + if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); + if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) + throw new TypeError('Pubkeys mismatch'); } - typef({ - network: typef.maybe(typef.Object), - m: typef.maybe(typef.Number), - n: typef.maybe(typef.Number), - output: typef.maybe(typef.Buffer), - pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), - signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - input: typef.maybe(typef.Buffer), - }, a); - const network = a.network || networks_1.bitcoin; - const o = { network }; - let chunks = []; - let decoded = false; - function decode(output) { - if (decoded) - return; - decoded = true; - chunks = bscript.decompile(output); - o.m = chunks[0] - OP_INT_BASE; - o.n = chunks[chunks.length - 2] - OP_INT_BASE; - o.pubkeys = chunks.slice(1, -2); + if (a.pubkeys) { + if (a.n !== undefined && a.n !== a.pubkeys.length) + throw new TypeError('Pubkey count mismatch'); + o.n = a.pubkeys.length; + if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m'); } - lazy.prop(o, 'output', () => { - if (!a.m) - return; - if (!o.n) - return; - if (!a.pubkeys) - return; - return bscript.compile([].concat(OP_INT_BASE + a.m, a.pubkeys, OP_INT_BASE + o.n, OPS.OP_CHECKMULTISIG)); - }); - lazy.prop(o, 'm', () => { - if (!o.output) - return; - decode(o.output); - return o.m; - }); - lazy.prop(o, 'n', () => { - if (!o.pubkeys) - return; - return o.pubkeys.length; - }); - lazy.prop(o, 'pubkeys', () => { - if (!a.output) - return; - decode(a.output); - return o.pubkeys; - }); - lazy.prop(o, 'signatures', () => { - if (!a.input) - return; - return bscript.decompile(a.input).slice(1); - }); - lazy.prop(o, 'input', () => { - if (!a.signatures) - return; - return bscript.compile([OPS.OP_0].concat(a.signatures)); - }); - lazy.prop(o, 'witness', () => { - if (!o.input) - return; - return []; - }); - // extended validation - if (opts.validate) { - if (a.output) { - decode(a.output); - if (!typef.Number(chunks[0])) - throw new TypeError('Output is invalid'); - if (!typef.Number(chunks[chunks.length - 2])) - throw new TypeError('Output is invalid'); - if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) - throw new TypeError('Output is invalid'); - if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) - throw new TypeError('Output is invalid'); - if (!o.pubkeys.every(x => ecc.isPoint(x))) - throw new TypeError('Output is invalid'); - if (a.m !== undefined && a.m !== o.m) - throw new TypeError('m mismatch'); - if (a.n !== undefined && a.n !== o.n) - throw new TypeError('n mismatch'); - if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) - throw new TypeError('Pubkeys mismatch'); - } - if (a.pubkeys) { - if (a.n !== undefined && a.n !== a.pubkeys.length) - throw new TypeError('Pubkey count mismatch'); - o.n = a.pubkeys.length; - if (o.n < o.m) - throw new TypeError('Pubkey count cannot be less than m'); - } - if (a.signatures) { - if (a.signatures.length < o.m) - throw new TypeError('Not enough signatures provided'); - if (a.signatures.length > o.m) - throw new TypeError('Too many signatures provided'); - } - if (a.input) { - if (a.input[0] !== OPS.OP_0) - throw new TypeError('Input is invalid'); - if (o.signatures.length === 0 || - !o.signatures.every(isAcceptableSignature)) - throw new TypeError('Input has invalid signature(s)'); - if (a.signatures && !stacksEqual(a.signatures, o.signatures)) - throw new TypeError('Signature mismatch'); - if (a.m !== undefined && a.m !== a.signatures.length) - throw new TypeError('Signature count mismatch'); - } + if (a.signatures) { + if (a.signatures.length < o.m) + throw new TypeError('Not enough signatures provided'); + if (a.signatures.length > o.m) + throw new TypeError('Too many signatures provided'); } - return Object.assign(o, a); + if (a.input) { + if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); + if ( + o.signatures.length === 0 || + !o.signatures.every(isAcceptableSignature) + ) + throw new TypeError('Input has invalid signature(s)'); + if (a.signatures && !stacksEqual(a.signatures, o.signatures)) + throw new TypeError('Signature mismatch'); + if (a.m !== undefined && a.m !== a.signatures.length) + throw new TypeError('Signature count mismatch'); + } + } + return Object.assign(o, a); } exports.p2ms = p2ms; diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js index 81fe427..13356d1 100644 --- a/src/payments/p2pk.js +++ b/src/payments/p2pk.js @@ -1,75 +1,72 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); // input: {signature} // output: {pubKey} OP_CHECKSIG function p2pk(a, opts) { - if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, a); - const _chunks = lazy.value(() => { - return bscript.decompile(a.input); - }); - const network = a.network || networks_1.bitcoin; - const o = { network }; - lazy.prop(o, 'output', () => { - if (!a.pubkey) - return; - return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); - }); - lazy.prop(o, 'pubkey', () => { - if (!a.output) - return; - return a.output.slice(1, -1); - }); - lazy.prop(o, 'signature', () => { - if (!a.input) - return; - return _chunks()[0]; - }); - lazy.prop(o, 'input', () => { - if (!a.signature) - return; - return bscript.compile([a.signature]); - }); - lazy.prop(o, 'witness', () => { - if (!o.input) - return; - return []; - }); - // extended validation - if (opts.validate) { - if (a.output) { - if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) - throw new TypeError('Output is invalid'); - if (!ecc.isPoint(o.pubkey)) - throw new TypeError('Output pubkey is invalid'); - if (a.pubkey && !a.pubkey.equals(o.pubkey)) - throw new TypeError('Pubkey mismatch'); - } - if (a.signature) { - if (a.input && !a.input.equals(o.input)) - throw new TypeError('Signature mismatch'); - } - if (a.input) { - if (_chunks().length !== 1) - throw new TypeError('Input is invalid'); - if (!bscript.isCanonicalScriptSignature(o.signature)) - throw new TypeError('Input has invalid signature'); - } + if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), + }, + a, + ); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'output', () => { + if (!a.pubkey) return; + return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); + }); + lazy.prop(o, 'pubkey', () => { + if (!a.output) return; + return a.output.slice(1, -1); + }); + lazy.prop(o, 'signature', () => { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', () => { + if (!a.signature) return; + return bscript.compile([a.signature]); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + // extended validation + if (opts.validate) { + if (a.output) { + if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) + throw new TypeError('Output is invalid'); + if (!ecc.isPoint(o.pubkey)) + throw new TypeError('Output pubkey is invalid'); + if (a.pubkey && !a.pubkey.equals(o.pubkey)) + throw new TypeError('Pubkey mismatch'); } - return Object.assign(o, a); + if (a.signature) { + if (a.input && !a.input.equals(o.input)) + throw new TypeError('Signature mismatch'); + } + if (a.input) { + if (_chunks().length !== 1) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(o.signature)) + throw new TypeError('Input has invalid signature'); + } + } + return Object.assign(o, a); } exports.p2pk = p2pk; diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js index 9f06bde..ceb7093 100644 --- a/src/payments/p2pkh.js +++ b/src/payments/p2pkh.js @@ -1,9 +1,9 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypto = require("../crypto"); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bcrypto = require('../crypto'); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -11,132 +11,122 @@ const bs58check = require('bs58check'); // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG function p2pkh(a, opts) { - if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(25)), - pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, a); - const _address = lazy.value(() => { - const payload = bs58check.decode(a.address); - const version = payload.readUInt8(0); - const hash = payload.slice(1); - return { version, hash }; - }); - const _chunks = lazy.value(() => { - return bscript.decompile(a.input); - }); - const network = a.network || networks_1.bitcoin; - const o = { network }; - lazy.prop(o, 'address', () => { - if (!o.hash) - return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(network.pubKeyHash, 0); - o.hash.copy(payload, 1); - return bs58check.encode(payload); - }); - lazy.prop(o, 'hash', () => { - if (a.output) - return a.output.slice(3, 23); - if (a.address) - return _address().hash; - if (a.pubkey || o.pubkey) - return bcrypto.hash160(a.pubkey || o.pubkey); - }); - lazy.prop(o, 'output', () => { - if (!o.hash) - return; - return bscript.compile([ - OPS.OP_DUP, - OPS.OP_HASH160, - o.hash, - OPS.OP_EQUALVERIFY, - OPS.OP_CHECKSIG, - ]); - }); - lazy.prop(o, 'pubkey', () => { - if (!a.input) - return; - return _chunks()[1]; - }); - lazy.prop(o, 'signature', () => { - if (!a.input) - return; - return _chunks()[0]; - }); - lazy.prop(o, 'input', () => { - if (!a.pubkey) - return; - if (!a.signature) - return; - return bscript.compile([a.signature, a.pubkey]); - }); - lazy.prop(o, 'witness', () => { - if (!o.input) - return; - return []; - }); - // extended validation - if (opts.validate) { - let hash = Buffer.from([]); - if (a.address) { - if (_address().version !== network.pubKeyHash) - throw new TypeError('Invalid version or Network mismatch'); - if (_address().hash.length !== 20) - throw new TypeError('Invalid address'); - hash = _address().hash; - } - if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) - throw new TypeError('Hash mismatch'); - else - hash = a.hash; - } - if (a.output) { - if (a.output.length !== 25 || - a.output[0] !== OPS.OP_DUP || - a.output[1] !== OPS.OP_HASH160 || - a.output[2] !== 0x14 || - a.output[23] !== OPS.OP_EQUALVERIFY || - a.output[24] !== OPS.OP_CHECKSIG) - throw new TypeError('Output is invalid'); - const hash2 = a.output.slice(3, 23); - if (hash.length > 0 && !hash.equals(hash2)) - throw new TypeError('Hash mismatch'); - else - hash = hash2; - } - if (a.pubkey) { - const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) - throw new TypeError('Hash mismatch'); - else - hash = pkh; - } - if (a.input) { - const chunks = _chunks(); - if (chunks.length !== 2) - throw new TypeError('Input is invalid'); - if (!bscript.isCanonicalScriptSignature(chunks[0])) - throw new TypeError('Input has invalid signature'); - if (!ecc.isPoint(chunks[1])) - throw new TypeError('Input has invalid pubkey'); - if (a.signature && !a.signature.equals(chunks[0])) - throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(chunks[1])) - throw new TypeError('Pubkey mismatch'); - const pkh = bcrypto.hash160(chunks[1]); - if (hash.length > 0 && !hash.equals(pkh)) - throw new TypeError('Hash mismatch'); - } + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(25)), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), + }, + a, + ); + const _address = lazy.value(() => { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(network.pubKeyHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(3, 23); + if (a.address) return _address().hash; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([ + OPS.OP_DUP, + OPS.OP_HASH160, + o.hash, + OPS.OP_EQUALVERIFY, + OPS.OP_CHECKSIG, + ]); + }); + lazy.prop(o, 'pubkey', () => { + if (!a.input) return; + return _chunks()[1]; + }); + lazy.prop(o, 'signature', () => { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', () => { + if (!a.pubkey) return; + if (!a.signature) return; + return bscript.compile([a.signature, a.pubkey]); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.pubKeyHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; } - return Object.assign(o, a); + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 25 || + a.output[0] !== OPS.OP_DUP || + a.output[1] !== OPS.OP_HASH160 || + a.output[2] !== 0x14 || + a.output[23] !== OPS.OP_EQUALVERIFY || + a.output[24] !== OPS.OP_CHECKSIG + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(3, 23); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; + } + if (a.input) { + const chunks = _chunks(); + if (chunks.length !== 2) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(chunks[0])) + throw new TypeError('Input has invalid signature'); + if (!ecc.isPoint(chunks[1])) + throw new TypeError('Input has invalid pubkey'); + if (a.signature && !a.signature.equals(chunks[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(chunks[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(chunks[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); } exports.p2pkh = p2pkh; diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js index e419deb..5fe660a 100644 --- a/src/payments/p2sh.js +++ b/src/payments/p2sh.js @@ -1,185 +1,178 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypto = require("../crypto"); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bcrypto = require('../crypto'); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; const bs58check = require('bs58check'); function stacksEqual(a, b) { - if (a.length !== b.length) - return false; - return a.every((x, i) => { - return x.equals(b[i]); - }); + if (a.length !== b.length) return false; + return a.every((x, i) => { + return x.equals(b[i]); + }); } // input: [redeemScriptSig ...] {redeemScript} // witness: // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL function p2sh(a, opts) { - if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ + if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(23)), + redeem: typef.maybe({ network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(23)), - redeem: typef.maybe({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }), + output: typef.maybe(typef.Buffer), input: typef.maybe(typef.Buffer), witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, a); - let network = a.network; - if (!network) { - network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + }), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + } + const o = { network }; + const _address = lazy.value(() => { + const payload = bs58check.decode(a.address); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const _redeem = lazy.value(() => { + const chunks = _chunks(); + return { + network, + output: chunks[chunks.length - 1], + input: bscript.compile(chunks.slice(0, -1)), + witness: a.witness || [], + }; + }); + // output dependents + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(o.network.scriptHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', () => { + // in order of least effort + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().hash; + if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); + }); + // input dependents + lazy.prop(o, 'redeem', () => { + if (!a.input) return; + return _redeem(); + }); + lazy.prop(o, 'input', () => { + if (!a.redeem || !a.redeem.input || !a.redeem.output) return; + return bscript.compile( + [].concat(bscript.decompile(a.redeem.input), a.redeem.output), + ); + }); + lazy.prop(o, 'witness', () => { + if (o.redeem && o.redeem.witness) return o.redeem.witness; + if (o.input) return []; + }); + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.scriptHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; } - const o = { network }; - const _address = lazy.value(() => { - const payload = bs58check.decode(a.address); - const version = payload.readUInt8(0); - const hash = payload.slice(1); - return { version, hash }; - }); - const _chunks = lazy.value(() => { - return bscript.decompile(a.input); - }); - const _redeem = lazy.value(() => { - const chunks = _chunks(); - return { - network, - output: chunks[chunks.length - 1], - input: bscript.compile(chunks.slice(0, -1)), - witness: a.witness || [], - }; - }); - // output dependents - lazy.prop(o, 'address', () => { - if (!o.hash) - return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(o.network.scriptHash, 0); - o.hash.copy(payload, 1); - return bs58check.encode(payload); - }); - lazy.prop(o, 'hash', () => { - // in order of least effort - if (a.output) - return a.output.slice(2, 22); - if (a.address) - return _address().hash; - if (o.redeem && o.redeem.output) - return bcrypto.hash160(o.redeem.output); - }); - lazy.prop(o, 'output', () => { - if (!o.hash) - return; - return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); - }); - // input dependents - lazy.prop(o, 'redeem', () => { - if (!a.input) - return; - return _redeem(); - }); - lazy.prop(o, 'input', () => { - if (!a.redeem || !a.redeem.input || !a.redeem.output) - return; - return bscript.compile([].concat(bscript.decompile(a.redeem.input), a.redeem.output)); - }); - lazy.prop(o, 'witness', () => { - if (o.redeem && o.redeem.witness) - return o.redeem.witness; - if (o.input) - return []; - }); - if (opts.validate) { - let hash = Buffer.from([]); - if (a.address) { - if (_address().version !== network.scriptHash) - throw new TypeError('Invalid version or Network mismatch'); - if (_address().hash.length !== 20) - throw new TypeError('Invalid address'); - hash = _address().hash; - } - if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) - throw new TypeError('Hash mismatch'); - else - hash = a.hash; - } - if (a.output) { - if (a.output.length !== 23 || - a.output[0] !== OPS.OP_HASH160 || - a.output[1] !== 0x14 || - a.output[22] !== OPS.OP_EQUAL) - throw new TypeError('Output is invalid'); - const hash2 = a.output.slice(2, 22); - if (hash.length > 0 && !hash.equals(hash2)) - throw new TypeError('Hash mismatch'); - else - hash = hash2; - } - // inlined to prevent 'no-inner-declarations' failing - const checkRedeem = (redeem) => { - // is the redeem output empty/invalid? - if (redeem.output) { - const decompile = bscript.decompile(redeem.output); - if (!decompile || decompile.length < 1) - throw new TypeError('Redeem.output too short'); - // match hash against other sources - const hash2 = bcrypto.hash160(redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) - throw new TypeError('Hash mismatch'); - else - hash = hash2; - } - if (redeem.input) { - const hasInput = redeem.input.length > 0; - const hasWitness = redeem.witness && redeem.witness.length > 0; - if (!hasInput && !hasWitness) - throw new TypeError('Empty input'); - if (hasInput && hasWitness) - throw new TypeError('Input and witness provided'); - if (hasInput) { - const richunks = bscript.decompile(redeem.input); - if (!bscript.isPushOnly(richunks)) - throw new TypeError('Non push-only scriptSig'); - } - } - }; - if (a.input) { - const chunks = _chunks(); - if (!chunks || chunks.length < 1) - throw new TypeError('Input too short'); - if (!Buffer.isBuffer(_redeem().output)) - throw new TypeError('Input is invalid'); - checkRedeem(_redeem()); - } - if (a.redeem) { - if (a.redeem.network && a.redeem.network !== network) - throw new TypeError('Network mismatch'); - if (a.input) { - const redeem = _redeem(); - if (a.redeem.output && !a.redeem.output.equals(redeem.output)) - throw new TypeError('Redeem.output mismatch'); - if (a.redeem.input && !a.redeem.input.equals(redeem.input)) - throw new TypeError('Redeem.input mismatch'); - } - checkRedeem(a.redeem); - } - if (a.witness) { - if (a.redeem && - a.redeem.witness && - !stacksEqual(a.redeem.witness, a.witness)) - throw new TypeError('Witness and redeem.witness mismatch'); + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 23 || + a.output[0] !== OPS.OP_HASH160 || + a.output[1] !== 0x14 || + a.output[22] !== OPS.OP_EQUAL + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2, 22); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + // inlined to prevent 'no-inner-declarations' failing + const checkRedeem = redeem => { + // is the redeem output empty/invalid? + if (redeem.output) { + const decompile = bscript.decompile(redeem.output); + if (!decompile || decompile.length < 1) + throw new TypeError('Redeem.output too short'); + // match hash against other sources + const hash2 = bcrypto.hash160(redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (redeem.input) { + const hasInput = redeem.input.length > 0; + const hasWitness = redeem.witness && redeem.witness.length > 0; + if (!hasInput && !hasWitness) throw new TypeError('Empty input'); + if (hasInput && hasWitness) + throw new TypeError('Input and witness provided'); + if (hasInput) { + const richunks = bscript.decompile(redeem.input); + if (!bscript.isPushOnly(richunks)) + throw new TypeError('Non push-only scriptSig'); } + } + }; + if (a.input) { + const chunks = _chunks(); + if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); + if (!Buffer.isBuffer(_redeem().output)) + throw new TypeError('Input is invalid'); + checkRedeem(_redeem()); + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + if (a.input) { + const redeem = _redeem(); + if (a.redeem.output && !a.redeem.output.equals(redeem.output)) + throw new TypeError('Redeem.output mismatch'); + if (a.redeem.input && !a.redeem.input.equals(redeem.input)) + throw new TypeError('Redeem.input mismatch'); + } + checkRedeem(a.redeem); + } + if (a.witness) { + if ( + a.redeem && + a.redeem.witness && + !stacksEqual(a.redeem.witness, a.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); } - return Object.assign(o, a); + } + return Object.assign(o, a); } exports.p2sh = p2sh; diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js index 9e99610..9571e50 100644 --- a/src/payments/p2wpkh.js +++ b/src/payments/p2wpkh.js @@ -1,9 +1,9 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypto = require("../crypto"); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bcrypto = require('../crypto'); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; const ecc = require('tiny-secp256k1'); @@ -13,126 +13,116 @@ const EMPTY_BUFFER = Buffer.alloc(0); // input: <> // output: OP_0 {pubKeyHash} function p2wpkh(a, opts) { - if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - input: typef.maybe(typef.BufferN(0)), - network: typef.maybe(typef.Object), - output: typef.maybe(typef.BufferN(22)), - pubkey: typef.maybe(ecc.isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, a); - const _address = lazy.value(() => { - const result = bech32.decode(a.address); - const version = result.words.shift(); - const data = bech32.fromWords(result.words); - return { - version, - prefix: result.prefix, - data: Buffer.from(data), - }; - }); - const network = a.network || networks_1.bitcoin; - const o = { network }; - lazy.prop(o, 'address', () => { - if (!o.hash) - return; - const words = bech32.toWords(o.hash); - words.unshift(0x00); - return bech32.encode(network.bech32, words); - }); - lazy.prop(o, 'hash', () => { - if (a.output) - return a.output.slice(2, 22); - if (a.address) - return _address().data; - if (a.pubkey || o.pubkey) - return bcrypto.hash160(a.pubkey || o.pubkey); - }); - lazy.prop(o, 'output', () => { - if (!o.hash) - return; - return bscript.compile([OPS.OP_0, o.hash]); - }); - lazy.prop(o, 'pubkey', () => { - if (a.pubkey) - return a.pubkey; - if (!a.witness) - return; - return a.witness[1]; - }); - lazy.prop(o, 'signature', () => { - if (!a.witness) - return; - return a.witness[0]; - }); - lazy.prop(o, 'input', () => { - if (!o.witness) - return; - return EMPTY_BUFFER; - }); - lazy.prop(o, 'witness', () => { - if (!a.pubkey) - return; - if (!a.signature) - return; - return [a.signature, a.pubkey]; - }); - // extended validation - if (opts.validate) { - let hash = Buffer.from([]); - if (a.address) { - if (network && network.bech32 !== _address().prefix) - throw new TypeError('Invalid prefix or Network mismatch'); - if (_address().version !== 0x00) - throw new TypeError('Invalid address version'); - if (_address().data.length !== 20) - throw new TypeError('Invalid address data'); - hash = _address().data; - } - if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) - throw new TypeError('Hash mismatch'); - else - hash = a.hash; - } - if (a.output) { - if (a.output.length !== 22 || - a.output[0] !== OPS.OP_0 || - a.output[1] !== 0x14) - throw new TypeError('Output is invalid'); - if (hash.length > 0 && !hash.equals(a.output.slice(2))) - throw new TypeError('Hash mismatch'); - else - hash = a.output.slice(2); - } - if (a.pubkey) { - const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) - throw new TypeError('Hash mismatch'); - else - hash = pkh; - } - if (a.witness) { - if (a.witness.length !== 2) - throw new TypeError('Witness is invalid'); - if (!bscript.isCanonicalScriptSignature(a.witness[0])) - throw new TypeError('Witness has invalid signature'); - if (!ecc.isPoint(a.witness[1])) - throw new TypeError('Witness has invalid pubkey'); - if (a.signature && !a.signature.equals(a.witness[0])) - throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(a.witness[1])) - throw new TypeError('Pubkey mismatch'); - const pkh = bcrypto.hash160(a.witness[1]); - if (hash.length > 0 && !hash.equals(pkh)) - throw new TypeError('Hash mismatch'); - } + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + input: typef.maybe(typef.BufferN(0)), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.BufferN(22)), + pubkey: typef.maybe(ecc.isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + const _address = lazy.value(() => { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data), + }; + }); + const network = a.network || networks_1.bitcoin; + const o = { network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().data; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'pubkey', () => { + if (a.pubkey) return a.pubkey; + if (!a.witness) return; + return a.witness[1]; + }); + lazy.prop(o, 'signature', () => { + if (!a.witness) return; + return a.witness[0]; + }); + lazy.prop(o, 'input', () => { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', () => { + if (!a.pubkey) return; + if (!a.signature) return; + return [a.signature, a.pubkey]; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 20) + throw new TypeError('Invalid address data'); + hash = _address().data; } - return Object.assign(o, a); + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 22 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x14 + ) + throw new TypeError('Output is invalid'); + if (hash.length > 0 && !hash.equals(a.output.slice(2))) + throw new TypeError('Hash mismatch'); + else hash = a.output.slice(2); + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; + } + if (a.witness) { + if (a.witness.length !== 2) throw new TypeError('Witness is invalid'); + if (!bscript.isCanonicalScriptSignature(a.witness[0])) + throw new TypeError('Witness has invalid signature'); + if (!ecc.isPoint(a.witness[1])) + throw new TypeError('Witness has invalid pubkey'); + if (a.signature && !a.signature.equals(a.witness[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(a.witness[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(a.witness[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); } exports.p2wpkh = p2wpkh; diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js index 0def430..9363718 100644 --- a/src/payments/p2wsh.js +++ b/src/payments/p2wsh.js @@ -1,177 +1,176 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bcrypto = require("../crypto"); -const networks_1 = require("../networks"); -const bscript = require("../script"); -const lazy = require("./lazy"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bcrypto = require('../crypto'); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const lazy = require('./lazy'); const typef = require('typeforce'); const OPS = bscript.OPS; const bech32 = require('bech32'); const EMPTY_BUFFER = Buffer.alloc(0); function stacksEqual(a, b) { - if (a.length !== b.length) - return false; - return a.every((x, i) => { - return x.equals(b[i]); - }); + if (a.length !== b.length) return false; + return a.every((x, i) => { + return x.equals(b[i]); + }); } // input: <> // witness: [redeemScriptSig ...] {redeemScript} // output: OP_0 {sha256(redeemScript)} function p2wsh(a, opts) { - if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) - throw new TypeError('Not enough data'); - opts = Object.assign({ validate: true }, opts || {}); - typef({ + if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(32)), + output: typef.maybe(typef.BufferN(34)), + redeem: typef.maybe({ + input: typef.maybe(typef.Buffer), network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(32)), - output: typef.maybe(typef.BufferN(34)), - redeem: typef.maybe({ - input: typef.maybe(typef.Buffer), - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }), - input: typef.maybe(typef.BufferN(0)), + output: typef.maybe(typef.Buffer), witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, a); - const _address = lazy.value(() => { - const result = bech32.decode(a.address); - const version = result.words.shift(); - const data = bech32.fromWords(result.words); - return { - version, - prefix: result.prefix, - data: Buffer.from(data), - }; - }); - const _rchunks = lazy.value(() => { - return bscript.decompile(a.redeem.input); - }); - let network = a.network; - if (!network) { - network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + }), + input: typef.maybe(typef.BufferN(0)), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + const _address = lazy.value(() => { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data), + }; + }); + const _rchunks = lazy.value(() => { + return bscript.decompile(a.redeem.input); + }); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + } + const o = { network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(2); + if (a.address) return _address().data; + if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'redeem', () => { + if (!a.witness) return; + return { + output: a.witness[a.witness.length - 1], + input: EMPTY_BUFFER, + witness: a.witness.slice(0, -1), + }; + }); + lazy.prop(o, 'input', () => { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', () => { + // transform redeem input to witness stack? + if ( + a.redeem && + a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.output && + a.redeem.output.length > 0 + ) { + const stack = bscript.toStack(_rchunks()); + // assign, and blank the existing input + o.redeem = Object.assign({ witness: stack }, a.redeem); + o.redeem.input = EMPTY_BUFFER; + return [].concat(stack, a.redeem.output); } - const o = { network }; - lazy.prop(o, 'address', () => { - if (!o.hash) - return; - const words = bech32.toWords(o.hash); - words.unshift(0x00); - return bech32.encode(network.bech32, words); - }); - lazy.prop(o, 'hash', () => { - if (a.output) - return a.output.slice(2); - if (a.address) - return _address().data; - if (o.redeem && o.redeem.output) - return bcrypto.sha256(o.redeem.output); - }); - lazy.prop(o, 'output', () => { - if (!o.hash) - return; - return bscript.compile([OPS.OP_0, o.hash]); - }); - lazy.prop(o, 'redeem', () => { - if (!a.witness) - return; - return { - output: a.witness[a.witness.length - 1], - input: EMPTY_BUFFER, - witness: a.witness.slice(0, -1), - }; - }); - lazy.prop(o, 'input', () => { - if (!o.witness) - return; - return EMPTY_BUFFER; - }); - lazy.prop(o, 'witness', () => { - // transform redeem input to witness stack? - if (a.redeem && - a.redeem.input && - a.redeem.input.length > 0 && - a.redeem.output && - a.redeem.output.length > 0) { - const stack = bscript.toStack(_rchunks()); - // assign, and blank the existing input - o.redeem = Object.assign({ witness: stack }, a.redeem); - o.redeem.input = EMPTY_BUFFER; - return [].concat(stack, a.redeem.output); - } - if (!a.redeem) - return; - if (!a.redeem.output) - return; - if (!a.redeem.witness) - return; - return [].concat(a.redeem.witness, a.redeem.output); - }); - // extended validation - if (opts.validate) { - let hash = Buffer.from([]); - if (a.address) { - if (_address().prefix !== network.bech32) - throw new TypeError('Invalid prefix or Network mismatch'); - if (_address().version !== 0x00) - throw new TypeError('Invalid address version'); - if (_address().data.length !== 32) - throw new TypeError('Invalid address data'); - hash = _address().data; - } - if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) - throw new TypeError('Hash mismatch'); - else - hash = a.hash; - } - if (a.output) { - if (a.output.length !== 34 || - a.output[0] !== OPS.OP_0 || - a.output[1] !== 0x20) - throw new TypeError('Output is invalid'); - const hash2 = a.output.slice(2); - if (hash.length > 0 && !hash.equals(hash2)) - throw new TypeError('Hash mismatch'); - else - hash = hash2; - } - if (a.redeem) { - if (a.redeem.network && a.redeem.network !== network) - throw new TypeError('Network mismatch'); - // is there two redeem sources? - if (a.redeem.input && - a.redeem.input.length > 0 && - a.redeem.witness && - a.redeem.witness.length > 0) - throw new TypeError('Ambiguous witness source'); - // is the redeem output non-empty? - if (a.redeem.output) { - if (bscript.decompile(a.redeem.output).length === 0) - throw new TypeError('Redeem.output is invalid'); - // match hash against other sources - const hash2 = bcrypto.sha256(a.redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) - throw new TypeError('Hash mismatch'); - else - hash = hash2; - } - if (a.redeem.input && !bscript.isPushOnly(_rchunks())) - throw new TypeError('Non push-only scriptSig'); - if (a.witness && - a.redeem.witness && - !stacksEqual(a.witness, a.redeem.witness)) - throw new TypeError('Witness and redeem.witness mismatch'); - } - if (a.witness) { - if (a.redeem && - a.redeem.output && - !a.redeem.output.equals(a.witness[a.witness.length - 1])) - throw new TypeError('Witness and redeem.output mismatch'); - } + if (!a.redeem) return; + if (!a.redeem.output) return; + if (!a.redeem.witness) return; + return [].concat(a.redeem.witness, a.redeem.output); + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().prefix !== network.bech32) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + hash = _address().data; } - return Object.assign(o, a); + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 34 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x20 + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + // is there two redeem sources? + if ( + a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.witness && + a.redeem.witness.length > 0 + ) + throw new TypeError('Ambiguous witness source'); + // is the redeem output non-empty? + if (a.redeem.output) { + if (bscript.decompile(a.redeem.output).length === 0) + throw new TypeError('Redeem.output is invalid'); + // match hash against other sources + const hash2 = bcrypto.sha256(a.redeem.output); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.redeem.input && !bscript.isPushOnly(_rchunks())) + throw new TypeError('Non push-only scriptSig'); + if ( + a.witness && + a.redeem.witness && + !stacksEqual(a.witness, a.redeem.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); + } + if (a.witness) { + if ( + a.redeem && + a.redeem.output && + !a.redeem.output.equals(a.witness[a.witness.length - 1]) + ) + throw new TypeError('Witness and redeem.output mismatch'); + } + } + return Object.assign(o, a); } exports.p2wsh = p2wsh; diff --git a/src/script.js b/src/script.js index ac334f8..39859dc 100644 --- a/src/script.js +++ b/src/script.js @@ -1,8 +1,8 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const scriptNumber = require("./script_number"); -const scriptSignature = require("./script_signature"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const scriptNumber = require('./script_number'); +const scriptSignature = require('./script_signature'); +const types = require('./types'); const bip66 = require('bip66'); const ecc = require('tiny-secp256k1'); const pushdata = require('pushdata-bitcoin'); @@ -11,179 +11,165 @@ exports.OPS = require('bitcoin-ops'); const REVERSE_OPS = require('bitcoin-ops/map'); const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1 function isOPInt(value) { - return (types.Number(value) && - (value === exports.OPS.OP_0 || - (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || - value === exports.OPS.OP_1NEGATE)); + return ( + types.Number(value) && + (value === exports.OPS.OP_0 || + (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || + value === exports.OPS.OP_1NEGATE) + ); } function isPushOnlyChunk(value) { - return types.Buffer(value) || isOPInt(value); + return types.Buffer(value) || isOPInt(value); } function isPushOnly(value) { - return types.Array(value) && value.every(isPushOnlyChunk); + return types.Array(value) && value.every(isPushOnlyChunk); } exports.isPushOnly = isPushOnly; function asMinimalOP(buffer) { - if (buffer.length === 0) - return exports.OPS.OP_0; - if (buffer.length !== 1) - return; - if (buffer[0] >= 1 && buffer[0] <= 16) - return OP_INT_BASE + buffer[0]; - if (buffer[0] === 0x81) - return exports.OPS.OP_1NEGATE; + if (buffer.length === 0) return exports.OPS.OP_0; + if (buffer.length !== 1) return; + if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; + if (buffer[0] === 0x81) return exports.OPS.OP_1NEGATE; } function chunksIsBuffer(buf) { - return Buffer.isBuffer(buf); + return Buffer.isBuffer(buf); } function chunksIsArray(buf) { - return types.Array(buf); + return types.Array(buf); } function singleChunkIsBuffer(buf) { - return Buffer.isBuffer(buf); + return Buffer.isBuffer(buf); } function compile(chunks) { - // TODO: remove me - if (chunksIsBuffer(chunks)) - return chunks; - typeforce(types.Array, chunks); - const bufferSize = chunks.reduce((accum, chunk) => { - // data chunk - if (singleChunkIsBuffer(chunk)) { - // adhere to BIP62.3, minimal push policy - if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { - return accum + 1; - } - return accum + pushdata.encodingLength(chunk.length) + chunk.length; - } - // opcode + // TODO: remove me + if (chunksIsBuffer(chunks)) return chunks; + typeforce(types.Array, chunks); + const bufferSize = chunks.reduce((accum, chunk) => { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { return accum + 1; - }, 0.0); - const buffer = Buffer.allocUnsafe(bufferSize); - let offset = 0; - chunks.forEach(chunk => { - // data chunk - if (singleChunkIsBuffer(chunk)) { - // adhere to BIP62.3, minimal push policy - const opcode = asMinimalOP(chunk); - if (opcode !== undefined) { - buffer.writeUInt8(opcode, offset); - offset += 1; - return; - } - offset += pushdata.encode(buffer, chunk.length, offset); - chunk.copy(buffer, offset); - offset += chunk.length; - // opcode - } - else { - buffer.writeUInt8(chunk, offset); - offset += 1; - } - }); - if (offset !== buffer.length) - throw new Error('Could not decode chunks'); - return buffer; + } + return accum + pushdata.encodingLength(chunk.length) + chunk.length; + } + // opcode + return accum + 1; + }, 0.0); + const buffer = Buffer.allocUnsafe(bufferSize); + let offset = 0; + chunks.forEach(chunk => { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + const opcode = asMinimalOP(chunk); + if (opcode !== undefined) { + buffer.writeUInt8(opcode, offset); + offset += 1; + return; + } + offset += pushdata.encode(buffer, chunk.length, offset); + chunk.copy(buffer, offset); + offset += chunk.length; + // opcode + } else { + buffer.writeUInt8(chunk, offset); + offset += 1; + } + }); + if (offset !== buffer.length) throw new Error('Could not decode chunks'); + return buffer; } exports.compile = compile; function decompile(buffer) { - // TODO: remove me - if (chunksIsArray(buffer)) - return buffer; - typeforce(types.Buffer, buffer); - const chunks = []; - let i = 0; - while (i < buffer.length) { - const opcode = buffer[i]; - // data chunk - if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) { - const d = pushdata.decode(buffer, i); - // did reading a pushDataInt fail? - if (d === null) - return null; - i += d.size; - // attempt to read too much data? - if (i + d.number > buffer.length) - return null; - const data = buffer.slice(i, i + d.number); - i += d.number; - // decompile minimally - const op = asMinimalOP(data); - if (op !== undefined) { - chunks.push(op); - } - else { - chunks.push(data); - } - // opcode - } - else { - chunks.push(opcode); - i += 1; - } + // TODO: remove me + if (chunksIsArray(buffer)) return buffer; + typeforce(types.Buffer, buffer); + const chunks = []; + let i = 0; + while (i < buffer.length) { + const opcode = buffer[i]; + // data chunk + if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) { + const d = pushdata.decode(buffer, i); + // did reading a pushDataInt fail? + if (d === null) return null; + i += d.size; + // attempt to read too much data? + if (i + d.number > buffer.length) return null; + const data = buffer.slice(i, i + d.number); + i += d.number; + // decompile minimally + const op = asMinimalOP(data); + if (op !== undefined) { + chunks.push(op); + } else { + chunks.push(data); + } + // opcode + } else { + chunks.push(opcode); + i += 1; } - return chunks; + } + return chunks; } exports.decompile = decompile; function toASM(chunks) { - if (chunksIsBuffer(chunks)) { - chunks = decompile(chunks); - } - return chunks - .map(chunk => { - // data? - if (singleChunkIsBuffer(chunk)) { - const op = asMinimalOP(chunk); - if (op === undefined) - return chunk.toString('hex'); - chunk = op; - } - // opcode! - return REVERSE_OPS[chunk]; + if (chunksIsBuffer(chunks)) { + chunks = decompile(chunks); + } + return chunks + .map(chunk => { + // data? + if (singleChunkIsBuffer(chunk)) { + const op = asMinimalOP(chunk); + if (op === undefined) return chunk.toString('hex'); + chunk = op; + } + // opcode! + return REVERSE_OPS[chunk]; }) - .join(' '); + .join(' '); } exports.toASM = toASM; function fromASM(asm) { - typeforce(types.String, asm); - return compile(asm.split(' ').map(chunkStr => { - // opcode? - if (exports.OPS[chunkStr] !== undefined) - return exports.OPS[chunkStr]; - typeforce(types.Hex, chunkStr); - // data! - return Buffer.from(chunkStr, 'hex'); - })); + typeforce(types.String, asm); + return compile( + asm.split(' ').map(chunkStr => { + // opcode? + if (exports.OPS[chunkStr] !== undefined) return exports.OPS[chunkStr]; + typeforce(types.Hex, chunkStr); + // data! + return Buffer.from(chunkStr, 'hex'); + }), + ); } exports.fromASM = fromASM; function toStack(chunks) { - chunks = decompile(chunks); - typeforce(isPushOnly, chunks); - return chunks.map(op => { - if (singleChunkIsBuffer(op)) - return op; - if (op === exports.OPS.OP_0) - return Buffer.allocUnsafe(0); - return scriptNumber.encode(op - OP_INT_BASE); - }); + chunks = decompile(chunks); + typeforce(isPushOnly, chunks); + return chunks.map(op => { + if (singleChunkIsBuffer(op)) return op; + if (op === exports.OPS.OP_0) return Buffer.allocUnsafe(0); + return scriptNumber.encode(op - OP_INT_BASE); + }); } exports.toStack = toStack; function isCanonicalPubKey(buffer) { - return ecc.isPoint(buffer); + return ecc.isPoint(buffer); } exports.isCanonicalPubKey = isCanonicalPubKey; function isDefinedHashType(hashType) { - const hashTypeMod = hashType & ~0x80; - // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE - return hashTypeMod > 0x00 && hashTypeMod < 0x04; + const hashTypeMod = hashType & ~0x80; + // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE + return hashTypeMod > 0x00 && hashTypeMod < 0x04; } exports.isDefinedHashType = isDefinedHashType; function isCanonicalScriptSignature(buffer) { - if (!Buffer.isBuffer(buffer)) - return false; - if (!isDefinedHashType(buffer[buffer.length - 1])) - return false; - return bip66.check(buffer.slice(0, -1)); + if (!Buffer.isBuffer(buffer)) return false; + if (!isDefinedHashType(buffer[buffer.length - 1])) return false; + return bip66.check(buffer.slice(0, -1)); } exports.isCanonicalScriptSignature = isCanonicalScriptSignature; // tslint:disable-next-line variable-name diff --git a/src/script_number.js b/src/script_number.js index 3a30a43..3f313af 100644 --- a/src/script_number.js +++ b/src/script_number.js @@ -1,65 +1,61 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); function decode(buffer, maxLength, minimal) { - maxLength = maxLength || 4; - minimal = minimal === undefined ? true : minimal; - const length = buffer.length; - if (length === 0) - return 0; - if (length > maxLength) - throw new TypeError('Script number overflow'); - if (minimal) { - if ((buffer[length - 1] & 0x7f) === 0) { - if (length <= 1 || (buffer[length - 2] & 0x80) === 0) - throw new Error('Non-minimally encoded script number'); - } + maxLength = maxLength || 4; + minimal = minimal === undefined ? true : minimal; + const length = buffer.length; + if (length === 0) return 0; + if (length > maxLength) throw new TypeError('Script number overflow'); + if (minimal) { + if ((buffer[length - 1] & 0x7f) === 0) { + if (length <= 1 || (buffer[length - 2] & 0x80) === 0) + throw new Error('Non-minimally encoded script number'); } - // 40-bit - if (length === 5) { - const a = buffer.readUInt32LE(0); - const b = buffer.readUInt8(4); - if (b & 0x80) - return -((b & ~0x80) * 0x100000000 + a); - return b * 0x100000000 + a; - } - // 32-bit / 24-bit / 16-bit / 8-bit - let result = 0; - for (let i = 0; i < length; ++i) { - result |= buffer[i] << (8 * i); - } - if (buffer[length - 1] & 0x80) - return -(result & ~(0x80 << (8 * (length - 1)))); - return result; + } + // 40-bit + if (length === 5) { + const a = buffer.readUInt32LE(0); + const b = buffer.readUInt8(4); + if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); + return b * 0x100000000 + a; + } + // 32-bit / 24-bit / 16-bit / 8-bit + let result = 0; + for (let i = 0; i < length; ++i) { + result |= buffer[i] << (8 * i); + } + if (buffer[length - 1] & 0x80) + return -(result & ~(0x80 << (8 * (length - 1)))); + return result; } exports.decode = decode; function scriptNumSize(i) { - return i > 0x7fffffff - ? 5 - : i > 0x7fffff - ? 4 - : i > 0x7fff - ? 3 - : i > 0x7f - ? 2 - : i > 0x00 - ? 1 - : 0; + return i > 0x7fffffff + ? 5 + : i > 0x7fffff + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; } function encode(_number) { - let value = Math.abs(_number); - const size = scriptNumSize(value); - const buffer = Buffer.allocUnsafe(size); - const negative = _number < 0; - for (let i = 0; i < size; ++i) { - buffer.writeUInt8(value & 0xff, i); - value >>= 8; - } - if (buffer[size - 1] & 0x80) { - buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); - } - else if (negative) { - buffer[size - 1] |= 0x80; - } - return buffer; + let value = Math.abs(_number); + const size = scriptNumSize(value); + const buffer = Buffer.allocUnsafe(size); + const negative = _number < 0; + for (let i = 0; i < size; ++i) { + buffer.writeUInt8(value & 0xff, i); + value >>= 8; + } + if (buffer[size - 1] & 0x80) { + buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + } else if (negative) { + buffer[size - 1] |= 0x80; + } + return buffer; } exports.encode = encode; diff --git a/src/script_signature.js b/src/script_signature.js index a1f2f22..fb52fe9 100644 --- a/src/script_signature.js +++ b/src/script_signature.js @@ -1,53 +1,52 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const types = require('./types'); const bip66 = require('bip66'); const typeforce = require('typeforce'); const ZERO = Buffer.alloc(1, 0); function toDER(x) { - let i = 0; - while (x[i] === 0) - ++i; - if (i === x.length) - return ZERO; - x = x.slice(i); - if (x[0] & 0x80) - return Buffer.concat([ZERO, x], 1 + x.length); - return x; + let i = 0; + while (x[i] === 0) ++i; + if (i === x.length) return ZERO; + x = x.slice(i); + if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + return x; } function fromDER(x) { - if (x[0] === 0x00) - x = x.slice(1); - const buffer = Buffer.alloc(32, 0); - const bstart = Math.max(0, 32 - x.length); - x.copy(buffer, bstart); - return buffer; + if (x[0] === 0x00) x = x.slice(1); + const buffer = Buffer.alloc(32, 0); + const bstart = Math.max(0, 32 - x.length); + x.copy(buffer, bstart); + return buffer; } // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) function decode(buffer) { - const hashType = buffer.readUInt8(buffer.length - 1); - const hashTypeMod = hashType & ~0x80; - if (hashTypeMod <= 0 || hashTypeMod >= 4) - throw new Error('Invalid hashType ' + hashType); - const decoded = bip66.decode(buffer.slice(0, -1)); - const r = fromDER(decoded.r); - const s = fromDER(decoded.s); - const signature = Buffer.concat([r, s], 64); - return { signature, hashType }; + const hashType = buffer.readUInt8(buffer.length - 1); + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); + const decoded = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decoded.r); + const s = fromDER(decoded.s); + const signature = Buffer.concat([r, s], 64); + return { signature, hashType }; } exports.decode = decode; function encode(signature, hashType) { - typeforce({ - signature: types.BufferN(64), - hashType: types.UInt8, - }, { signature, hashType }); - const hashTypeMod = hashType & ~0x80; - if (hashTypeMod <= 0 || hashTypeMod >= 4) - throw new Error('Invalid hashType ' + hashType); - const hashTypeBuffer = Buffer.allocUnsafe(1); - hashTypeBuffer.writeUInt8(hashType, 0); - const r = toDER(signature.slice(0, 32)); - const s = toDER(signature.slice(32, 64)); - return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + typeforce( + { + signature: types.BufferN(64), + hashType: types.UInt8, + }, + { signature, hashType }, + ); + const hashTypeMod = hashType & ~0x80; + if (hashTypeMod <= 0 || hashTypeMod >= 4) + throw new Error('Invalid hashType ' + hashType); + const hashTypeBuffer = Buffer.allocUnsafe(1); + hashTypeBuffer.writeUInt8(hashType, 0); + const r = toDER(signature.slice(0, 32)); + const s = toDER(signature.slice(32, 64)); + return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); } exports.encode = encode; diff --git a/src/templates/multisig/index.js b/src/templates/multisig/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/multisig/index.js +++ b/src/templates/multisig/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.js index 4b4f395..403c2f7 100644 --- a/src/templates/multisig/input.js +++ b/src/templates/multisig/input.js @@ -1,23 +1,23 @@ -"use strict"; +'use strict'; // OP_0 [signatures ...] -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function partialSignature(value) { - return (value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value)); + return ( + value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value) + ); } function check(script, allowIncomplete) { - const chunks = bscript.decompile(script); - if (chunks.length < 2) - return false; - if (chunks[0] !== script_1.OPS.OP_0) - return false; - if (allowIncomplete) { - return chunks.slice(1).every(partialSignature); - } - return chunks.slice(1).every(bscript.isCanonicalScriptSignature); + const chunks = bscript.decompile(script); + if (chunks.length < 2) return false; + if (chunks[0] !== script_1.OPS.OP_0) return false; + if (allowIncomplete) { + return chunks.slice(1).every(partialSignature); + } + return chunks.slice(1).every(bscript.isCanonicalScriptSignature); } exports.check = check; check.toJSON = () => { - return 'multisig input'; + return 'multisig input'; }; diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.js index c79fe9b..0896605 100644 --- a/src/templates/multisig/output.js +++ b/src/templates/multisig/output.js @@ -1,36 +1,27 @@ -"use strict"; +'use strict'; // m [pubKeys ...] n OP_CHECKMULTISIG -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); -const types = require("../../types"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); +const types = require('../../types'); const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1 function check(script, allowIncomplete) { - const chunks = bscript.decompile(script); - if (chunks.length < 4) - return false; - if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) - return false; - if (!types.Number(chunks[0])) - return false; - if (!types.Number(chunks[chunks.length - 2])) - return false; - const m = chunks[0] - OP_INT_BASE; - const n = chunks[chunks.length - 2] - OP_INT_BASE; - if (m <= 0) - return false; - if (n > 16) - return false; - if (m > n) - return false; - if (n !== chunks.length - 3) - return false; - if (allowIncomplete) - return true; - const keys = chunks.slice(1, -2); - return keys.every(bscript.isCanonicalPubKey); + const chunks = bscript.decompile(script); + if (chunks.length < 4) return false; + if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) return false; + if (!types.Number(chunks[0])) return false; + if (!types.Number(chunks[chunks.length - 2])) return false; + const m = chunks[0] - OP_INT_BASE; + const n = chunks[chunks.length - 2] - OP_INT_BASE; + if (m <= 0) return false; + if (n > 16) return false; + if (m > n) return false; + if (n !== chunks.length - 3) return false; + if (allowIncomplete) return true; + const keys = chunks.slice(1, -2); + return keys.every(bscript.isCanonicalPubKey); } exports.check = check; check.toJSON = () => { - return 'multi-sig output'; + return 'multi-sig output'; }; diff --git a/src/templates/nulldata.js b/src/templates/nulldata.js index 29bee7a..50355d3 100644 --- a/src/templates/nulldata.js +++ b/src/templates/nulldata.js @@ -1,15 +1,15 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); // OP_RETURN {data} -const bscript = require("../script"); +const bscript = require('../script'); const OPS = bscript.OPS; function check(script) { - const buffer = bscript.compile(script); - return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; + const buffer = bscript.compile(script); + return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; } exports.check = check; check.toJSON = () => { - return 'null data output'; + return 'null data output'; }; const output = { check }; exports.output = output; diff --git a/src/templates/pubkey/index.js b/src/templates/pubkey/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/pubkey/index.js +++ b/src/templates/pubkey/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.js index 479fdc5..9715b80 100644 --- a/src/templates/pubkey/input.js +++ b/src/templates/pubkey/input.js @@ -1,13 +1,12 @@ -"use strict"; +'use strict'; // {signature} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); function check(script) { - const chunks = bscript.decompile(script); - return (chunks.length === 1 && - bscript.isCanonicalScriptSignature(chunks[0])); + const chunks = bscript.decompile(script); + return chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]); } exports.check = check; check.toJSON = () => { - return 'pubKey input'; + return 'pubKey input'; }; diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.js index 1f17990..2edb731 100644 --- a/src/templates/pubkey/output.js +++ b/src/templates/pubkey/output.js @@ -1,15 +1,17 @@ -"use strict"; +'use strict'; // {pubKey} OP_CHECKSIG -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function check(script) { - const chunks = bscript.decompile(script); - return (chunks.length === 2 && - bscript.isCanonicalPubKey(chunks[0]) && - chunks[1] === script_1.OPS.OP_CHECKSIG); + const chunks = bscript.decompile(script); + return ( + chunks.length === 2 && + bscript.isCanonicalPubKey(chunks[0]) && + chunks[1] === script_1.OPS.OP_CHECKSIG + ); } exports.check = check; check.toJSON = () => { - return 'pubKey output'; + return 'pubKey output'; }; diff --git a/src/templates/pubkeyhash/index.js b/src/templates/pubkeyhash/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/pubkeyhash/index.js +++ b/src/templates/pubkeyhash/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.js index 7de30ec..14d72cc 100644 --- a/src/templates/pubkeyhash/input.js +++ b/src/templates/pubkeyhash/input.js @@ -1,14 +1,16 @@ -"use strict"; +'use strict'; // {signature} {pubKey} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); function check(script) { - const chunks = bscript.decompile(script); - return (chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - bscript.isCanonicalPubKey(chunks[1])); + const chunks = bscript.decompile(script); + return ( + chunks.length === 2 && + bscript.isCanonicalScriptSignature(chunks[0]) && + bscript.isCanonicalPubKey(chunks[1]) + ); } exports.check = check; check.toJSON = () => { - return 'pubKeyHash input'; + return 'pubKeyHash input'; }; diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.js index 5ee692b..079e1ed 100644 --- a/src/templates/pubkeyhash/output.js +++ b/src/templates/pubkeyhash/output.js @@ -1,18 +1,20 @@ -"use strict"; +'use strict'; // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function check(script) { - const buffer = bscript.compile(script); - return (buffer.length === 25 && - buffer[0] === script_1.OPS.OP_DUP && - buffer[1] === script_1.OPS.OP_HASH160 && - buffer[2] === 0x14 && - buffer[23] === script_1.OPS.OP_EQUALVERIFY && - buffer[24] === script_1.OPS.OP_CHECKSIG); + const buffer = bscript.compile(script); + return ( + buffer.length === 25 && + buffer[0] === script_1.OPS.OP_DUP && + buffer[1] === script_1.OPS.OP_HASH160 && + buffer[2] === 0x14 && + buffer[23] === script_1.OPS.OP_EQUALVERIFY && + buffer[24] === script_1.OPS.OP_CHECKSIG + ); } exports.check = check; check.toJSON = () => { - return 'pubKeyHash output'; + return 'pubKeyHash output'; }; diff --git a/src/templates/scripthash/index.js b/src/templates/scripthash/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/scripthash/index.js +++ b/src/templates/scripthash/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.js index 488b931..999cc83 100644 --- a/src/templates/scripthash/input.js +++ b/src/templates/scripthash/input.js @@ -1,44 +1,50 @@ -"use strict"; +'use strict'; // {serialized scriptPubKey script} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const p2ms = require("../multisig"); -const p2pk = require("../pubkey"); -const p2pkh = require("../pubkeyhash"); -const p2wpkho = require("../witnesspubkeyhash/output"); -const p2wsho = require("../witnessscripthash/output"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const p2ms = require('../multisig'); +const p2pk = require('../pubkey'); +const p2pkh = require('../pubkeyhash'); +const p2wpkho = require('../witnesspubkeyhash/output'); +const p2wsho = require('../witnessscripthash/output'); function check(script, allowIncomplete) { - const chunks = bscript.decompile(script); - if (chunks.length < 1) - return false; - const lastChunk = chunks[chunks.length - 1]; - if (!Buffer.isBuffer(lastChunk)) - return false; - const scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))); - const redeemScriptChunks = bscript.decompile(lastChunk); - // is redeemScript a valid script? - if (!redeemScriptChunks) - return false; - // is redeemScriptSig push only? - if (!bscript.isPushOnly(scriptSigChunks)) - return false; - // is witness? - if (chunks.length === 1) { - return (p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks)); - } - // match types - if (p2pkh.input.check(scriptSigChunks) && - p2pkh.output.check(redeemScriptChunks)) - return true; - if (p2ms.input.check(scriptSigChunks, allowIncomplete) && - p2ms.output.check(redeemScriptChunks)) - return true; - if (p2pk.input.check(scriptSigChunks) && - p2pk.output.check(redeemScriptChunks)) - return true; - return false; + const chunks = bscript.decompile(script); + if (chunks.length < 1) return false; + const lastChunk = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(lastChunk)) return false; + const scriptSigChunks = bscript.decompile( + bscript.compile(chunks.slice(0, -1)), + ); + const redeemScriptChunks = bscript.decompile(lastChunk); + // is redeemScript a valid script? + if (!redeemScriptChunks) return false; + // is redeemScriptSig push only? + if (!bscript.isPushOnly(scriptSigChunks)) return false; + // is witness? + if (chunks.length === 1) { + return ( + p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks) + ); + } + // match types + if ( + p2pkh.input.check(scriptSigChunks) && + p2pkh.output.check(redeemScriptChunks) + ) + return true; + if ( + p2ms.input.check(scriptSigChunks, allowIncomplete) && + p2ms.output.check(redeemScriptChunks) + ) + return true; + if ( + p2pk.input.check(scriptSigChunks) && + p2pk.output.check(redeemScriptChunks) + ) + return true; + return false; } exports.check = check; check.toJSON = () => { - return 'scriptHash input'; + return 'scriptHash input'; }; diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.js index bf1246a..3797003 100644 --- a/src/templates/scripthash/output.js +++ b/src/templates/scripthash/output.js @@ -1,16 +1,18 @@ -"use strict"; +'use strict'; // OP_HASH160 {scriptHash} OP_EQUAL -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function check(script) { - const buffer = bscript.compile(script); - return (buffer.length === 23 && - buffer[0] === script_1.OPS.OP_HASH160 && - buffer[1] === 0x14 && - buffer[22] === script_1.OPS.OP_EQUAL); + const buffer = bscript.compile(script); + return ( + buffer.length === 23 && + buffer[0] === script_1.OPS.OP_HASH160 && + buffer[1] === 0x14 && + buffer[22] === script_1.OPS.OP_EQUAL + ); } exports.check = check; check.toJSON = () => { - return 'scriptHash output'; + return 'scriptHash output'; }; diff --git a/src/templates/witnesscommitment/index.js b/src/templates/witnesscommitment/index.js index aff0618..099ac72 100644 --- a/src/templates/witnesscommitment/index.js +++ b/src/templates/witnesscommitment/index.js @@ -1,4 +1,4 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const output = require("./output"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const output = require('./output'); exports.output = output; diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.js index f4d6af0..fb1d59c 100644 --- a/src/templates/witnesscommitment/output.js +++ b/src/templates/witnesscommitment/output.js @@ -1,32 +1,34 @@ -"use strict"; +'use strict'; // OP_RETURN {aa21a9ed} {commitment} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); -const types = require("../../types"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); +const types = require('../../types'); const typeforce = require('typeforce'); const HEADER = Buffer.from('aa21a9ed', 'hex'); function check(script) { - const buffer = bscript.compile(script); - return (buffer.length > 37 && - buffer[0] === script_1.OPS.OP_RETURN && - buffer[1] === 0x24 && - buffer.slice(2, 6).equals(HEADER)); + const buffer = bscript.compile(script); + return ( + buffer.length > 37 && + buffer[0] === script_1.OPS.OP_RETURN && + buffer[1] === 0x24 && + buffer.slice(2, 6).equals(HEADER) + ); } exports.check = check; check.toJSON = () => { - return 'Witness commitment output'; + return 'Witness commitment output'; }; function encode(commitment) { - typeforce(types.Hash256bit, commitment); - const buffer = Buffer.allocUnsafe(36); - HEADER.copy(buffer, 0); - commitment.copy(buffer, 4); - return bscript.compile([script_1.OPS.OP_RETURN, buffer]); + typeforce(types.Hash256bit, commitment); + const buffer = Buffer.allocUnsafe(36); + HEADER.copy(buffer, 0); + commitment.copy(buffer, 4); + return bscript.compile([script_1.OPS.OP_RETURN, buffer]); } exports.encode = encode; function decode(buffer) { - typeforce(check, buffer); - return bscript.decompile(buffer)[1].slice(4, 36); + typeforce(check, buffer); + return bscript.decompile(buffer)[1].slice(4, 36); } exports.decode = decode; diff --git a/src/templates/witnesspubkeyhash/index.js b/src/templates/witnesspubkeyhash/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/witnesspubkeyhash/index.js +++ b/src/templates/witnesspubkeyhash/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.js index 3d589e9..4343584 100644 --- a/src/templates/witnesspubkeyhash/input.js +++ b/src/templates/witnesspubkeyhash/input.js @@ -1,17 +1,19 @@ -"use strict"; +'use strict'; // {signature} {pubKey} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); function isCompressedCanonicalPubKey(pubKey) { - return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; + return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; } function check(script) { - const chunks = bscript.decompile(script); - return (chunks.length === 2 && - bscript.isCanonicalScriptSignature(chunks[0]) && - isCompressedCanonicalPubKey(chunks[1])); + const chunks = bscript.decompile(script); + return ( + chunks.length === 2 && + bscript.isCanonicalScriptSignature(chunks[0]) && + isCompressedCanonicalPubKey(chunks[1]) + ); } exports.check = check; check.toJSON = () => { - return 'witnessPubKeyHash input'; + return 'witnessPubKeyHash input'; }; diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.js index 69aab11..ea5ed1e 100644 --- a/src/templates/witnesspubkeyhash/output.js +++ b/src/templates/witnesspubkeyhash/output.js @@ -1,13 +1,17 @@ -"use strict"; +'use strict'; // OP_0 {pubKeyHash} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function check(script) { - const buffer = bscript.compile(script); - return buffer.length === 22 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x14; + const buffer = bscript.compile(script); + return ( + buffer.length === 22 && + buffer[0] === script_1.OPS.OP_0 && + buffer[1] === 0x14 + ); } exports.check = check; check.toJSON = () => { - return 'Witness pubKeyHash output'; + return 'Witness pubKeyHash output'; }; diff --git a/src/templates/witnessscripthash/index.js b/src/templates/witnessscripthash/index.js index 85a15b9..b8cd6c4 100644 --- a/src/templates/witnessscripthash/index.js +++ b/src/templates/witnessscripthash/index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const input = require("./input"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const input = require('./input'); exports.input = input; -const output = require("./output"); +const output = require('./output'); exports.output = output; diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.js index 3f5c002..f69a810 100644 --- a/src/templates/witnessscripthash/input.js +++ b/src/templates/witnessscripthash/input.js @@ -1,36 +1,39 @@ -"use strict"; +'use strict'; // {serialized scriptPubKey script} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); const typeforce = require('typeforce'); -const p2ms = require("../multisig"); -const p2pk = require("../pubkey"); -const p2pkh = require("../pubkeyhash"); +const p2ms = require('../multisig'); +const p2pk = require('../pubkey'); +const p2pkh = require('../pubkeyhash'); function check(chunks, allowIncomplete) { - typeforce(typeforce.Array, chunks); - if (chunks.length < 1) - return false; - const witnessScript = chunks[chunks.length - 1]; - if (!Buffer.isBuffer(witnessScript)) - return false; - const witnessScriptChunks = bscript.decompile(witnessScript); - // is witnessScript a valid script? - if (!witnessScriptChunks || witnessScriptChunks.length === 0) - return false; - const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); - // match types - if (p2pkh.input.check(witnessRawScriptSig) && - p2pkh.output.check(witnessScriptChunks)) - return true; - if (p2ms.input.check(witnessRawScriptSig, allowIncomplete) && - p2ms.output.check(witnessScriptChunks)) - return true; - if (p2pk.input.check(witnessRawScriptSig) && - p2pk.output.check(witnessScriptChunks)) - return true; - return false; + typeforce(typeforce.Array, chunks); + if (chunks.length < 1) return false; + const witnessScript = chunks[chunks.length - 1]; + if (!Buffer.isBuffer(witnessScript)) return false; + const witnessScriptChunks = bscript.decompile(witnessScript); + // is witnessScript a valid script? + if (!witnessScriptChunks || witnessScriptChunks.length === 0) return false; + const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); + // match types + if ( + p2pkh.input.check(witnessRawScriptSig) && + p2pkh.output.check(witnessScriptChunks) + ) + return true; + if ( + p2ms.input.check(witnessRawScriptSig, allowIncomplete) && + p2ms.output.check(witnessScriptChunks) + ) + return true; + if ( + p2pk.input.check(witnessRawScriptSig) && + p2pk.output.check(witnessScriptChunks) + ) + return true; + return false; } exports.check = check; check.toJSON = () => { - return 'witnessScriptHash input'; + return 'witnessScriptHash input'; }; diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.js index a6d4d95..f69a429 100644 --- a/src/templates/witnessscripthash/output.js +++ b/src/templates/witnessscripthash/output.js @@ -1,13 +1,17 @@ -"use strict"; +'use strict'; // OP_0 {scriptHash} -Object.defineProperty(exports, "__esModule", { value: true }); -const bscript = require("../../script"); -const script_1 = require("../../script"); +Object.defineProperty(exports, '__esModule', { value: true }); +const bscript = require('../../script'); +const script_1 = require('../../script'); function check(script) { - const buffer = bscript.compile(script); - return buffer.length === 34 && buffer[0] === script_1.OPS.OP_0 && buffer[1] === 0x20; + const buffer = bscript.compile(script); + return ( + buffer.length === 34 && + buffer[0] === script_1.OPS.OP_0 && + buffer[1] === 0x20 + ); } exports.check = check; check.toJSON = () => { - return 'Witness scriptHash output'; + return 'Witness scriptHash output'; }; diff --git a/src/transaction.js b/src/transaction.js index c6c847a..c4e6506 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,446 +1,472 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bufferutils = require("./bufferutils"); -const bufferutils_1 = require("./bufferutils"); -const bcrypto = require("./crypto"); -const bscript = require("./script"); -const script_1 = require("./script"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const bufferutils = require('./bufferutils'); +const bufferutils_1 = require('./bufferutils'); +const bcrypto = require('./crypto'); +const bscript = require('./script'); +const script_1 = require('./script'); +const types = require('./types'); const typeforce = require('typeforce'); const varuint = require('varuint-bitcoin'); function varSliceSize(someScript) { - const length = someScript.length; - return varuint.encodingLength(length) + length; + const length = someScript.length; + return varuint.encodingLength(length) + length; } function vectorSize(someVector) { - const length = someVector.length; - return (varuint.encodingLength(length) + - someVector.reduce((sum, witness) => { - return sum + varSliceSize(witness); - }, 0)); + const length = someVector.length; + return ( + varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0) + ); } const EMPTY_SCRIPT = Buffer.allocUnsafe(0); const EMPTY_WITNESS = []; -const ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); -const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); +const ZERO = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', +); +const ONE = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex', +); const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT = { - script: EMPTY_SCRIPT, - valueBuffer: VALUE_UINT64_MAX, + script: EMPTY_SCRIPT, + valueBuffer: VALUE_UINT64_MAX, }; function isOutput(out) { - return out.value !== undefined; + return out.value !== undefined; } class Transaction { - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; - } - static fromBuffer(buffer, _NO_STRICT) { - let offset = 0; - function readSlice(n) { - offset += n; - return buffer.slice(offset - n, offset); - } - function readUInt32() { - const i = buffer.readUInt32LE(offset); - offset += 4; - return i; - } - function readInt32() { - const i = buffer.readInt32LE(offset); - offset += 4; - return i; - } - function readUInt64() { - const i = bufferutils.readUInt64LE(buffer, offset); - offset += 8; - return i; - } - function readVarInt() { - const vi = varuint.decode(buffer, offset); - offset += varuint.decode.bytes; - return vi; - } - function readVarSlice() { - return readSlice(readVarInt()); - } - function readVector() { - const count = readVarInt(); - const vector = []; - for (let i = 0; i < count; i++) - vector.push(readVarSlice()); - return vector; - } - const tx = new Transaction(); - tx.version = readInt32(); - const marker = buffer.readUInt8(offset); - const flag = buffer.readUInt8(offset + 1); - let hasWitnesses = false; - if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && - flag === Transaction.ADVANCED_TRANSACTION_FLAG) { - offset += 2; - hasWitnesses = true; - } - const vinLen = readVarInt(); - for (let i = 0; i < vinLen; ++i) { - tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), - witness: EMPTY_WITNESS, - }); - } - const voutLen = readVarInt(); - for (let i = 0; i < voutLen; ++i) { - tx.outs.push({ - value: readUInt64(), - script: readVarSlice(), - }); - } - if (hasWitnesses) { - for (let i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector(); - } - // was this pointless? - if (!tx.hasWitnesses()) - throw new Error('Transaction has superfluous witness data'); - } - tx.locktime = readUInt32(); - if (_NO_STRICT) - return tx; - if (offset !== buffer.length) - throw new Error('Transaction has unexpected data'); - return tx; - } - static fromHex(hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); - } - static isCoinbaseHash(buffer) { - typeforce(types.Hash256bit, buffer); - for (let i = 0; i < 32; ++i) { - if (buffer[i] !== 0) - return false; - } - return true; - } - isCoinbase() { - return (this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)); - } - addInput(hash, index, sequence, scriptSig) { - typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); - if (types.Null(sequence)) { - sequence = Transaction.DEFAULT_SEQUENCE; - } - // Add the input and return the input's index - return (this.ins.push({ - hash, - index, - script: scriptSig || EMPTY_SCRIPT, - sequence: sequence, - witness: EMPTY_WITNESS, - }) - 1); - } - addOutput(scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); - // Add the output and return the output's index - return (this.outs.push({ - script: scriptPubKey, - value, - }) - 1); - } - hasWitnesses() { - return this.ins.some(x => { - return x.witness.length !== 0; - }); - } - weight() { - const base = this.__byteLength(false); - const total = this.__byteLength(true); - return base * 3 + total; - } - virtualSize() { - return Math.ceil(this.weight() / 4); - } - byteLength() { - return this.__byteLength(true); - } - clone() { - const newTx = new Transaction(); - newTx.version = this.version; - newTx.locktime = this.locktime; - newTx.ins = this.ins.map(txIn => { - return { - hash: txIn.hash, - index: txIn.index, - script: txIn.script, - sequence: txIn.sequence, - witness: txIn.witness, - }; - }); - newTx.outs = this.outs.map(txOut => { - return { - script: txOut.script, - value: txOut.value, - }; - }); - return newTx; - } - /** - * Hash transaction for signing a specific input. - * - * Bitcoin uses a different hash for each signed transaction input. - * This method copies the transaction, makes the necessary changes based on the - * hashType, and then hashes the result. - * This hash can then be used to sign the provided transaction input. - */ - hashForSignature(inIndex, prevOutScript, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments); - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 - if (inIndex >= this.ins.length) - return ONE; - // ignore OP_CODESEPARATOR - const ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(x => { - return x !== script_1.OPS.OP_CODESEPARATOR; - })); - const txTmp = this.clone(); - // SIGHASH_NONE: ignore all outputs? (wildcard payee) - if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { - txTmp.outs = []; - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, i) => { - if (i === inIndex) - return; - input.sequence = 0; - }); - // SIGHASH_SINGLE: ignore all outputs, except at the same index? - } - else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { - // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 - if (inIndex >= this.outs.length) - return ONE; - // truncate outputs after - txTmp.outs.length = inIndex + 1; - // "blank" outputs before - for (let i = 0; i < inIndex; i++) { - txTmp.outs[i] = BLANK_OUTPUT; - } - // ignore sequence numbers (except at inIndex) - txTmp.ins.forEach((input, y) => { - if (y === inIndex) - return; - input.sequence = 0; - }); - } - // SIGHASH_ANYONECANPAY: ignore inputs entirely? - if (hashType & Transaction.SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]]; - txTmp.ins[0].script = ourScript; - // SIGHASH_ALL: only ignore input scripts - } - else { - // "blank" others input scripts - txTmp.ins.forEach(input => { - input.script = EMPTY_SCRIPT; - }); - txTmp.ins[inIndex].script = ourScript; - } - // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); - txTmp.__toBuffer(buffer, 0, false); - return bcrypto.hash256(buffer); - } - hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments); - let tbuffer = Buffer.from([]); - let toffset = 0; - function writeSlice(slice) { - toffset += slice.copy(tbuffer, toffset); - } - function writeUInt32(i) { - toffset = tbuffer.writeUInt32LE(i, toffset); - } - function writeUInt64(i) { - toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset); - } - function writeVarInt(i) { - varuint.encode(i, tbuffer, toffset); - toffset += varuint.encode.bytes; - } - function writeVarSlice(slice) { - writeVarInt(slice.length); - writeSlice(slice); - } - let hashOutputs = ZERO; - let hashPrevouts = ZERO; - let hashSequence = ZERO; - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); - toffset = 0; - this.ins.forEach(txIn => { - writeSlice(txIn.hash); - writeUInt32(txIn.index); - }); - hashPrevouts = bcrypto.hash256(tbuffer); - } - if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && - (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); - toffset = 0; - this.ins.forEach(txIn => { - writeUInt32(txIn.sequence); - }); - hashSequence = bcrypto.hash256(tbuffer); - } - if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && - (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { - const txOutsSize = this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); - toffset = 0; - this.outs.forEach(out => { - writeUInt64(out.value); - writeVarSlice(out.script); - }); - hashOutputs = bcrypto.hash256(tbuffer); - } - else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && - inIndex < this.outs.length) { - const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); - toffset = 0; - writeUInt64(output.value); - writeVarSlice(output.script); - hashOutputs = bcrypto.hash256(tbuffer); - } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); - toffset = 0; - const input = this.ins[inIndex]; - writeUInt32(this.version); - writeSlice(hashPrevouts); - writeSlice(hashSequence); - writeSlice(input.hash); - writeUInt32(input.index); - writeVarSlice(prevOutScript); - writeUInt64(value); - writeUInt32(input.sequence); - writeSlice(hashOutputs); - writeUInt32(this.locktime); - writeUInt32(hashType); - return bcrypto.hash256(tbuffer); - } - getHash(forWitness) { - // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) - return Buffer.alloc(32, 0); - return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); - } - getId() { - // transaction hash's are displayed in reverse order - return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex'); - } - toBuffer(buffer, initialOffset) { - return this.__toBuffer(buffer, initialOffset, true); - } - toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); - } - setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); - this.ins[index].script = scriptSig; - } - setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); - this.ins[index].witness = witness; - } - __byteLength(_ALLOW_WITNESS) { - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - return ((hasWitnesses ? 10 : 8) + - varuint.encodingLength(this.ins.length) + - varuint.encodingLength(this.outs.length) + - this.ins.reduce((sum, input) => { - return sum + 40 + varSliceSize(input.script); - }, 0) + - this.outs.reduce((sum, output) => { - return sum + 8 + varSliceSize(output.script); - }, 0) + - (hasWitnesses - ? this.ins.reduce((sum, input) => { - return sum + vectorSize(input.witness); - }, 0) - : 0)); - } - __toBuffer(buffer, initialOffset, _ALLOW_WITNESS) { - if (!buffer) - buffer = Buffer.allocUnsafe(this.__byteLength(_ALLOW_WITNESS)); - let offset = initialOffset || 0; - function writeSlice(slice) { - offset += slice.copy(buffer, offset); - } - function writeUInt8(i) { - offset = buffer.writeUInt8(i, offset); - } - function writeUInt32(i) { - offset = buffer.writeUInt32LE(i, offset); - } - function writeInt32(i) { - offset = buffer.writeInt32LE(i, offset); - } - function writeUInt64(i) { - offset = bufferutils.writeUInt64LE(buffer, i, offset); - } - function writeVarInt(i) { - varuint.encode(i, buffer, offset); - offset += varuint.encode.bytes; - } - function writeVarSlice(slice) { - writeVarInt(slice.length); - writeSlice(slice); - } - function writeVector(vector) { - writeVarInt(vector.length); - vector.forEach(writeVarSlice); - } - writeInt32(this.version); - const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); - if (hasWitnesses) { - writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); - writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); - } - writeVarInt(this.ins.length); - this.ins.forEach(txIn => { - writeSlice(txIn.hash); - writeUInt32(txIn.index); - writeVarSlice(txIn.script); - writeUInt32(txIn.sequence); - }); - writeVarInt(this.outs.length); - this.outs.forEach(txOut => { - if (isOutput(txOut)) { - writeUInt64(txOut.value); - } - else { - writeSlice(txOut.valueBuffer); - } - writeVarSlice(txOut.script); - }); - if (hasWitnesses) { - this.ins.forEach(input => { - writeVector(input.witness); - }); - } - writeUInt32(this.locktime); - // avoid slicing unless necessary - if (initialOffset !== undefined) - return buffer.slice(initialOffset, offset); - return buffer; + constructor() { + this.version = 1; + this.locktime = 0; + this.ins = []; + this.outs = []; + } + static fromBuffer(buffer, _NO_STRICT) { + let offset = 0; + function readSlice(n) { + offset += n; + return buffer.slice(offset - n, offset); } + function readUInt32() { + const i = buffer.readUInt32LE(offset); + offset += 4; + return i; + } + function readInt32() { + const i = buffer.readInt32LE(offset); + offset += 4; + return i; + } + function readUInt64() { + const i = bufferutils.readUInt64LE(buffer, offset); + offset += 8; + return i; + } + function readVarInt() { + const vi = varuint.decode(buffer, offset); + offset += varuint.decode.bytes; + return vi; + } + function readVarSlice() { + return readSlice(readVarInt()); + } + function readVector() { + const count = readVarInt(); + const vector = []; + for (let i = 0; i < count; i++) vector.push(readVarSlice()); + return vector; + } + const tx = new Transaction(); + tx.version = readInt32(); + const marker = buffer.readUInt8(offset); + const flag = buffer.readUInt8(offset + 1); + let hasWitnesses = false; + if ( + marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG + ) { + offset += 2; + hasWitnesses = true; + } + const vinLen = readVarInt(); + for (let i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readVarSlice(), + sequence: readUInt32(), + witness: EMPTY_WITNESS, + }); + } + const voutLen = readVarInt(); + for (let i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readVarSlice(), + }); + } + if (hasWitnesses) { + for (let i = 0; i < vinLen; ++i) { + tx.ins[i].witness = readVector(); + } + // was this pointless? + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); + } + tx.locktime = readUInt32(); + if (_NO_STRICT) return tx; + if (offset !== buffer.length) + throw new Error('Transaction has unexpected data'); + return tx; + } + static fromHex(hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + } + static isCoinbaseHash(buffer) { + typeforce(types.Hash256bit, buffer); + for (let i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false; + } + return true; + } + isCoinbase() { + return ( + this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + ); + } + addInput(hash, index, sequence, scriptSig) { + typeforce( + types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer), + ), + arguments, + ); + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE; + } + // Add the input and return the input's index + return ( + this.ins.push({ + hash, + index, + script: scriptSig || EMPTY_SCRIPT, + sequence: sequence, + witness: EMPTY_WITNESS, + }) - 1 + ); + } + addOutput(scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // Add the output and return the output's index + return ( + this.outs.push({ + script: scriptPubKey, + value, + }) - 1 + ); + } + hasWitnesses() { + return this.ins.some(x => { + return x.witness.length !== 0; + }); + } + weight() { + const base = this.__byteLength(false); + const total = this.__byteLength(true); + return base * 3 + total; + } + virtualSize() { + return Math.ceil(this.weight() / 4); + } + byteLength() { + return this.__byteLength(true); + } + clone() { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; + newTx.ins = this.ins.map(txIn => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness, + }; + }); + newTx.outs = this.outs.map(txOut => { + return { + script: txOut.script, + value: txOut.value, + }; + }); + return newTx; + } + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex, prevOutScript, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + arguments, + ); + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE; + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile( + bscript.decompile(prevOutScript).filter(x => { + return x !== script_1.OPS.OP_CODESEPARATOR; + }), + ); + const txTmp = this.clone(); + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = []; + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) return; + input.sequence = 0; + }); + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE; + // truncate outputs after + txTmp.outs.length = inIndex + 1; + // "blank" outputs before + for (let i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT; + } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) return; + input.sequence = 0; + }); + } + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach(input => { + input.script = EMPTY_SCRIPT; + }); + txTmp.ins[inIndex].script = ourScript; + } + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); + return bcrypto.hash256(buffer); + } + hashForWitnessV0(inIndex, prevOutScript, value, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + arguments, + ); + let tbuffer = Buffer.from([]); + let toffset = 0; + function writeSlice(slice) { + toffset += slice.copy(tbuffer, toffset); + } + function writeUInt32(i) { + toffset = tbuffer.writeUInt32LE(i, toffset); + } + function writeUInt64(i) { + toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset); + } + function writeVarInt(i) { + varuint.encode(i, tbuffer, toffset); + toffset += varuint.encode.bytes; + } + function writeVarSlice(slice) { + writeVarInt(slice.length); + writeSlice(slice); + } + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + toffset = 0; + this.ins.forEach(txIn => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.hash256(tbuffer); + } + if ( + !(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + toffset = 0; + this.ins.forEach(txIn => { + writeUInt32(txIn.sequence); + }); + hashSequence = bcrypto.hash256(tbuffer); + } + if ( + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0); + tbuffer = Buffer.allocUnsafe(txOutsSize); + toffset = 0; + this.outs.forEach(out => { + writeUInt64(out.value); + writeVarSlice(out.script); + }); + hashOutputs = bcrypto.hash256(tbuffer); + } else if ( + (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length + ) { + const output = this.outs[inIndex]; + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + toffset = 0; + writeUInt64(output.value); + writeVarSlice(output.script); + hashOutputs = bcrypto.hash256(tbuffer); + } + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + toffset = 0; + const input = this.ins[inIndex]; + writeUInt32(this.version); + writeSlice(hashPrevouts); + writeSlice(hashSequence); + writeSlice(input.hash); + writeUInt32(input.index); + writeVarSlice(prevOutScript); + writeUInt64(value); + writeUInt32(input.sequence); + writeSlice(hashOutputs); + writeUInt32(this.locktime); + writeUInt32(hashType); + return bcrypto.hash256(tbuffer); + } + getHash(forWitness) { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); + } + getId() { + // transaction hash's are displayed in reverse order + return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex'); + } + toBuffer(buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true); + } + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } + __byteLength(_ALLOW_WITNESS) { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0) + ); + } + __toBuffer(buffer, initialOffset, _ALLOW_WITNESS) { + if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(_ALLOW_WITNESS)); + let offset = initialOffset || 0; + function writeSlice(slice) { + offset += slice.copy(buffer, offset); + } + function writeUInt8(i) { + offset = buffer.writeUInt8(i, offset); + } + function writeUInt32(i) { + offset = buffer.writeUInt32LE(i, offset); + } + function writeInt32(i) { + offset = buffer.writeInt32LE(i, offset); + } + function writeUInt64(i) { + offset = bufferutils.writeUInt64LE(buffer, i, offset); + } + function writeVarInt(i) { + varuint.encode(i, buffer, offset); + offset += varuint.encode.bytes; + } + function writeVarSlice(slice) { + writeVarInt(slice.length); + writeSlice(slice); + } + function writeVector(vector) { + writeVarInt(vector.length); + vector.forEach(writeVarSlice); + } + writeInt32(this.version); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + if (hasWitnesses) { + writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); + } + writeVarInt(this.ins.length); + this.ins.forEach(txIn => { + writeSlice(txIn.hash); + writeUInt32(txIn.index); + writeVarSlice(txIn.script); + writeUInt32(txIn.sequence); + }); + writeVarInt(this.outs.length); + this.outs.forEach(txOut => { + if (isOutput(txOut)) { + writeUInt64(txOut.value); + } else { + writeSlice(txOut.valueBuffer); + } + writeVarSlice(txOut.script); + }); + if (hasWitnesses) { + this.ins.forEach(input => { + writeVector(input.witness); + }); + } + writeUInt32(this.locktime); + // avoid slicing unless necessary + if (initialOffset !== undefined) return buffer.slice(initialOffset, offset); + return buffer; + } } Transaction.DEFAULT_SEQUENCE = 0xffffffff; Transaction.SIGHASH_ALL = 0x01; diff --git a/src/transaction_builder.js b/src/transaction_builder.js index d3b2673..a4dcdf8 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -1,720 +1,739 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const baddress = require("./address"); -const bufferutils_1 = require("./bufferutils"); -const classify = require("./classify"); -const bcrypto = require("./crypto"); -const ECPair = require("./ecpair"); -const networks = require("./networks"); -const payments = require("./payments"); -const bscript = require("./script"); -const script_1 = require("./script"); -const transaction_1 = require("./transaction"); -const types = require("./types"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const baddress = require('./address'); +const bufferutils_1 = require('./bufferutils'); +const classify = require('./classify'); +const bcrypto = require('./crypto'); +const ECPair = require('./ecpair'); +const networks = require('./networks'); +const payments = require('./payments'); +const bscript = require('./script'); +const script_1 = require('./script'); +const transaction_1 = require('./transaction'); +const types = require('./types'); const typeforce = require('typeforce'); const SCRIPT_TYPES = classify.types; function txIsString(tx) { - return typeof tx === 'string' || tx instanceof String; + return typeof tx === 'string' || tx instanceof String; } function txIsTransaction(tx) { - return tx instanceof transaction_1.Transaction; + return tx instanceof transaction_1.Transaction; } class TransactionBuilder { - // WARNING: maximumFeeRate is __NOT__ to be relied on, - // it's just another potential safety mechanism (safety in-depth) - constructor(network = networks.bitcoin, maximumFeeRate = 2500) { - this.network = network; - this.maximumFeeRate = maximumFeeRate; - this.__PREV_TX_SET = {}; - this.__INPUTS = []; - this.__TX = new transaction_1.Transaction(); - this.__TX.version = 2; - } - static fromTransaction(transaction, network) { - const txb = new TransactionBuilder(network); - // Copy transaction fields - txb.setVersion(transaction.version); - txb.setLockTime(transaction.locktime); - // Copy outputs (done first to avoid signature invalidation) - transaction.outs.forEach(txOut => { - txb.addOutput(txOut.script, txOut.value); - }); - // Copy inputs - transaction.ins.forEach(txIn => { - txb.__addInputUnsafe(txIn.hash, txIn.index, { - sequence: txIn.sequence, - script: txIn.script, - witness: txIn.witness, - }); - }); - // fix some things not possible through the public API - txb.__INPUTS.forEach((input, i) => { - fixMultisigOrder(input, transaction, i); - }); - return txb; - } - setLockTime(locktime) { - typeforce(types.UInt32, locktime); - // if any signatures exist, throw - if (this.__INPUTS.some(input => { - if (!input.signatures) - return false; - return input.signatures.some(s => s !== undefined); - })) { - throw new Error('No, this would invalidate signatures'); - } - this.__TX.locktime = locktime; + // WARNING: maximumFeeRate is __NOT__ to be relied on, + // it's just another potential safety mechanism (safety in-depth) + constructor(network = networks.bitcoin, maximumFeeRate = 2500) { + this.network = network; + this.maximumFeeRate = maximumFeeRate; + this.__PREV_TX_SET = {}; + this.__INPUTS = []; + this.__TX = new transaction_1.Transaction(); + this.__TX.version = 2; + } + static fromTransaction(transaction, network) { + const txb = new TransactionBuilder(network); + // Copy transaction fields + txb.setVersion(transaction.version); + txb.setLockTime(transaction.locktime); + // Copy outputs (done first to avoid signature invalidation) + transaction.outs.forEach(txOut => { + txb.addOutput(txOut.script, txOut.value); + }); + // Copy inputs + transaction.ins.forEach(txIn => { + txb.__addInputUnsafe(txIn.hash, txIn.index, { + sequence: txIn.sequence, + script: txIn.script, + witness: txIn.witness, + }); + }); + // fix some things not possible through the public API + txb.__INPUTS.forEach((input, i) => { + fixMultisigOrder(input, transaction, i); + }); + return txb; + } + setLockTime(locktime) { + typeforce(types.UInt32, locktime); + // if any signatures exist, throw + if ( + this.__INPUTS.some(input => { + if (!input.signatures) return false; + return input.signatures.some(s => s !== undefined); + }) + ) { + throw new Error('No, this would invalidate signatures'); } - setVersion(version) { - typeforce(types.UInt32, version); - // XXX: this might eventually become more complex depending on what the versions represent - this.__TX.version = version; + this.__TX.locktime = locktime; + } + setVersion(version) { + typeforce(types.UInt32, version); + // XXX: this might eventually become more complex depending on what the versions represent + this.__TX.version = version; + } + addInput(txHash, vout, sequence, prevOutScript) { + if (!this.__canModifyInputs()) { + throw new Error('No, this would invalidate signatures'); } - addInput(txHash, vout, sequence, prevOutScript) { - if (!this.__canModifyInputs()) { - throw new Error('No, this would invalidate signatures'); - } - let value; - // is it a hex string? - if (txIsString(txHash)) { - // transaction hashs's are displayed in reverse order, un-reverse it - txHash = bufferutils_1.reverseBuffer(Buffer.from(txHash, 'hex')); - // is it a Transaction object? - } - else if (txIsTransaction(txHash)) { - const txOut = txHash.outs[vout]; - prevOutScript = txOut.script; - value = txOut.value; - txHash = txHash.getHash(false); - } - return this.__addInputUnsafe(txHash, vout, { - sequence, - prevOutScript, - value, - }); + let value; + // is it a hex string? + if (txIsString(txHash)) { + // transaction hashs's are displayed in reverse order, un-reverse it + txHash = bufferutils_1.reverseBuffer(Buffer.from(txHash, 'hex')); + // is it a Transaction object? + } else if (txIsTransaction(txHash)) { + const txOut = txHash.outs[vout]; + prevOutScript = txOut.script; + value = txOut.value; + txHash = txHash.getHash(false); } - addOutput(scriptPubKey, value) { - if (!this.__canModifyOutputs()) { - throw new Error('No, this would invalidate signatures'); - } - // Attempt to get a script if it's a base58 or bech32 address string - if (typeof scriptPubKey === 'string') { - scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); - } - return this.__TX.addOutput(scriptPubKey, value); - } - build() { - return this.__build(false); - } - buildIncomplete() { - return this.__build(true); - } - sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { - // TODO: remove keyPair.network matching in 4.0.0 - if (keyPair.network && keyPair.network !== this.network) - throw new TypeError('Inconsistent network'); - if (!this.__INPUTS[vin]) - throw new Error('No input at index: ' + vin); - hashType = hashType || transaction_1.Transaction.SIGHASH_ALL; - if (this.__needsOutputs(hashType)) - throw new Error('Transaction needs outputs'); - const input = this.__INPUTS[vin]; - // if redeemScript was previously provided, enforce consistency - if (input.redeemScript !== undefined && - redeemScript && - !input.redeemScript.equals(redeemScript)) { - throw new Error('Inconsistent redeemScript'); - } - const ourPubKey = keyPair.publicKey || keyPair.getPublicKey(); - if (!canSign(input)) { - if (witnessValue !== undefined) { - if (input.value !== undefined && input.value !== witnessValue) - throw new Error('Input did not match witnessValue'); - typeforce(types.Satoshi, witnessValue); - input.value = witnessValue; - } - if (!canSign(input)) { - const prepared = prepareInput(input, ourPubKey, redeemScript, witnessScript); - // updates inline - Object.assign(input, prepared); - } - if (!canSign(input)) - throw Error(input.prevOutType + ' not supported'); - } - // ready to sign - let signatureHash; - if (input.hasWitness) { - signatureHash = this.__TX.hashForWitnessV0(vin, input.signScript, input.value, hashType); - } - else { - signatureHash = this.__TX.hashForSignature(vin, input.signScript, hashType); - } - // enforce in order signing of public keys - const signed = input.pubkeys.some((pubKey, i) => { - if (!ourPubKey.equals(pubKey)) - return false; - if (input.signatures[i]) - throw new Error('Signature already exists'); - // TODO: add tests - if (ourPubKey.length !== 33 && input.hasWitness) { - throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH'); - } - const signature = keyPair.sign(signatureHash); - input.signatures[i] = bscript.signature.encode(signature, hashType); - return true; - }); - if (!signed) - throw new Error('Key pair cannot sign for this input'); + return this.__addInputUnsafe(txHash, vout, { + sequence, + prevOutScript, + value, + }); + } + addOutput(scriptPubKey, value) { + if (!this.__canModifyOutputs()) { + throw new Error('No, this would invalidate signatures'); } - __addInputUnsafe(txHash, vout, options) { - if (transaction_1.Transaction.isCoinbaseHash(txHash)) { - throw new Error('coinbase inputs not supported'); - } - const prevTxOut = txHash.toString('hex') + ':' + vout; - if (this.__PREV_TX_SET[prevTxOut] !== undefined) - throw new Error('Duplicate TxOut: ' + prevTxOut); - let input = {}; - // derive what we can from the scriptSig - if (options.script !== undefined) { - input = expandInput(options.script, options.witness || []); - } - // if an input value was given, retain it - if (options.value !== undefined) { - input.value = options.value; - } - // derive what we can from the previous transactions output script - if (!input.prevOutScript && options.prevOutScript) { - let prevOutType; - if (!input.pubkeys && !input.signatures) { - const expanded = expandOutput(options.prevOutScript); - if (expanded.pubkeys) { - input.pubkeys = expanded.pubkeys; - input.signatures = expanded.signatures; - } - prevOutType = expanded.type; - } - input.prevOutScript = options.prevOutScript; - input.prevOutType = prevOutType || classify.output(options.prevOutScript); - } - const vin = this.__TX.addInput(txHash, vout, options.sequence, options.scriptSig); - this.__INPUTS[vin] = input; - this.__PREV_TX_SET[prevTxOut] = true; - return vin; - } - __build(allowIncomplete) { - if (!allowIncomplete) { - if (!this.__TX.ins.length) - throw new Error('Transaction has no inputs'); - if (!this.__TX.outs.length) - throw new Error('Transaction has no outputs'); - } - const tx = this.__TX.clone(); - // create script signatures from inputs - this.__INPUTS.forEach((input, i) => { - if (!input.prevOutType && !allowIncomplete) - throw new Error('Transaction is not complete'); - const result = build(input.prevOutType, input, allowIncomplete); - if (!result) { - if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) - throw new Error('Unknown input type'); - if (!allowIncomplete) - throw new Error('Not enough information'); - return; - } - tx.setInputScript(i, result.input); - tx.setWitness(i, result.witness); - }); - if (!allowIncomplete) { - // do not rely on this, its merely a last resort - if (this.__overMaximumFees(tx.virtualSize())) { - throw new Error('Transaction has absurd fees'); - } - } - return tx; - } - __canModifyInputs() { - return this.__INPUTS.every(input => { - if (!input.signatures) - return true; - return input.signatures.every(signature => { - if (!signature) - return true; - const hashType = signatureHashType(signature); - // if SIGHASH_ANYONECANPAY is set, signatures would not - // be invalidated by more inputs - return (hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) !== 0; - }); - }); + // Attempt to get a script if it's a base58 or bech32 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); } - __needsOutputs(signingHashType) { - if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) { - return this.__TX.outs.length === 0; - } - // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs - // .build() will fail, but .buildIncomplete() is OK - return (this.__TX.outs.length === 0 && - this.__INPUTS.some(input => { - if (!input.signatures) - return false; - return input.signatures.some(signature => { - if (!signature) - return false; // no signature, no issue - const hashType = signatureHashType(signature); - if (hashType & transaction_1.Transaction.SIGHASH_NONE) - return false; // SIGHASH_NONE doesn't care about outputs - return true; // SIGHASH_* does care - }); - })); - } - __canModifyOutputs() { - const nInputs = this.__TX.ins.length; - const nOutputs = this.__TX.outs.length; - return this.__INPUTS.every(input => { - if (input.signatures === undefined) - return true; - return input.signatures.every(signature => { - if (!signature) - return true; - const hashType = signatureHashType(signature); - const hashTypeMod = hashType & 0x1f; - if (hashTypeMod === transaction_1.Transaction.SIGHASH_NONE) - return true; - if (hashTypeMod === transaction_1.Transaction.SIGHASH_SINGLE) { - // if SIGHASH_SINGLE is set, and nInputs > nOutputs - // some signatures would be invalidated by the addition - // of more outputs - return nInputs <= nOutputs; - } - return false; - }); - }); + return this.__TX.addOutput(scriptPubKey, value); + } + build() { + return this.__build(false); + } + buildIncomplete() { + return this.__build(true); + } + sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { + // TODO: remove keyPair.network matching in 4.0.0 + if (keyPair.network && keyPair.network !== this.network) + throw new TypeError('Inconsistent network'); + if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin); + hashType = hashType || transaction_1.Transaction.SIGHASH_ALL; + if (this.__needsOutputs(hashType)) + throw new Error('Transaction needs outputs'); + const input = this.__INPUTS[vin]; + // if redeemScript was previously provided, enforce consistency + if ( + input.redeemScript !== undefined && + redeemScript && + !input.redeemScript.equals(redeemScript) + ) { + throw new Error('Inconsistent redeemScript'); + } + const ourPubKey = keyPair.publicKey || keyPair.getPublicKey(); + if (!canSign(input)) { + if (witnessValue !== undefined) { + if (input.value !== undefined && input.value !== witnessValue) + throw new Error('Input did not match witnessValue'); + typeforce(types.Satoshi, witnessValue); + input.value = witnessValue; + } + if (!canSign(input)) { + const prepared = prepareInput( + input, + ourPubKey, + redeemScript, + witnessScript, + ); + // updates inline + Object.assign(input, prepared); + } + if (!canSign(input)) throw Error(input.prevOutType + ' not supported'); + } + // ready to sign + let signatureHash; + if (input.hasWitness) { + signatureHash = this.__TX.hashForWitnessV0( + vin, + input.signScript, + input.value, + hashType, + ); + } else { + signatureHash = this.__TX.hashForSignature( + vin, + input.signScript, + hashType, + ); + } + // enforce in order signing of public keys + const signed = input.pubkeys.some((pubKey, i) => { + if (!ourPubKey.equals(pubKey)) return false; + if (input.signatures[i]) throw new Error('Signature already exists'); + // TODO: add tests + if (ourPubKey.length !== 33 && input.hasWitness) { + throw new Error( + 'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH', + ); + } + const signature = keyPair.sign(signatureHash); + input.signatures[i] = bscript.signature.encode(signature, hashType); + return true; + }); + if (!signed) throw new Error('Key pair cannot sign for this input'); + } + __addInputUnsafe(txHash, vout, options) { + if (transaction_1.Transaction.isCoinbaseHash(txHash)) { + throw new Error('coinbase inputs not supported'); + } + const prevTxOut = txHash.toString('hex') + ':' + vout; + if (this.__PREV_TX_SET[prevTxOut] !== undefined) + throw new Error('Duplicate TxOut: ' + prevTxOut); + let input = {}; + // derive what we can from the scriptSig + if (options.script !== undefined) { + input = expandInput(options.script, options.witness || []); + } + // if an input value was given, retain it + if (options.value !== undefined) { + input.value = options.value; } - __overMaximumFees(bytes) { - // not all inputs will have .value defined - const incoming = this.__INPUTS.reduce((a, x) => a + (x.value >>> 0), 0); - // but all outputs do, and if we have any input value - // we can immediately determine if the outputs are too small - const outgoing = this.__TX.outs.reduce((a, x) => a + x.value, 0); - const fee = incoming - outgoing; - const feeRate = fee / bytes; - return feeRate > this.maximumFeeRate; + // derive what we can from the previous transactions output script + if (!input.prevOutScript && options.prevOutScript) { + let prevOutType; + if (!input.pubkeys && !input.signatures) { + const expanded = expandOutput(options.prevOutScript); + if (expanded.pubkeys) { + input.pubkeys = expanded.pubkeys; + input.signatures = expanded.signatures; + } + prevOutType = expanded.type; + } + input.prevOutScript = options.prevOutScript; + input.prevOutType = prevOutType || classify.output(options.prevOutScript); } + const vin = this.__TX.addInput( + txHash, + vout, + options.sequence, + options.scriptSig, + ); + this.__INPUTS[vin] = input; + this.__PREV_TX_SET[prevTxOut] = true; + return vin; + } + __build(allowIncomplete) { + if (!allowIncomplete) { + if (!this.__TX.ins.length) throw new Error('Transaction has no inputs'); + if (!this.__TX.outs.length) throw new Error('Transaction has no outputs'); + } + const tx = this.__TX.clone(); + // create script signatures from inputs + this.__INPUTS.forEach((input, i) => { + if (!input.prevOutType && !allowIncomplete) + throw new Error('Transaction is not complete'); + const result = build(input.prevOutType, input, allowIncomplete); + if (!result) { + if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) + throw new Error('Unknown input type'); + if (!allowIncomplete) throw new Error('Not enough information'); + return; + } + tx.setInputScript(i, result.input); + tx.setWitness(i, result.witness); + }); + if (!allowIncomplete) { + // do not rely on this, its merely a last resort + if (this.__overMaximumFees(tx.virtualSize())) { + throw new Error('Transaction has absurd fees'); + } + } + return tx; + } + __canModifyInputs() { + return this.__INPUTS.every(input => { + if (!input.signatures) return true; + return input.signatures.every(signature => { + if (!signature) return true; + const hashType = signatureHashType(signature); + // if SIGHASH_ANYONECANPAY is set, signatures would not + // be invalidated by more inputs + return ( + (hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) !== 0 + ); + }); + }); + } + __needsOutputs(signingHashType) { + if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) { + return this.__TX.outs.length === 0; + } + // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs + // .build() will fail, but .buildIncomplete() is OK + return ( + this.__TX.outs.length === 0 && + this.__INPUTS.some(input => { + if (!input.signatures) return false; + return input.signatures.some(signature => { + if (!signature) return false; // no signature, no issue + const hashType = signatureHashType(signature); + if (hashType & transaction_1.Transaction.SIGHASH_NONE) return false; // SIGHASH_NONE doesn't care about outputs + return true; // SIGHASH_* does care + }); + }) + ); + } + __canModifyOutputs() { + const nInputs = this.__TX.ins.length; + const nOutputs = this.__TX.outs.length; + return this.__INPUTS.every(input => { + if (input.signatures === undefined) return true; + return input.signatures.every(signature => { + if (!signature) return true; + const hashType = signatureHashType(signature); + const hashTypeMod = hashType & 0x1f; + if (hashTypeMod === transaction_1.Transaction.SIGHASH_NONE) return true; + if (hashTypeMod === transaction_1.Transaction.SIGHASH_SINGLE) { + // if SIGHASH_SINGLE is set, and nInputs > nOutputs + // some signatures would be invalidated by the addition + // of more outputs + return nInputs <= nOutputs; + } + return false; + }); + }); + } + __overMaximumFees(bytes) { + // not all inputs will have .value defined + const incoming = this.__INPUTS.reduce((a, x) => a + (x.value >>> 0), 0); + // but all outputs do, and if we have any input value + // we can immediately determine if the outputs are too small + const outgoing = this.__TX.outs.reduce((a, x) => a + x.value, 0); + const fee = incoming - outgoing; + const feeRate = fee / bytes; + return feeRate > this.maximumFeeRate; + } } exports.TransactionBuilder = TransactionBuilder; function expandInput(scriptSig, witnessStack, type, scriptPubKey) { - if (scriptSig.length === 0 && witnessStack.length === 0) - return {}; - if (!type) { - let ssType = classify.input(scriptSig, true); - let wsType = classify.witness(witnessStack, true); - if (ssType === SCRIPT_TYPES.NONSTANDARD) - ssType = undefined; - if (wsType === SCRIPT_TYPES.NONSTANDARD) - wsType = undefined; - type = ssType || wsType; - } - switch (type) { - case SCRIPT_TYPES.P2WPKH: { - const { output, pubkey, signature } = payments.p2wpkh({ - witness: witnessStack, - }); - return { - prevOutScript: output, - prevOutType: SCRIPT_TYPES.P2WPKH, - pubkeys: [pubkey], - signatures: [signature], - }; - } - case SCRIPT_TYPES.P2PKH: { - const { output, pubkey, signature } = payments.p2pkh({ - input: scriptSig, - }); - return { - prevOutScript: output, - prevOutType: SCRIPT_TYPES.P2PKH, - pubkeys: [pubkey], - signatures: [signature], - }; - } - case SCRIPT_TYPES.P2PK: { - const { signature } = payments.p2pk({ input: scriptSig }); - return { - prevOutType: SCRIPT_TYPES.P2PK, - pubkeys: [undefined], - signatures: [signature], - }; - } - case SCRIPT_TYPES.P2MS: { - const { m, pubkeys, signatures } = payments.p2ms({ - input: scriptSig, - output: scriptPubKey, - }, { allowIncomplete: true }); - return { - prevOutType: SCRIPT_TYPES.P2MS, - pubkeys, - signatures, - maxSignatures: m, - }; - } + if (scriptSig.length === 0 && witnessStack.length === 0) return {}; + if (!type) { + let ssType = classify.input(scriptSig, true); + let wsType = classify.witness(witnessStack, true); + if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined; + if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined; + type = ssType || wsType; + } + switch (type) { + case SCRIPT_TYPES.P2WPKH: { + const { output, pubkey, signature } = payments.p2wpkh({ + witness: witnessStack, + }); + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2WPKH, + pubkeys: [pubkey], + signatures: [signature], + }; } - if (type === SCRIPT_TYPES.P2SH) { - const { output, redeem } = payments.p2sh({ - input: scriptSig, - witness: witnessStack, - }); - const outputType = classify.output(redeem.output); - const expanded = expandInput(redeem.input, redeem.witness, outputType, redeem.output); - if (!expanded.prevOutType) - return {}; - return { - prevOutScript: output, - prevOutType: SCRIPT_TYPES.P2SH, - redeemScript: redeem.output, - redeemScriptType: expanded.prevOutType, - witnessScript: expanded.witnessScript, - witnessScriptType: expanded.witnessScriptType, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - }; - } - if (type === SCRIPT_TYPES.P2WSH) { - const { output, redeem } = payments.p2wsh({ - input: scriptSig, - witness: witnessStack, - }); - const outputType = classify.output(redeem.output); - let expanded; - if (outputType === SCRIPT_TYPES.P2WPKH) { - expanded = expandInput(redeem.input, redeem.witness, outputType); - } - else { - expanded = expandInput(bscript.compile(redeem.witness), [], outputType, redeem.output); - } - if (!expanded.prevOutType) - return {}; - return { - prevOutScript: output, - prevOutType: SCRIPT_TYPES.P2WSH, - witnessScript: redeem.output, - witnessScriptType: expanded.prevOutType, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - }; + case SCRIPT_TYPES.P2PKH: { + const { output, pubkey, signature } = payments.p2pkh({ + input: scriptSig, + }); + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2PKH, + pubkeys: [pubkey], + signatures: [signature], + }; + } + case SCRIPT_TYPES.P2PK: { + const { signature } = payments.p2pk({ input: scriptSig }); + return { + prevOutType: SCRIPT_TYPES.P2PK, + pubkeys: [undefined], + signatures: [signature], + }; + } + case SCRIPT_TYPES.P2MS: { + const { m, pubkeys, signatures } = payments.p2ms( + { + input: scriptSig, + output: scriptPubKey, + }, + { allowIncomplete: true }, + ); + return { + prevOutType: SCRIPT_TYPES.P2MS, + pubkeys, + signatures, + maxSignatures: m, + }; + } + } + if (type === SCRIPT_TYPES.P2SH) { + const { output, redeem } = payments.p2sh({ + input: scriptSig, + witness: witnessStack, + }); + const outputType = classify.output(redeem.output); + const expanded = expandInput( + redeem.input, + redeem.witness, + outputType, + redeem.output, + ); + if (!expanded.prevOutType) return {}; + return { + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2SH, + redeemScript: redeem.output, + redeemScriptType: expanded.prevOutType, + witnessScript: expanded.witnessScript, + witnessScriptType: expanded.witnessScriptType, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + }; + } + if (type === SCRIPT_TYPES.P2WSH) { + const { output, redeem } = payments.p2wsh({ + input: scriptSig, + witness: witnessStack, + }); + const outputType = classify.output(redeem.output); + let expanded; + if (outputType === SCRIPT_TYPES.P2WPKH) { + expanded = expandInput(redeem.input, redeem.witness, outputType); + } else { + expanded = expandInput( + bscript.compile(redeem.witness), + [], + outputType, + redeem.output, + ); } + if (!expanded.prevOutType) return {}; return { - prevOutType: SCRIPT_TYPES.NONSTANDARD, - prevOutScript: scriptSig, + prevOutScript: output, + prevOutType: SCRIPT_TYPES.P2WSH, + witnessScript: redeem.output, + witnessScriptType: expanded.prevOutType, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, }; + } + return { + prevOutType: SCRIPT_TYPES.NONSTANDARD, + prevOutScript: scriptSig, + }; } // could be done in expandInput, but requires the original Transaction for hashForSignature function fixMultisigOrder(input, transaction, vin) { - if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) - return; - if (input.pubkeys.length === input.signatures.length) - return; - const unmatched = input.signatures.concat(); - input.signatures = input.pubkeys.map(pubKey => { - const keyPair = ECPair.fromPublicKey(pubKey); - let match; - // check for a signature - unmatched.some((signature, i) => { - // skip if undefined || OP_0 - if (!signature) - return false; - // TODO: avoid O(n) hashForSignature - const parsed = bscript.signature.decode(signature); - const hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType); - // skip if signature does not match pubKey - if (!keyPair.verify(hash, parsed.signature)) - return false; - // remove matched signature from unmatched - unmatched[i] = undefined; - match = signature; - return true; - }); - return match; + if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) + return; + if (input.pubkeys.length === input.signatures.length) return; + const unmatched = input.signatures.concat(); + input.signatures = input.pubkeys.map(pubKey => { + const keyPair = ECPair.fromPublicKey(pubKey); + let match; + // check for a signature + unmatched.some((signature, i) => { + // skip if undefined || OP_0 + if (!signature) return false; + // TODO: avoid O(n) hashForSignature + const parsed = bscript.signature.decode(signature); + const hash = transaction.hashForSignature( + vin, + input.redeemScript, + parsed.hashType, + ); + // skip if signature does not match pubKey + if (!keyPair.verify(hash, parsed.signature)) return false; + // remove matched signature from unmatched + unmatched[i] = undefined; + match = signature; + return true; }); + return match; + }); } function expandOutput(script, ourPubKey) { - typeforce(types.Buffer, script); - const type = classify.output(script); - switch (type) { - case SCRIPT_TYPES.P2PKH: { - if (!ourPubKey) - return { type }; - // does our hash160(pubKey) match the output scripts? - const pkh1 = payments.p2pkh({ output: script }).hash; - const pkh2 = bcrypto.hash160(ourPubKey); - if (!pkh1.equals(pkh2)) - return { type }; - return { - type, - pubkeys: [ourPubKey], - signatures: [undefined], - }; - } - case SCRIPT_TYPES.P2WPKH: { - if (!ourPubKey) - return { type }; - // does our hash160(pubKey) match the output scripts? - const wpkh1 = payments.p2wpkh({ output: script }).hash; - const wpkh2 = bcrypto.hash160(ourPubKey); - if (!wpkh1.equals(wpkh2)) - return { type }; - return { - type, - pubkeys: [ourPubKey], - signatures: [undefined], - }; - } - case SCRIPT_TYPES.P2PK: { - const p2pk = payments.p2pk({ output: script }); - return { - type, - pubkeys: [p2pk.pubkey], - signatures: [undefined], - }; - } - case SCRIPT_TYPES.P2MS: { - const p2ms = payments.p2ms({ output: script }); - return { - type, - pubkeys: p2ms.pubkeys, - signatures: p2ms.pubkeys.map(() => undefined), - maxSignatures: p2ms.m, - }; - } + typeforce(types.Buffer, script); + const type = classify.output(script); + switch (type) { + case SCRIPT_TYPES.P2PKH: { + if (!ourPubKey) return { type }; + // does our hash160(pubKey) match the output scripts? + const pkh1 = payments.p2pkh({ output: script }).hash; + const pkh2 = bcrypto.hash160(ourPubKey); + if (!pkh1.equals(pkh2)) return { type }; + return { + type, + pubkeys: [ourPubKey], + signatures: [undefined], + }; + } + case SCRIPT_TYPES.P2WPKH: { + if (!ourPubKey) return { type }; + // does our hash160(pubKey) match the output scripts? + const wpkh1 = payments.p2wpkh({ output: script }).hash; + const wpkh2 = bcrypto.hash160(ourPubKey); + if (!wpkh1.equals(wpkh2)) return { type }; + return { + type, + pubkeys: [ourPubKey], + signatures: [undefined], + }; + } + case SCRIPT_TYPES.P2PK: { + const p2pk = payments.p2pk({ output: script }); + return { + type, + pubkeys: [p2pk.pubkey], + signatures: [undefined], + }; + } + case SCRIPT_TYPES.P2MS: { + const p2ms = payments.p2ms({ output: script }); + return { + type, + pubkeys: p2ms.pubkeys, + signatures: p2ms.pubkeys.map(() => undefined), + maxSignatures: p2ms.m, + }; } - return { type }; + } + return { type }; } function prepareInput(input, ourPubKey, redeemScript, witnessScript) { - if (redeemScript && witnessScript) { - const p2wsh = payments.p2wsh({ - redeem: { output: witnessScript }, - }); - const p2wshAlt = payments.p2wsh({ output: redeemScript }); - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); - const p2shAlt = payments.p2sh({ redeem: p2wsh }); - // enforces P2SH(P2WSH(...)) - if (!p2wsh.hash.equals(p2wshAlt.hash)) - throw new Error('Witness script inconsistent with prevOutScript'); - if (!p2sh.hash.equals(p2shAlt.hash)) - throw new Error('Redeem script inconsistent with prevOutScript'); - const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); - if (!expanded.pubkeys) - throw new Error(expanded.type + - ' not supported as witnessScript (' + - bscript.toASM(witnessScript) + - ')'); - if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures; - } - const signScript = witnessScript; - if (expanded.type === SCRIPT_TYPES.P2WPKH) - throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); - return { - redeemScript, - redeemScriptType: SCRIPT_TYPES.P2WSH, - witnessScript, - witnessScriptType: expanded.type, - prevOutType: SCRIPT_TYPES.P2SH, - prevOutScript: p2sh.output, - hasWitness: true, - signScript, - signType: expanded.type, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures, - }; - } - if (redeemScript) { - const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); - if (input.prevOutScript) { - let p2shAlt; - try { - p2shAlt = payments.p2sh({ output: input.prevOutScript }); - } - catch (e) { - throw new Error('PrevOutScript must be P2SH'); - } - if (!p2sh.hash.equals(p2shAlt.hash)) - throw new Error('Redeem script inconsistent with prevOutScript'); - } - const expanded = expandOutput(p2sh.redeem.output, ourPubKey); - if (!expanded.pubkeys) - throw new Error(expanded.type + - ' not supported as redeemScript (' + - bscript.toASM(redeemScript) + - ')'); - if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures; - } - let signScript = redeemScript; - if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; - } - return { - redeemScript, - redeemScriptType: expanded.type, - prevOutType: SCRIPT_TYPES.P2SH, - prevOutScript: p2sh.output, - hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, - signScript, - signType: expanded.type, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures, - }; - } - if (witnessScript) { - const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); - if (input.prevOutScript) { - const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }); - if (!p2wsh.hash.equals(p2wshAlt.hash)) - throw new Error('Witness script inconsistent with prevOutScript'); - } - const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); - if (!expanded.pubkeys) - throw new Error(expanded.type + - ' not supported as witnessScript (' + - bscript.toASM(witnessScript) + - ')'); - if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures; - } - const signScript = witnessScript; - if (expanded.type === SCRIPT_TYPES.P2WPKH) - throw new Error('P2WSH(P2WPKH) is a consensus failure'); - return { - witnessScript, - witnessScriptType: expanded.type, - prevOutType: SCRIPT_TYPES.P2WSH, - prevOutScript: p2wsh.output, - hasWitness: true, - signScript, - signType: expanded.type, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures, - }; - } - if (input.prevOutType && input.prevOutScript) { - // embedded scripts are not possible without extra information - if (input.prevOutType === SCRIPT_TYPES.P2SH) - throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript'); - if (input.prevOutType === SCRIPT_TYPES.P2WSH) - throw new Error('PrevOutScript is ' + input.prevOutType + ', requires witnessScript'); - if (!input.prevOutScript) - throw new Error('PrevOutScript is missing'); - const expanded = expandOutput(input.prevOutScript, ourPubKey); - if (!expanded.pubkeys) - throw new Error(expanded.type + - ' not supported (' + - bscript.toASM(input.prevOutScript) + - ')'); - if (input.signatures && input.signatures.some(x => x !== undefined)) { - expanded.signatures = input.signatures; - } - let signScript = input.prevOutScript; - if (expanded.type === SCRIPT_TYPES.P2WPKH) { - signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }) - .output; - } - return { - prevOutType: expanded.type, - prevOutScript: input.prevOutScript, - hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, - signScript, - signType: expanded.type, - pubkeys: expanded.pubkeys, - signatures: expanded.signatures, - maxSignatures: expanded.maxSignatures, - }; - } - const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; + if (redeemScript && witnessScript) { + const p2wsh = payments.p2wsh({ + redeem: { output: witnessScript }, + }); + const p2wshAlt = payments.p2wsh({ output: redeemScript }); + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + const p2shAlt = payments.p2sh({ redeem: p2wsh }); + // enforces P2SH(P2WSH(...)) + if (!p2wsh.hash.equals(p2wshAlt.hash)) + throw new Error('Witness script inconsistent with prevOutScript'); + if (!p2sh.hash.equals(p2shAlt.hash)) + throw new Error('Redeem script inconsistent with prevOutScript'); + const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')', + ); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + const signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); return { - prevOutType: SCRIPT_TYPES.P2PKH, - prevOutScript, - hasWitness: false, - signScript: prevOutScript, - signType: SCRIPT_TYPES.P2PKH, - pubkeys: [ourPubKey], - signatures: [undefined], + redeemScript, + redeemScriptType: SCRIPT_TYPES.P2WSH, + witnessScript, + witnessScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2SH, + prevOutScript: p2sh.output, + hasWitness: true, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures, + }; + } + if (redeemScript) { + const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); + if (input.prevOutScript) { + let p2shAlt; + try { + p2shAlt = payments.p2sh({ output: input.prevOutScript }); + } catch (e) { + throw new Error('PrevOutScript must be P2SH'); + } + if (!p2sh.hash.equals(p2shAlt.hash)) + throw new Error('Redeem script inconsistent with prevOutScript'); + } + const expanded = expandOutput(p2sh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as redeemScript (' + + bscript.toASM(redeemScript) + + ')', + ); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = redeemScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) { + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; + } + return { + redeemScript, + redeemScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2SH, + prevOutScript: p2sh.output, + hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures, + }; + } + if (witnessScript) { + const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); + if (input.prevOutScript) { + const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }); + if (!p2wsh.hash.equals(p2wshAlt.hash)) + throw new Error('Witness script inconsistent with prevOutScript'); + } + const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported as witnessScript (' + + bscript.toASM(witnessScript) + + ')', + ); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + const signScript = witnessScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) + throw new Error('P2WSH(P2WPKH) is a consensus failure'); + return { + witnessScript, + witnessScriptType: expanded.type, + prevOutType: SCRIPT_TYPES.P2WSH, + prevOutScript: p2wsh.output, + hasWitness: true, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures, + }; + } + if (input.prevOutType && input.prevOutScript) { + // embedded scripts are not possible without extra information + if (input.prevOutType === SCRIPT_TYPES.P2SH) + throw new Error( + 'PrevOutScript is ' + input.prevOutType + ', requires redeemScript', + ); + if (input.prevOutType === SCRIPT_TYPES.P2WSH) + throw new Error( + 'PrevOutScript is ' + input.prevOutType + ', requires witnessScript', + ); + if (!input.prevOutScript) throw new Error('PrevOutScript is missing'); + const expanded = expandOutput(input.prevOutScript, ourPubKey); + if (!expanded.pubkeys) + throw new Error( + expanded.type + + ' not supported (' + + bscript.toASM(input.prevOutScript) + + ')', + ); + if (input.signatures && input.signatures.some(x => x !== undefined)) { + expanded.signatures = input.signatures; + } + let signScript = input.prevOutScript; + if (expanded.type === SCRIPT_TYPES.P2WPKH) { + signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; + } + return { + prevOutType: expanded.type, + prevOutScript: input.prevOutScript, + hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, + signScript, + signType: expanded.type, + pubkeys: expanded.pubkeys, + signatures: expanded.signatures, + maxSignatures: expanded.maxSignatures, }; + } + const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; + return { + prevOutType: SCRIPT_TYPES.P2PKH, + prevOutScript, + hasWitness: false, + signScript: prevOutScript, + signType: SCRIPT_TYPES.P2PKH, + pubkeys: [ourPubKey], + signatures: [undefined], + }; } function build(type, input, allowIncomplete) { - const pubkeys = (input.pubkeys || []); - let signatures = (input.signatures || []); - switch (type) { - case SCRIPT_TYPES.P2PKH: { - if (pubkeys.length === 0) - break; - if (signatures.length === 0) - break; - return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }); - } - case SCRIPT_TYPES.P2WPKH: { - if (pubkeys.length === 0) - break; - if (signatures.length === 0) - break; - return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }); - } - case SCRIPT_TYPES.P2PK: { - if (pubkeys.length === 0) - break; - if (signatures.length === 0) - break; - return payments.p2pk({ signature: signatures[0] }); - } - case SCRIPT_TYPES.P2MS: { - const m = input.maxSignatures; - if (allowIncomplete) { - signatures = signatures.map(x => x || script_1.OPS.OP_0); - } - else { - signatures = signatures.filter(x => x); - } - // if the transaction is not not complete (complete), or if signatures.length === m, validate - // otherwise, the number of OP_0's may be >= m, so don't validate (boo) - const validate = !allowIncomplete || m === signatures.length; - return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate }); - } - case SCRIPT_TYPES.P2SH: { - const redeem = build(input.redeemScriptType, input, allowIncomplete); - if (!redeem) - return; - return payments.p2sh({ - redeem: { - output: redeem.output || input.redeemScript, - input: redeem.input, - witness: redeem.witness, - }, - }); - } - case SCRIPT_TYPES.P2WSH: { - const redeem = build(input.witnessScriptType, input, allowIncomplete); - if (!redeem) - return; - return payments.p2wsh({ - redeem: { - output: input.witnessScript, - input: redeem.input, - witness: redeem.witness, - }, - }); - } + const pubkeys = input.pubkeys || []; + let signatures = input.signatures || []; + switch (type) { + case SCRIPT_TYPES.P2PKH: { + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; + return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }); + } + case SCRIPT_TYPES.P2WPKH: { + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; + return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }); + } + case SCRIPT_TYPES.P2PK: { + if (pubkeys.length === 0) break; + if (signatures.length === 0) break; + return payments.p2pk({ signature: signatures[0] }); + } + case SCRIPT_TYPES.P2MS: { + const m = input.maxSignatures; + if (allowIncomplete) { + signatures = signatures.map(x => x || script_1.OPS.OP_0); + } else { + signatures = signatures.filter(x => x); + } + // if the transaction is not not complete (complete), or if signatures.length === m, validate + // otherwise, the number of OP_0's may be >= m, so don't validate (boo) + const validate = !allowIncomplete || m === signatures.length; + return payments.p2ms( + { m, pubkeys, signatures }, + { allowIncomplete, validate }, + ); + } + case SCRIPT_TYPES.P2SH: { + const redeem = build(input.redeemScriptType, input, allowIncomplete); + if (!redeem) return; + return payments.p2sh({ + redeem: { + output: redeem.output || input.redeemScript, + input: redeem.input, + witness: redeem.witness, + }, + }); + } + case SCRIPT_TYPES.P2WSH: { + const redeem = build(input.witnessScriptType, input, allowIncomplete); + if (!redeem) return; + return payments.p2wsh({ + redeem: { + output: input.witnessScript, + input: redeem.input, + witness: redeem.witness, + }, + }); } + } } function canSign(input) { - return (input.signScript !== undefined && - input.signType !== undefined && - input.pubkeys !== undefined && - input.signatures !== undefined && - input.signatures.length === input.pubkeys.length && - input.pubkeys.length > 0 && - (input.hasWitness === false || input.value !== undefined)); + return ( + input.signScript !== undefined && + input.signType !== undefined && + input.pubkeys !== undefined && + input.signatures !== undefined && + input.signatures.length === input.pubkeys.length && + input.pubkeys.length > 0 && + (input.hasWitness === false || input.value !== undefined) + ); } function signatureHashType(buffer) { - return buffer.readUInt8(buffer.length - 1); + return buffer.readUInt8(buffer.length - 1); } diff --git a/src/types.js b/src/types.js index dbe7ca5..be95266 100644 --- a/src/types.js +++ b/src/types.js @@ -1,35 +1,35 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); const typeforce = require('typeforce'); const UINT31_MAX = Math.pow(2, 31) - 1; function UInt31(value) { - return typeforce.UInt32(value) && value <= UINT31_MAX; + return typeforce.UInt32(value) && value <= UINT31_MAX; } exports.UInt31 = UInt31; function BIP32Path(value) { - return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); + return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); } exports.BIP32Path = BIP32Path; BIP32Path.toJSON = () => { - return 'BIP32 derivation path'; + return 'BIP32 derivation path'; }; const SATOSHI_MAX = 21 * 1e14; function Satoshi(value) { - return typeforce.UInt53(value) && value <= SATOSHI_MAX; + return typeforce.UInt53(value) && value <= SATOSHI_MAX; } exports.Satoshi = Satoshi; // external dependent types exports.ECPoint = typeforce.quacksLike('Point'); // exposed, external API exports.Network = typeforce.compile({ - messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), - bip32: { - public: typeforce.UInt32, - private: typeforce.UInt32, - }, - pubKeyHash: typeforce.UInt8, - scriptHash: typeforce.UInt8, - wif: typeforce.UInt8, + messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), + bip32: { + public: typeforce.UInt32, + private: typeforce.UInt32, + }, + pubKeyHash: typeforce.UInt8, + scriptHash: typeforce.UInt8, + wif: typeforce.UInt8, }); exports.Buffer256bit = typeforce.BufferN(32); exports.Hash160bit = typeforce.BufferN(20); From 67aa87e28df35c414b0650d8a0b79998e58a64a7 Mon Sep 17 00:00:00 2001 From: jolestar Date: Tue, 23 Apr 2019 13:55:51 +0800 Subject: [PATCH 175/183] fix bug:ECPair.verify should return boolean fECPair.verify should return boolean, and js implements indeed return boolean. --- types/ecpair.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index a5ae716..2cc2c27 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -12,7 +12,7 @@ export interface ECPairInterface { publicKey?: Buffer; toWIF(): string; sign(hash: Buffer): Buffer; - verify(hash: Buffer, signature: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): boolean; getPublicKey?(): Buffer; } declare class ECPair implements ECPairInterface { @@ -25,7 +25,7 @@ declare class ECPair implements ECPairInterface { readonly publicKey: Buffer | undefined; toWIF(): string; sign(hash: Buffer): Buffer; - verify(hash: Buffer, signature: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): boolean; } declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair; declare function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair; From 00ca4c2ec7a112ca5f036409d98cfedaa24ee0cf Mon Sep 17 00:00:00 2001 From: Jonathan Underwood Date: Tue, 23 Apr 2019 15:10:01 +0900 Subject: [PATCH 176/183] Fix ts files from Buffer to boolean --- ts_src/ecpair.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 3941afa..5c31e7f 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -26,7 +26,7 @@ export interface ECPairInterface { publicKey?: Buffer; toWIF(): string; sign(hash: Buffer): Buffer; - verify(hash: Buffer, signature: Buffer): Buffer; + verify(hash: Buffer, signature: Buffer): boolean; getPublicKey?(): Buffer; } @@ -66,7 +66,7 @@ class ECPair implements ECPairInterface { return ecc.sign(hash, this.__D); } - verify(hash: Buffer, signature: Buffer): Buffer { + verify(hash: Buffer, signature: Buffer): boolean { return ecc.verify(hash, this.publicKey, signature); } } From 56c876e979a24fbdaa6c90cad3bafe302f9f9f24 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 25 Apr 2019 19:07:46 +0900 Subject: [PATCH 177/183] 5.0.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f56a619..b69c70b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.2", + "version": "5.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 591e98a..2387bed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitcoinjs-lib", - "version": "5.0.2", + "version": "5.0.3", "description": "Client-side Bitcoin JavaScript library", "main": "./src/index.js", "types": "./types/index.d.ts", From 68339fda4de72cc40fa8db6602595b4e1a7e8577 Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Mon, 13 May 2019 16:35:02 +0700 Subject: [PATCH 178/183] Remove source files before rebuilding --- package-lock.json | 25 +++++++++++++++++++++++++ package.json | 4 +++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index b69c70b..2b0f37e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1845,6 +1845,31 @@ "path-parse": "^1.0.5" } }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", diff --git a/package.json b/package.json index 2387bed..b667ba0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "bitcoinjs" ], "scripts": { - "build": "tsc -p ./tsconfig.json", + "clean": "rimraf src", + "build": "npm run clean && tsc -p ./tsconfig.json", "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", @@ -71,6 +72,7 @@ "nyc": "^13.3.0", "prettier": "1.16.4", "proxyquire": "^2.0.1", + "rimraf": "^2.6.3", "tslint": "5.13.1", "typescript": "3.2.2" }, From 5ef135f9e429925c51461d11c3000ce6d1275793 Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Mon, 13 May 2019 16:39:08 +0700 Subject: [PATCH 179/183] Ensure build scripts are in alphabetical order --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b667ba0..a26330d 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "bitcoinjs" ], "scripts": { - "clean": "rimraf src", "build": "npm run clean && tsc -p ./tsconfig.json", + "clean": "rimraf src", "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", From 1c75c0203809ced5ace402ca211c2c12bb9db4bc Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 16 May 2019 16:29:23 +0900 Subject: [PATCH 180/183] Fix publicKey type on ECPairInterface --- ts_src/ecpair.ts | 11 ++++++----- types/ecpair.d.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 5c31e7f..18c0c9e 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -22,8 +22,8 @@ interface ECPairOptions { export interface ECPairInterface { compressed: boolean; network: Network; + publicKey: Buffer; privateKey?: Buffer; - publicKey?: Buffer; toWIF(): string; sign(hash: Buffer): Buffer; verify(hash: Buffer, signature: Buffer): boolean; @@ -51,8 +51,9 @@ class ECPair implements ECPairInterface { return this.__D; } - get publicKey(): Buffer | undefined { - if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); + get publicKey(): Buffer { + if (!this.__Q) + this.__Q = ecc.pointFromScalar(this.__D, this.compressed) as Buffer; return this.__Q; } @@ -77,13 +78,13 @@ function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair { throw new TypeError('Private key not in range [1, n)'); typeforce(isOptions, options); - return new ECPair(buffer, undefined, options as ECPairOptions); + return new ECPair(buffer, undefined, options); } function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair { typeforce(ecc.isPoint, buffer); typeforce(isOptions, options); - return new ECPair(undefined, buffer, options as ECPairOptions); + return new ECPair(undefined, buffer, options); } function fromWIF(wifString: string, network?: Network | Network[]): ECPair { diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts index 2cc2c27..896025b 100644 --- a/types/ecpair.d.ts +++ b/types/ecpair.d.ts @@ -8,8 +8,8 @@ interface ECPairOptions { export interface ECPairInterface { compressed: boolean; network: Network; + publicKey: Buffer; privateKey?: Buffer; - publicKey?: Buffer; toWIF(): string; sign(hash: Buffer): Buffer; verify(hash: Buffer, signature: Buffer): boolean; @@ -22,7 +22,7 @@ declare class ECPair implements ECPairInterface { network: Network; constructor(__D?: Buffer | undefined, __Q?: Buffer | undefined, options?: ECPairOptions); readonly privateKey: Buffer | undefined; - readonly publicKey: Buffer | undefined; + readonly publicKey: Buffer; toWIF(): string; sign(hash: Buffer): Buffer; verify(hash: Buffer, signature: Buffer): boolean; From 5a381ba582856a348d8182508a15a2584894cefa Mon Sep 17 00:00:00 2001 From: Agent of User Date: Fri, 17 May 2019 08:02:53 -0400 Subject: [PATCH 181/183] Bump tiny-secp256k1 to version supporting node 12 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b0f37e..f5bb788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -731,9 +731,9 @@ "dev": true }, "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "nyc": { "version": "13.3.0", @@ -1936,15 +1936,15 @@ } }, "tiny-secp256k1": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.0.1.tgz", - "integrity": "sha512-Wz2kMPWtCI5XBftFeF3bUL8uz2+VlasniKwOkRPjvL7h1QVd9rbhrve/HWUu747kJKzVf1XHonzcdM4Ut8fvww==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.1.tgz", + "integrity": "sha512-jA9WalQuhKun1svJrAVi9Vu8aUWKMfR7nMV903kHjrHTTY/IFa0petSq+Jk/Mv447dGD9LC8fGsmGRubBbcNng==", "requires": { "bindings": "^1.3.0", "bn.js": "^4.11.8", "create-hmac": "^1.1.7", "elliptic": "^6.4.0", - "nan": "^2.10.0" + "nan": "^2.13.2" } }, "to-fast-properties": { diff --git a/package.json b/package.json index a26330d..1f6f83a 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "merkle-lib": "^2.0.10", "pushdata-bitcoin": "^1.0.1", "randombytes": "^2.0.1", - "tiny-secp256k1": "^1.0.0", + "tiny-secp256k1": "^1.1.1", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" From 4d9c1b81bdbe7fbf04767117ac315cc1533c7f66 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 21 May 2019 15:13:38 +0900 Subject: [PATCH 182/183] Update packages npm audit --- package-lock.json | 2364 +++++++++++++++++++++------------------------ package.json | 6 +- 2 files changed, 1084 insertions(+), 1286 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a1d1d3..6e84754 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,12 @@ } }, "@babel/generator": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", - "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", "dev": true, "requires": { - "@babel/types": "^7.3.4", + "@babel/types": "^7.4.4", "jsesc": "^2.5.1", "lodash": "^4.17.11", "source-map": "^0.5.0", @@ -47,12 +47,12 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.4.4" } }, "@babel/highlight": { @@ -64,45 +64,37 @@ "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" - }, - "dependencies": { - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - } } }, "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", + "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", "dev": true }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" } }, "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", + "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", + "@babel/generator": "^7.4.4", "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.11" @@ -126,9 +118,9 @@ } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -142,15 +134,33 @@ "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "argparse": { @@ -162,38 +172,6 @@ "sprintf-js": "~1.0.2" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -222,15 +200,15 @@ } }, "bip32": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.0.tgz", - "integrity": "sha512-dYuSVcH43KXLsmiOlud62m5ZP3KG8UBUAbP+wMq8VKuhPvxOOM8VOXRs6ppcJB4iUJtYjmg7VuzTlr8waMusfg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.3.tgz", + "integrity": "sha512-Tg4dHUXiYBkJyCQq4g++C2PqKcZRveVqy7cKxyl88Uai7MmmknFGaF88odYrXcXk5EMyrlXLuAMC3yEiLxRnNA==", "requires": { "@types/node": "10.12.18", "bs58check": "^2.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "tiny-secp256k1": "^1.0.0", + "tiny-secp256k1": "^1.1.0", "typeforce": "^1.11.5", "wif": "^2.0.6" } @@ -323,6 +301,24 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -332,17 +328,6 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } } }, "cipher-base": { @@ -354,6 +339,17 @@ "safe-buffer": "^5.0.1" } }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -375,12 +371,40 @@ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + } + }, "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -406,6 +430,16 @@ "sha.js": "^2.4.8" } }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -415,6 +449,21 @@ "ms": "2.0.0" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, "dhttp": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz", @@ -444,6 +493,36 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -462,6 +541,36 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -477,12 +586,57 @@ "merge-descriptors": "~1.0.0" } }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -498,9 +652,15 @@ } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, "growl": { @@ -509,13 +669,24 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "has-flag": { @@ -542,6 +713,15 @@ "minimalistic-assert": "^1.0.1" } }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -564,6 +744,18 @@ "integrity": "sha512-j1jog3tDfhpWlqbVbh29qc7FG7w+NT4ed+QQFGqvww83+50AzzretB7wykZGOe28mBdvCYH3GdHaVWJQ2lJ/4w==", "dev": true }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -579,43 +771,157 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", "dev": true }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, "istanbul-lib-instrument": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", - "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", "dev": true, "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.3", - "semver": "^5.5.0" + "handlebars": "^4.1.2" } }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", - "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -628,12 +934,92 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -644,17 +1030,51 @@ "safe-buffer": "^5.1.2" } }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "merkle-lib": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimaldata": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz", @@ -735,1173 +1155,101 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, - "nyc": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.3.0.tgz", - "integrity": "sha512-P+FwIuro2aFG6B0Esd9ZDWUd51uZrAEoGutqZxzrVmYl3qSfkLgcQpBPBjtDFsUQLFY1dvTQJPOyeqr8S9GF8w==", + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^3.0.1", - "convert-source-map": "^1.6.0", - "find-cache-dir": "^2.0.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.3", - "istanbul-lib-hook": "^2.0.3", - "istanbul-lib-instrument": "^3.1.0", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.2", - "istanbul-reports": "^2.1.1", - "make-dir": "^1.3.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.1.0", - "uuid": "^3.3.2", - "yargs": "^12.0.5", - "yargs-parser": "^11.1.1" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "append-transform": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "async": { - "version": "2.6.2", - "resolved": false, - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": false, - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "caching-transform": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha512-Y1KTLNwSPd4ljsDrFOtyXVmm7Gnk42yQitNq43AhE+cwUR/e4T+rmOHs1IPtzBg8066GBJfTOj1rQYFSWSsH2g==", - "dev": true, - "requires": { - "hasha": "^3.0.0", - "make-dir": "^1.3.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.3.0" - } - }, - "camelcase": { - "version": "5.0.0", - "resolved": false, - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": false, - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "commander": { - "version": "2.17.1", - "resolved": false, - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - }, - "commondir": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": false, - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cross-spawn": { - "version": "4.0.2", - "resolved": false, - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "debug": { - "version": "4.1.1", - "resolved": false, - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": false, - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": false, - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": false, - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": false, - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "find-cache-dir": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "foreground-child": { - "version": "1.5.6", - "resolved": false, - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": false, - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": false, - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": false, - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true - }, - "handlebars": { - "version": "4.1.0", - "resolved": false, - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", - "dev": true, - "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": false, - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "hasha": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", - "dev": true, - "requires": { - "is-stream": "^1.0.1" - } - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": false, - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": false, - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": false, - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": false, - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": false, - "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.3", - "resolved": false, - "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, - "istanbul-lib-report": { - "version": "2.0.4", - "resolved": false, - "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "supports-color": "^6.0.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": false, - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": false, - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", - "dev": true, - "requires": { - "handlebars": "^4.1.0" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": false, - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": false, - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": false, - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": false, - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": false, - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "mem": { - "version": "4.1.0", - "resolved": false, - "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^2.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": false, - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": false, - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.10", - "resolved": false, - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": false, - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": false, - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": false, - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": false, - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": false, - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": false, - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", - "dev": true - }, - "p-limit": { - "version": "2.1.0", - "resolved": false, - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - }, - "package-hash": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": false, - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": false, - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, "resolve": { - "version": "1.10.0", - "resolved": false, - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", "dev": true, "requires": { "path-parse": "^1.0.6" } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": false, - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": false, - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "semver": { - "version": "5.6.0", - "resolved": false, - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "spawn-wrap": { - "version": "1.4.2", - "resolved": false, - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": false, - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": false, - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.3", - "resolved": false, - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": false, - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "test-exclude": { - "version": "5.1.0", - "resolved": false, - "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^1.0.1" - } - }, - "uglify-js": { - "version": "3.4.9", - "resolved": false, - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": false, - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "uuid": { - "version": "3.3.2", - "resolved": false, - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": false, - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": false, - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": false, - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": false, - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.2", - "resolved": false, - "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": false, - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": false, - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": false, - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": false, - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -1915,18 +1263,138 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -1940,6 +1408,21 @@ "sha.js": "^2.4.8" } }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, "prettier": { "version": "1.16.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", @@ -1957,6 +1440,22 @@ "resolve": "~1.8.1" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "pushdata-bitcoin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", @@ -1973,6 +1472,48 @@ "safe-buffer": "^5.1.0" } }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -1982,6 +1523,12 @@ "path-parse": "^1.0.5" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -2022,9 +1569,15 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "sha.js": { @@ -2036,12 +1589,79 @@ "safe-buffer": "^5.0.1" } }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "spawn-wrap": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -2054,15 +1674,38 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^4.1.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -2072,6 +1715,34 @@ "has-flag": "^3.0.0" } }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "tiny-secp256k1": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.1.tgz", @@ -2103,24 +1774,24 @@ "dev": true }, "tslint": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.1.tgz", - "integrity": "sha512-fplQqb2miLbcPhyHoMV4FU9PtNRbgmm/zI5d3SZwwmJQM6V0eodju+hplpyfhLWpmwrDNfNYU57uYRb8s0zZoQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz", + "integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", + "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", "chalk": "^2.3.0", "commander": "^2.12.1", "diff": "^3.2.0", "glob": "^7.1.1", - "js-yaml": "^3.7.0", + "js-yaml": "^3.13.0", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", - "tsutils": "^2.27.2" + "tsutils": "^2.29.0" } }, "tsutils": { @@ -2143,12 +1814,55 @@ "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", "dev": true }, + "uglify-js": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz", + "integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "unorm": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.5.0.tgz", "integrity": "sha512-sMfSWoiRaXXeDZSXC+YRZ23H4xchQpwxjpw1tmfR+kgbBCaOgln4NI0LXejJIhnBuKINrB3WRn+ZI8IWssirVw==", "dev": true }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "varuint-bitcoin": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz", @@ -2157,6 +1871,21 @@ "safe-buffer": "^5.1.1" } }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, "wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", @@ -2165,11 +1894,80 @@ "bs58check": "<3.0.0" } }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "write-file-atomic": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } } diff --git a/package.json b/package.json index 1f6f83a..5c1d3d2 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "dependencies": { "@types/node": "10.12.18", "bech32": "^1.1.2", - "bip32": "^2.0.0", + "bip32": "^2.0.3", "bip66": "^1.1.0", "bitcoin-ops": "^1.4.0", "bs58check": "^2.0.0", @@ -69,11 +69,11 @@ "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^5.2.0", - "nyc": "^13.3.0", + "nyc": "^14.1.1", "prettier": "1.16.4", "proxyquire": "^2.0.1", "rimraf": "^2.6.3", - "tslint": "5.13.1", + "tslint": "^5.16.0", "typescript": "3.2.2" }, "license": "MIT" From 04b1f50a2f9c53716b942e43ec4e3160e81db539 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 21 May 2019 15:23:18 +0900 Subject: [PATCH 183/183] Add js format check to CI --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98429f5..b24a248 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "coverage": "npm run build && npm run nobuild:coverage", "format": "npm run prettier -- --write", "formatjs": "npm run prettierjs -- --write > /dev/null 2>&1", - "format:ci": "npm run prettier -- --check", + "format:ci": "npm run prettier -- --check && npm run prettierjs -- --check", "gitdiff:ci": "npm run build && git diff --exit-code", "integration": "npm run build && npm run nobuild:integration", "lint": "tslint -p tsconfig.json -c tslint.json",