style: add build output after applying prettier

This commit is contained in:
d-yokoi 2019-03-03 23:31:17 +09:00
parent 6526000999
commit 0ad8fbc6ba
No known key found for this signature in database
GPG key ID: 49EAF81BC6A0D19A
22 changed files with 217 additions and 203 deletions

View file

@ -25,7 +25,7 @@ function fromBech32(address) {
return { return {
version: result.words[0], version: result.words[0],
prefix: result.prefix, prefix: result.prefix,
data: Buffer.from(data) data: Buffer.from(data),
}; };
} }
exports.fromBech32 = fromBech32; exports.fromBech32 = fromBech32;
@ -44,6 +44,7 @@ function toBech32(data, version, prefix) {
} }
exports.toBech32 = toBech32; exports.toBech32 = toBech32;
function fromOutputScript(output, network) { function fromOutputScript(output, network) {
//TODO: Network
network = network || networks.bitcoin; network = network || networks.bitcoin;
try { try {
return payments.p2pkh({ output, network }).address; return payments.p2pkh({ output, network }).address;

View file

@ -10,22 +10,22 @@ const varuint = require('varuint-bitcoin');
const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions'); const errorMerkleNoTxes = new TypeError('Cannot compute merkle root for zero transactions');
const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block'); const errorWitnessNotSegwit = new TypeError('Cannot compute witness commit for non-segwit block');
function txesHaveWitnessCommit(transactions) { function txesHaveWitnessCommit(transactions) {
return transactions instanceof Array && return (transactions instanceof Array &&
transactions[0] && transactions[0] &&
transactions[0].ins && transactions[0].ins &&
transactions[0].ins instanceof Array && transactions[0].ins instanceof Array &&
transactions[0].ins[0] && transactions[0].ins[0] &&
transactions[0].ins[0].witness && transactions[0].ins[0].witness &&
transactions[0].ins[0].witness instanceof Array && transactions[0].ins[0].witness instanceof Array &&
transactions[0].ins[0].witness.length > 0; transactions[0].ins[0].witness.length > 0);
} }
function anyTxHasWitness(transactions) { function anyTxHasWitness(transactions) {
return transactions instanceof Array && return (transactions instanceof Array &&
transactions.some(tx => typeof tx === 'object' && transactions.some(tx => typeof tx === 'object' &&
tx.ins instanceof Array && tx.ins instanceof Array &&
tx.ins.some(input => typeof input === 'object' && tx.ins.some(input => typeof input === 'object' &&
input.witness instanceof Array && input.witness instanceof Array &&
input.witness.length > 0)); input.witness.length > 0)));
} }
class Block { class Block {
constructor() { constructor() {
@ -116,9 +116,7 @@ class Block {
// There is no rule for the index of the output, so use filter to find it. // 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 // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
// If multiple commits are found, the output with highest index is assumed. // If multiple commits are found, the output with highest index is assumed.
let witnessCommits = this.transactions[0].outs 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));
.filter(out => out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')))
.map(out => out.script.slice(6, 38));
if (witnessCommits.length === 0) if (witnessCommits.length === 0)
return null; return null;
// Use the commit with the highest output (should only be one though) // Use the commit with the highest output (should only be one though)
@ -141,8 +139,9 @@ class Block {
byteLength(headersOnly) { byteLength(headersOnly) {
if (headersOnly || !this.transactions) if (headersOnly || !this.transactions)
return 80; return 80;
return 80 + varuint.encodingLength(this.transactions.length) + return (80 +
this.transactions.reduce((a, x) => a + x.byteLength(), 0); varuint.encodingLength(this.transactions.length) +
this.transactions.reduce((a, x) => a + x.byteLength(), 0));
} }
getHash() { getHash() {
return bcrypto.hash256(this.toBuffer(true)); return bcrypto.hash256(this.toBuffer(true));
@ -197,8 +196,8 @@ class Block {
let hasWitnessCommit = this.hasWitnessCommit(); let hasWitnessCommit = this.hasWitnessCommit();
if (!hasWitnessCommit && this.hasWitness()) if (!hasWitnessCommit && this.hasWitness())
return false; return false;
return this.__checkMerkleRoot() && return (this.__checkMerkleRoot() &&
(hasWitnessCommit ? this.__checkWitnessCommit() : true); (hasWitnessCommit ? this.__checkWitnessCommit() : true));
} }
checkMerkleRoot() { checkMerkleRoot() {
console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' + console.warn('Deprecation Warning: Block method checkMerkleRoot will be ' +

View file

@ -18,7 +18,7 @@ const types = {
P2SH: 'scripthash', P2SH: 'scripthash',
P2WPKH: 'witnesspubkeyhash', P2WPKH: 'witnesspubkeyhash',
P2WSH: 'witnessscripthash', P2WSH: 'witnessscripthash',
WITNESS_COMMITMENT: 'witnesscommitment' WITNESS_COMMITMENT: 'witnesscommitment',
}; };
exports.types = types; exports.types = types;
function classifyOutput(script) { function classifyOutput(script) {

View file

@ -2,15 +2,21 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const createHash = require('create-hash'); const createHash = require('create-hash');
function ripemd160(buffer) { function ripemd160(buffer) {
return createHash('rmd160').update(buffer).digest(); return createHash('rmd160')
.update(buffer)
.digest();
} }
exports.ripemd160 = ripemd160; exports.ripemd160 = ripemd160;
function sha1(buffer) { function sha1(buffer) {
return createHash('sha1').update(buffer).digest(); return createHash('sha1')
.update(buffer)
.digest();
} }
exports.sha1 = sha1; exports.sha1 = sha1;
function sha256(buffer) { function sha256(buffer) {
return createHash('sha256').update(buffer).digest(); return createHash('sha256')
.update(buffer)
.digest();
} }
exports.sha256 = sha256; exports.sha256 = sha256;
function hash160(buffer) { function hash160(buffer) {

View file

@ -8,13 +8,14 @@ const typeforce = require('typeforce');
const wif = require('wif'); const wif = require('wif');
const isOptions = typeforce.maybe(typeforce.compile({ const isOptions = typeforce.maybe(typeforce.compile({
compressed: types.maybe(types.Boolean), compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network) network: types.maybe(types.Network),
})); }));
class ECPair { class ECPair {
constructor(d, Q, options) { constructor(d, Q, options) {
if (options === undefined) if (options === undefined)
options = {}; options = {};
this.compressed = options.compressed === undefined ? true : options.compressed; this.compressed =
options.compressed === undefined ? true : options.compressed;
this.network = options.network || NETWORKS.bitcoin; this.network = options.network || NETWORKS.bitcoin;
this.__d = undefined; this.__d = undefined;
this.__Q = undefined; this.__Q = undefined;
@ -64,9 +65,11 @@ function fromWIF(string, network) {
const version = decoded.version; const version = decoded.version;
// list of networks? // list of networks?
if (types.Array(network)) { if (types.Array(network)) {
network = network.filter(function (x) { network = network
.filter(function (x) {
return version === x.wif; return version === x.wif;
}).pop(); })
.pop();
if (!network) if (!network)
throw new Error('Unknown network version'); throw new Error('Unknown network version');
// otherwise, assume a network object (or default to bitcoin) // otherwise, assume a network object (or default to bitcoin)
@ -78,7 +81,7 @@ function fromWIF(string, network) {
} }
return fromPrivateKey(decoded.privateKey, { return fromPrivateKey(decoded.privateKey, {
compressed: decoded.compressed, compressed: decoded.compressed,
network: network network: network,
}); });
} }
exports.fromWIF = fromWIF; exports.fromWIF = fromWIF;

View file

@ -5,31 +5,31 @@ exports.bitcoin = {
bech32: 'bc', bech32: 'bc',
bip32: { bip32: {
public: 0x0488b21e, public: 0x0488b21e,
private: 0x0488ade4 private: 0x0488ade4,
}, },
pubKeyHash: 0x00, pubKeyHash: 0x00,
scriptHash: 0x05, scriptHash: 0x05,
wif: 0x80 wif: 0x80,
}; };
exports.regtest = { exports.regtest = {
messagePrefix: '\x18Bitcoin Signed Message:\n', messagePrefix: '\x18Bitcoin Signed Message:\n',
bech32: 'bcrt', bech32: 'bcrt',
bip32: { bip32: {
public: 0x043587cf, public: 0x043587cf,
private: 0x04358394 private: 0x04358394,
}, },
pubKeyHash: 0x6f, pubKeyHash: 0x6f,
scriptHash: 0xc4, scriptHash: 0xc4,
wif: 0xef wif: 0xef,
}; };
exports.testnet = { exports.testnet = {
messagePrefix: '\x18Bitcoin Signed Message:\n', messagePrefix: '\x18Bitcoin Signed Message:\n',
bech32: 'tb', bech32: 'tb',
bip32: { bip32: {
public: 0x043587cf, public: 0x043587cf,
private: 0x04358394 private: 0x04358394,
}, },
pubKeyHash: 0x6f, pubKeyHash: 0x6f,
scriptHash: 0xc4, scriptHash: 0xc4,
wif: 0xef wif: 0xef,
}; };

View file

@ -14,14 +14,13 @@ function stacksEqual(a, b) {
} }
// output: OP_RETURN ... // output: OP_RETURN ...
function p2data(a, opts) { function p2data(a, opts) {
if (!a.data && if (!a.data && !a.output)
!a.output)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
network: typef.maybe(typef.Object), network: typef.maybe(typef.Object),
output: typef.maybe(typef.Buffer), output: typef.maybe(typef.Buffer),
data: typef.maybe(typef.arrayOf(typef.Buffer)) data: typef.maybe(typef.arrayOf(typef.Buffer)),
}, a); }, a);
const network = a.network || networks_1.bitcoin; const network = a.network || networks_1.bitcoin;
const o = { network }; const o = { network };

View file

@ -14,9 +14,9 @@ function prop(object, name, f) {
configurable: true, configurable: true,
enumerable: true, enumerable: true,
value: value, value: value,
writable: true writable: true,
}); });
} },
}); });
} }
exports.prop = prop; exports.prop = prop;

View file

@ -24,9 +24,8 @@ function p2ms(a, opts) {
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
function isAcceptableSignature(x) { function isAcceptableSignature(x) {
return bscript.isCanonicalScriptSignature(x) || return (bscript.isCanonicalScriptSignature(x) ||
(opts.allowIncomplete && (opts.allowIncomplete && x === OPS.OP_0) !== undefined); // eslint-disable-line
(x === OPS.OP_0)) !== undefined; // eslint-disable-line
} }
typef({ typef({
network: typef.maybe(typef.Object), network: typef.maybe(typef.Object),
@ -35,7 +34,7 @@ function p2ms(a, opts) {
output: typef.maybe(typef.Buffer), output: typef.maybe(typef.Buffer),
pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)),
signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)),
input: typef.maybe(typef.Buffer) input: typef.maybe(typef.Buffer),
}, a); }, a);
const network = a.network || networks_1.bitcoin; const network = a.network || networks_1.bitcoin;
const o = { network }; const o = { network };
@ -131,7 +130,8 @@ function p2ms(a, opts) {
if (a.input) { if (a.input) {
if (a.input[0] !== OPS.OP_0) if (a.input[0] !== OPS.OP_0)
throw new TypeError('Input is invalid'); 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)'); throw new TypeError('Input has invalid signature(s)');
if (a.signatures && !stacksEqual(a.signatures, o.signatures)) if (a.signatures && !stacksEqual(a.signatures, o.signatures))
throw new TypeError('Signature mismatch'); throw new TypeError('Signature mismatch');

View file

@ -9,11 +9,7 @@ const ecc = require('tiny-secp256k1');
// input: {signature} // input: {signature}
// output: {pubKey} OP_CHECKSIG // output: {pubKey} OP_CHECKSIG
function p2pk(a, opts) { function p2pk(a, opts) {
if (!a.input && if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature)
!a.output &&
!a.pubkey &&
!a.input &&
!a.signature)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
@ -21,18 +17,17 @@ function p2pk(a, opts) {
output: typef.maybe(typef.Buffer), output: typef.maybe(typef.Buffer),
pubkey: typef.maybe(ecc.isPoint), pubkey: typef.maybe(ecc.isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature), signature: typef.maybe(bscript.isCanonicalScriptSignature),
input: typef.maybe(typef.Buffer) input: typef.maybe(typef.Buffer),
}, a); }, 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 network = a.network || networks_1.bitcoin;
const o = { network }; const o = { network };
lazy.prop(o, 'output', function () { lazy.prop(o, 'output', function () {
if (!a.pubkey) if (!a.pubkey)
return; return;
return bscript.compile([ return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]);
a.pubkey,
OPS.OP_CHECKSIG
]);
}); });
lazy.prop(o, 'pubkey', function () { lazy.prop(o, 'pubkey', function () {
if (!a.output) if (!a.output)

View file

@ -11,11 +11,7 @@ const bs58check = require('bs58check');
// input: {signature} {pubkey} // input: {signature} {pubkey}
// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
function p2pkh(a, opts) { function p2pkh(a, opts) {
if (!a.address && if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
!a.hash &&
!a.output &&
!a.pubkey &&
!a.input)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
@ -25,7 +21,7 @@ function p2pkh(a, opts) {
output: typef.maybe(typef.BufferN(25)), output: typef.maybe(typef.BufferN(25)),
pubkey: typef.maybe(ecc.isPoint), pubkey: typef.maybe(ecc.isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature), signature: typef.maybe(bscript.isCanonicalScriptSignature),
input: typef.maybe(typef.Buffer) input: typef.maybe(typef.Buffer),
}, a); }, a);
const _address = lazy.value(function () { const _address = lazy.value(function () {
const payload = bs58check.decode(a.address); const payload = bs58check.decode(a.address);
@ -33,7 +29,9 @@ function p2pkh(a, opts) {
const hash = payload.slice(1); const hash = payload.slice(1);
return { version, hash }; 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 network = a.network || networks_1.bitcoin;
const o = { network }; const o = { network };
lazy.prop(o, 'address', function () { lazy.prop(o, 'address', function () {
@ -60,7 +58,7 @@ function p2pkh(a, opts) {
OPS.OP_HASH160, OPS.OP_HASH160,
o.hash, o.hash,
OPS.OP_EQUALVERIFY, OPS.OP_EQUALVERIFY,
OPS.OP_CHECKSIG OPS.OP_CHECKSIG,
]); ]);
}); });
lazy.prop(o, 'pubkey', function () { lazy.prop(o, 'pubkey', function () {

View file

@ -18,11 +18,7 @@ function stacksEqual(a, b) {
// witness: <?> // witness: <?>
// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
function p2sh(a, opts) { function p2sh(a, opts) {
if (!a.address && if (!a.address && !a.hash && !a.output && !a.redeem && !a.input)
!a.hash &&
!a.output &&
!a.redeem &&
!a.input)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
@ -34,10 +30,10 @@ function p2sh(a, opts) {
network: typef.maybe(typef.Object), network: typef.maybe(typef.Object),
output: typef.maybe(typef.Buffer), output: typef.maybe(typef.Buffer),
input: 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), input: typef.maybe(typef.Buffer),
witness: typef.maybe(typef.arrayOf(typef.Buffer)) witness: typef.maybe(typef.arrayOf(typef.Buffer)),
}, a); }, a);
let network = a.network; let network = a.network;
if (!network) { if (!network) {
@ -50,14 +46,16 @@ function p2sh(a, opts) {
const hash = payload.slice(1); const hash = payload.slice(1);
return { version, hash }; 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 _redeem = lazy.value(function () {
const chunks = _chunks(); const chunks = _chunks();
return { return {
network, network,
output: chunks[chunks.length - 1], output: chunks[chunks.length - 1],
input: bscript.compile(chunks.slice(0, -1)), input: bscript.compile(chunks.slice(0, -1)),
witness: a.witness || [] witness: a.witness || [],
}; };
}); });
// output dependents // output dependents
@ -81,11 +79,7 @@ function p2sh(a, opts) {
lazy.prop(o, 'output', function () { lazy.prop(o, 'output', function () {
if (!o.hash) if (!o.hash)
return; return;
return bscript.compile([ return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]);
OPS.OP_HASH160,
o.hash,
OPS.OP_EQUAL
]);
}); });
// input dependents // input dependents
lazy.prop(o, 'redeem', function () { lazy.prop(o, 'redeem', function () {
@ -153,7 +147,7 @@ function p2sh(a, opts) {
if (hasInput && hasWitness) if (hasInput && hasWitness)
throw new TypeError('Input and witness provided'); throw new TypeError('Input and witness provided');
if (hasInput) { if (hasInput) {
const richunks = bscript.decompile(redeem.input); const richunks = (bscript.decompile(redeem.input));
if (!bscript.isPushOnly(richunks)) if (!bscript.isPushOnly(richunks))
throw new TypeError('Non push-only scriptSig'); throw new TypeError('Non push-only scriptSig');
} }

View file

@ -13,11 +13,7 @@ const EMPTY_BUFFER = Buffer.alloc(0);
// input: <> // input: <>
// output: OP_0 {pubKeyHash} // output: OP_0 {pubKeyHash}
function p2wpkh(a, opts) { function p2wpkh(a, opts) {
if (!a.address && if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness)
!a.hash &&
!a.output &&
!a.pubkey &&
!a.witness)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
@ -28,7 +24,7 @@ function p2wpkh(a, opts) {
output: typef.maybe(typef.BufferN(22)), output: typef.maybe(typef.BufferN(22)),
pubkey: typef.maybe(ecc.isPoint), pubkey: typef.maybe(ecc.isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature), signature: typef.maybe(bscript.isCanonicalScriptSignature),
witness: typef.maybe(typef.arrayOf(typef.Buffer)) witness: typef.maybe(typef.arrayOf(typef.Buffer)),
}, a); }, a);
const _address = lazy.value(function () { const _address = lazy.value(function () {
const result = bech32.decode(a.address); const result = bech32.decode(a.address);
@ -37,7 +33,7 @@ function p2wpkh(a, opts) {
return { return {
version, version,
prefix: result.prefix, prefix: result.prefix,
data: Buffer.from(data) data: Buffer.from(data),
}; };
}); });
const network = a.network || networks_1.bitcoin; const network = a.network || networks_1.bitcoin;
@ -60,10 +56,7 @@ function p2wpkh(a, opts) {
lazy.prop(o, 'output', function () { lazy.prop(o, 'output', function () {
if (!o.hash) if (!o.hash)
return; return;
return bscript.compile([ return bscript.compile([OPS.OP_0, o.hash]);
OPS.OP_0,
o.hash
]);
}); });
lazy.prop(o, 'pubkey', function () { lazy.prop(o, 'pubkey', function () {
if (a.pubkey) if (a.pubkey)

View file

@ -19,11 +19,7 @@ function stacksEqual(a, b) {
// witness: [redeemScriptSig ...] {redeemScript} // witness: [redeemScriptSig ...] {redeemScript}
// output: OP_0 {sha256(redeemScript)} // output: OP_0 {sha256(redeemScript)}
function p2wsh(a, opts) { function p2wsh(a, opts) {
if (!a.address && if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness)
!a.hash &&
!a.output &&
!a.redeem &&
!a.witness)
throw new TypeError('Not enough data'); throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {}); opts = Object.assign({ validate: true }, opts || {});
typef({ typef({
@ -35,10 +31,10 @@ function p2wsh(a, opts) {
input: typef.maybe(typef.Buffer), input: typef.maybe(typef.Buffer),
network: typef.maybe(typef.Object), network: typef.maybe(typef.Object),
output: typef.maybe(typef.Buffer), 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)), input: typef.maybe(typef.BufferN(0)),
witness: typef.maybe(typef.arrayOf(typef.Buffer)) witness: typef.maybe(typef.arrayOf(typef.Buffer)),
}, a); }, a);
const _address = lazy.value(function () { const _address = lazy.value(function () {
const result = bech32.decode(a.address); const result = bech32.decode(a.address);
@ -47,10 +43,12 @@ function p2wsh(a, opts) {
return { return {
version, version,
prefix: result.prefix, 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; let network = a.network;
if (!network) { if (!network) {
network = (a.redeem && a.redeem.network) || networks_1.bitcoin; network = (a.redeem && a.redeem.network) || networks_1.bitcoin;
@ -74,10 +72,7 @@ function p2wsh(a, opts) {
lazy.prop(o, 'output', function () { lazy.prop(o, 'output', function () {
if (!o.hash) if (!o.hash)
return; return;
return bscript.compile([ return bscript.compile([OPS.OP_0, o.hash]);
OPS.OP_0,
o.hash
]);
}); });
lazy.prop(o, 'redeem', function () { lazy.prop(o, 'redeem', function () {
if (!a.witness) if (!a.witness)
@ -85,7 +80,7 @@ function p2wsh(a, opts) {
return { return {
output: a.witness[a.witness.length - 1], output: a.witness[a.witness.length - 1],
input: EMPTY_BUFFER, input: EMPTY_BUFFER,
witness: a.witness.slice(0, -1) witness: a.witness.slice(0, -1),
}; };
}); });
lazy.prop(o, 'input', function () { lazy.prop(o, 'input', function () {
@ -165,11 +160,15 @@ function p2wsh(a, opts) {
} }
if (a.redeem.input && !bscript.isPushOnly(_rchunks())) if (a.redeem.input && !bscript.isPushOnly(_rchunks()))
throw new TypeError('Non push-only scriptSig'); 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'); throw new TypeError('Witness and redeem.witness mismatch');
} }
if (a.witness) { 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'); throw new TypeError('Witness and redeem.output mismatch');
} }
} }

View file

@ -11,10 +11,10 @@ exports.OPS = require('bitcoin-ops');
const REVERSE_OPS = require('bitcoin-ops/map'); const REVERSE_OPS = require('bitcoin-ops/map');
const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1 const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1
function isOPInt(value) { function isOPInt(value) {
return types.Number(value) && return (types.Number(value) &&
((value === exports.OPS.OP_0) || (value === exports.OPS.OP_0 ||
(value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) ||
(value === exports.OPS.OP_1NEGATE)); value === exports.OPS.OP_1NEGATE));
} }
function isPushOnlyChunk(value) { function isPushOnlyChunk(value) {
return types.Buffer(value) || isOPInt(value); return types.Buffer(value) || isOPInt(value);
@ -96,7 +96,7 @@ function decompile(buffer) {
while (i < buffer.length) { while (i < buffer.length) {
const opcode = buffer[i]; const opcode = buffer[i];
// data chunk // 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); const d = pushdata.decode(buffer, i);
// did reading a pushDataInt fail? // did reading a pushDataInt fail?
if (d === null) if (d === null)
@ -129,7 +129,8 @@ function toASM(chunks) {
if (chunksIsBuffer(chunks)) { if (chunksIsBuffer(chunks)) {
chunks = decompile(chunks); chunks = decompile(chunks);
} }
return chunks.map(function (chunk) { return chunks
.map(function (chunk) {
// data? // data?
if (singleChunkIsBuffer(chunk)) { if (singleChunkIsBuffer(chunk)) {
const op = asMinimalOP(chunk); const op = asMinimalOP(chunk);
@ -139,7 +140,8 @@ function toASM(chunks) {
} }
// opcode! // opcode!
return REVERSE_OPS[chunk]; return REVERSE_OPS[chunk];
}).join(' '); })
.join(' ');
} }
exports.toASM = toASM; exports.toASM = toASM;
function fromASM(asm) { function fromASM(asm) {

View file

@ -19,8 +19,8 @@ function decode(buffer, maxLength, minimal) {
const a = buffer.readUInt32LE(0); const a = buffer.readUInt32LE(0);
const b = buffer.readUInt8(4); const b = buffer.readUInt8(4);
if (b & 0x80) if (b & 0x80)
return -(((b & ~0x80) * 0x100000000) + a); return -((b & ~0x80) * 0x100000000 + a);
return (b * 0x100000000) + a; return b * 0x100000000 + a;
} }
// 32-bit / 24-bit / 16-bit / 8-bit // 32-bit / 24-bit / 16-bit / 8-bit
let result = 0; let result = 0;
@ -33,11 +33,16 @@ function decode(buffer, maxLength, minimal) {
} }
exports.decode = decode; exports.decode = decode;
function scriptNumSize(i) { function scriptNumSize(i) {
return i > 0x7fffffff ? 5 return i > 0x7fffffff
: i > 0x7fffff ? 4 ? 5
: i > 0x7fff ? 3 : i > 0x7fffff
: i > 0x7f ? 2 ? 4
: i > 0x00 ? 1 : i > 0x7fff
? 3
: i > 0x7f
? 2
: i > 0x00
? 1
: 0; : 0;
} }
function encode(number) { function encode(number) {

View file

@ -34,14 +34,14 @@ function decode(buffer) {
const s = fromDER(decode.s); const s = fromDER(decode.s);
return { return {
signature: Buffer.concat([r, s], 64), signature: Buffer.concat([r, s], 64),
hashType: hashType hashType: hashType,
}; };
} }
exports.decode = decode; exports.decode = decode;
function encode(signature, hashType) { function encode(signature, hashType) {
typeforce({ typeforce({
signature: types.BufferN(64), signature: types.BufferN(64),
hashType: types.UInt8 hashType: types.UInt8,
}, { signature, hashType }); }, { signature, hashType });
const hashTypeMod = hashType & ~0x80; const hashTypeMod = hashType & ~0x80;
if (hashTypeMod <= 0 || hashTypeMod >= 4) if (hashTypeMod <= 0 || hashTypeMod >= 4)
@ -50,9 +50,6 @@ function encode(signature, hashType) {
hashTypeBuffer.writeUInt8(hashType, 0); hashTypeBuffer.writeUInt8(hashType, 0);
const r = toDER(signature.slice(0, 32)); const r = toDER(signature.slice(0, 32));
const s = toDER(signature.slice(32, 64)); const s = toDER(signature.slice(32, 64));
return Buffer.concat([ return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]);
bip66.encode(r, s),
hashTypeBuffer
]);
} }
exports.encode = encode; exports.encode = encode;

View file

@ -5,10 +5,11 @@ const bscript = require("../script");
const OPS = bscript.OPS; const OPS = bscript.OPS;
function check(script) { function check(script) {
const buffer = bscript.compile(script); const buffer = bscript.compile(script);
return buffer.length > 1 && return buffer.length > 1 && buffer[0] === OPS.OP_RETURN;
buffer[0] === OPS.OP_RETURN;
} }
exports.check = check; exports.check = check;
check.toJSON = function () { return 'null data output'; }; check.toJSON = function () {
return 'null data output';
};
const output = { check }; const output = { check };
exports.output = output; exports.output = output;

View file

@ -14,9 +14,10 @@ function varSliceSize(someScript) {
} }
function vectorSize(someVector) { function vectorSize(someVector) {
const length = someVector.length; const length = someVector.length;
return varuint.encodingLength(length) + someVector.reduce((sum, witness) => { return (varuint.encodingLength(length) +
return sum + varSliceSize(witness); someVector.reduce((sum, witness) => {
}, 0); return sum + varSliceSize(witness);
}, 0));
} }
const EMPTY_SCRIPT = Buffer.allocUnsafe(0); const EMPTY_SCRIPT = Buffer.allocUnsafe(0);
const EMPTY_WITNESS = []; const EMPTY_WITNESS = [];
@ -25,7 +26,7 @@ const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000
const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex');
const BLANK_OUTPUT = { const BLANK_OUTPUT = {
script: EMPTY_SCRIPT, script: EMPTY_SCRIPT,
valueBuffer: VALUE_UINT64_MAX valueBuffer: VALUE_UINT64_MAX,
}; };
function isOutput(out) { function isOutput(out) {
return out.value !== undefined; return out.value !== undefined;
@ -90,14 +91,14 @@ class Transaction {
index: readUInt32(), index: readUInt32(),
script: readVarSlice(), script: readVarSlice(),
sequence: readUInt32(), sequence: readUInt32(),
witness: EMPTY_WITNESS witness: EMPTY_WITNESS,
}); });
} }
const voutLen = readVarInt(); const voutLen = readVarInt();
for (i = 0; i < voutLen; ++i) { for (i = 0; i < voutLen; ++i) {
tx.outs.push({ tx.outs.push({
value: readUInt64(), value: readUInt64(),
script: readVarSlice() script: readVarSlice(),
}); });
} }
if (hasWitnesses) { if (hasWitnesses) {
@ -127,7 +128,7 @@ class Transaction {
return true; return true;
} }
isCoinbase() { 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) { addInput(hash, index, sequence, scriptSig) {
typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments); typeforce(types.tuple(types.Hash256bit, types.UInt32, types.maybe(types.UInt32), types.maybe(types.Buffer)), arguments);
@ -140,7 +141,7 @@ class Transaction {
index: index, index: index,
script: scriptSig || EMPTY_SCRIPT, script: scriptSig || EMPTY_SCRIPT,
sequence: sequence, sequence: sequence,
witness: EMPTY_WITNESS witness: EMPTY_WITNESS,
}) - 1); }) - 1);
} }
addOutput(scriptPubKey, value) { addOutput(scriptPubKey, value) {
@ -148,11 +149,11 @@ class Transaction {
// Add the output and return the output's index // Add the output and return the output's index
return (this.outs.push({ return (this.outs.push({
script: scriptPubKey, script: scriptPubKey,
value: value value: value,
}) - 1); }) - 1);
} }
hasWitnesses() { hasWitnesses() {
return this.ins.some((x) => { return this.ins.some(x => {
return x.witness.length !== 0; return x.witness.length !== 0;
}); });
} }
@ -178,27 +179,29 @@ class Transaction {
this.outs.reduce((sum, output) => { this.outs.reduce((sum, output) => {
return sum + 8 + varSliceSize(output.script); return sum + 8 + varSliceSize(output.script);
}, 0) + }, 0) +
(hasWitnesses ? this.ins.reduce((sum, input) => { (hasWitnesses
return sum + vectorSize(input.witness); ? this.ins.reduce((sum, input) => {
}, 0) : 0)); return sum + vectorSize(input.witness);
}, 0)
: 0));
} }
clone() { clone() {
const newTx = new Transaction(); const newTx = new Transaction();
newTx.version = this.version; newTx.version = this.version;
newTx.locktime = this.locktime; newTx.locktime = this.locktime;
newTx.ins = this.ins.map((txIn) => { newTx.ins = this.ins.map(txIn => {
return { return {
hash: txIn.hash, hash: txIn.hash,
index: txIn.index, index: txIn.index,
script: txIn.script, script: txIn.script,
sequence: txIn.sequence, sequence: txIn.sequence,
witness: txIn.witness witness: txIn.witness,
}; };
}); });
newTx.outs = this.outs.map((txOut) => { newTx.outs = this.outs.map(txOut => {
return { return {
script: txOut.script, script: txOut.script,
value: txOut.value value: txOut.value,
}; };
}); });
return newTx; return newTx;
@ -217,7 +220,7 @@ class Transaction {
if (inIndex >= this.ins.length) if (inIndex >= this.ins.length)
return ONE; return ONE;
// ignore OP_CODESEPARATOR // 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; return x !== script_1.OPS.OP_CODESEPARATOR;
})); }));
const txTmp = this.clone(); const txTmp = this.clone();
@ -257,7 +260,7 @@ class Transaction {
} }
else { else {
// "blank" others input scripts // "blank" others input scripts
txTmp.ins.forEach((input) => { txTmp.ins.forEach(input => {
input.script = EMPTY_SCRIPT; input.script = EMPTY_SCRIPT;
}); });
txTmp.ins[inIndex].script = ourScript; txTmp.ins[inIndex].script = ourScript;
@ -295,7 +298,7 @@ class Transaction {
if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) {
tbuffer = Buffer.allocUnsafe(36 * this.ins.length); tbuffer = Buffer.allocUnsafe(36 * this.ins.length);
toffset = 0; toffset = 0;
this.ins.forEach((txIn) => { this.ins.forEach(txIn => {
writeSlice(txIn.hash); writeSlice(txIn.hash);
writeUInt32(txIn.index); writeUInt32(txIn.index);
}); });
@ -306,7 +309,7 @@ class Transaction {
(hashType & 0x1f) !== Transaction.SIGHASH_NONE) { (hashType & 0x1f) !== Transaction.SIGHASH_NONE) {
tbuffer = Buffer.allocUnsafe(4 * this.ins.length); tbuffer = Buffer.allocUnsafe(4 * this.ins.length);
toffset = 0; toffset = 0;
this.ins.forEach((txIn) => { this.ins.forEach(txIn => {
writeUInt32(txIn.sequence); writeUInt32(txIn.sequence);
}); });
hashSequence = bcrypto.hash256(tbuffer); hashSequence = bcrypto.hash256(tbuffer);
@ -318,13 +321,14 @@ class Transaction {
}, 0); }, 0);
tbuffer = Buffer.allocUnsafe(txOutsSize); tbuffer = Buffer.allocUnsafe(txOutsSize);
toffset = 0; toffset = 0;
this.outs.forEach((out) => { this.outs.forEach(out => {
writeUInt64(out.value); writeUInt64(out.value);
writeVarSlice(out.script); writeVarSlice(out.script);
}); });
hashOutputs = bcrypto.hash256(tbuffer); 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]; const output = this.outs[inIndex];
tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script));
toffset = 0; toffset = 0;
@ -369,13 +373,13 @@ class Transaction {
offset += slice.copy(buffer, offset); offset += slice.copy(buffer, offset);
} }
function writeUInt8(i) { function writeUInt8(i) {
offset = (buffer).writeUInt8(i, offset); offset = buffer.writeUInt8(i, offset);
} }
function writeUInt32(i) { function writeUInt32(i) {
offset = (buffer).writeUInt32LE(i, offset); offset = buffer.writeUInt32LE(i, offset);
} }
function writeInt32(i) { function writeInt32(i) {
offset = (buffer).writeInt32LE(i, offset); offset = buffer.writeInt32LE(i, offset);
} }
function writeUInt64(i) { function writeUInt64(i) {
offset = bufferutils.writeUInt64LE(buffer, i, offset); offset = bufferutils.writeUInt64LE(buffer, i, offset);
@ -399,14 +403,14 @@ class Transaction {
writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG);
} }
writeVarInt(this.ins.length); writeVarInt(this.ins.length);
this.ins.forEach((txIn) => { this.ins.forEach(txIn => {
writeSlice(txIn.hash); writeSlice(txIn.hash);
writeUInt32(txIn.index); writeUInt32(txIn.index);
writeVarSlice(txIn.script); writeVarSlice(txIn.script);
writeUInt32(txIn.sequence); writeUInt32(txIn.sequence);
}); });
writeVarInt(this.outs.length); writeVarInt(this.outs.length);
this.outs.forEach((txOut) => { this.outs.forEach(txOut => {
if (isOutput(txOut)) { if (isOutput(txOut)) {
writeUInt64(txOut.value); writeUInt64(txOut.value);
} }
@ -416,7 +420,7 @@ class Transaction {
writeVarSlice(txOut.script); writeVarSlice(txOut.script);
}); });
if (hasWitnesses) { if (hasWitnesses) {
this.ins.forEach((input) => { this.ins.forEach(input => {
writeVector(input.witness); writeVector(input.witness);
}); });
} }

View file

@ -43,7 +43,7 @@ class TransactionBuilder {
txb.__addInputUnsafe(txIn.hash, txIn.index, { txb.__addInputUnsafe(txIn.hash, txIn.index, {
sequence: txIn.sequence, sequence: txIn.sequence,
script: txIn.script, script: txIn.script,
witness: txIn.witness witness: txIn.witness,
}); });
}); });
// fix some things not possible through the public API // fix some things not possible through the public API
@ -89,7 +89,7 @@ class TransactionBuilder {
return this.__addInputUnsafe(txHash, vout, { return this.__addInputUnsafe(txHash, vout, {
sequence: sequence, sequence: sequence,
prevOutScript: prevOutScript, prevOutScript: prevOutScript,
value: value value: value,
}); });
} }
__addInputUnsafe(txHash, vout, options) { __addInputUnsafe(txHash, vout, options) {
@ -194,7 +194,7 @@ class TransactionBuilder {
if (!canSign(input)) { if (!canSign(input)) {
if (witnessValue !== undefined) { if (witnessValue !== undefined) {
if (input.value !== undefined && input.value !== witnessValue) 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); typeforce(types.Satoshi, witnessValue);
input.value = witnessValue; input.value = witnessValue;
} }
@ -251,18 +251,19 @@ class TransactionBuilder {
} }
// if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs
// .build() will fail, but .buildIncomplete() is OK // .build() will fail, but .buildIncomplete() is OK
return (this.__tx.outs.length === 0) && this.__inputs.some((input) => { return (this.__tx.outs.length === 0 &&
if (!input.signatures) this.__inputs.some(input => {
return false; if (!input.signatures)
return input.signatures.some((signature) => { return false;
if (!signature) return input.signatures.some(signature => {
return false; // no signature, no issue if (!signature)
const hashType = signatureHashType(signature); return false; // no signature, no issue
if (hashType & transaction_1.Transaction.SIGHASH_NONE) const hashType = signatureHashType(signature);
return false; // SIGHASH_NONE doesn't care about outputs if (hashType & transaction_1.Transaction.SIGHASH_NONE)
return true; // SIGHASH_* does care return false; // SIGHASH_NONE doesn't care about outputs
}); return true; // SIGHASH_* does care
}); });
}));
} }
__canModifyOutputs() { __canModifyOutputs() {
const nInputs = this.__tx.ins.length; const nInputs = this.__tx.ins.length;
@ -313,21 +314,25 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) {
} }
switch (type) { switch (type) {
case SCRIPT_TYPES.P2WPKH: { case SCRIPT_TYPES.P2WPKH: {
const { output, pubkey, signature } = payments.p2wpkh({ witness: witnessStack }); const { output, pubkey, signature } = payments.p2wpkh({
witness: witnessStack,
});
return { return {
prevOutScript: output, prevOutScript: output,
prevOutType: SCRIPT_TYPES.P2WPKH, prevOutType: SCRIPT_TYPES.P2WPKH,
pubkeys: [pubkey], pubkeys: [pubkey],
signatures: [signature] signatures: [signature],
}; };
} }
case SCRIPT_TYPES.P2PKH: { case SCRIPT_TYPES.P2PKH: {
const { output, pubkey, signature } = payments.p2pkh({ input: scriptSig }); const { output, pubkey, signature } = payments.p2pkh({
input: scriptSig,
});
return { return {
prevOutScript: output, prevOutScript: output,
prevOutType: SCRIPT_TYPES.P2PKH, prevOutType: SCRIPT_TYPES.P2PKH,
pubkeys: [pubkey], pubkeys: [pubkey],
signatures: [signature] signatures: [signature],
}; };
} }
case SCRIPT_TYPES.P2PK: { case SCRIPT_TYPES.P2PK: {
@ -335,26 +340,26 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) {
return { return {
prevOutType: SCRIPT_TYPES.P2PK, prevOutType: SCRIPT_TYPES.P2PK,
pubkeys: [undefined], pubkeys: [undefined],
signatures: [signature] signatures: [signature],
}; };
} }
case SCRIPT_TYPES.P2MS: { case SCRIPT_TYPES.P2MS: {
const { m, pubkeys, signatures } = payments.p2ms({ const { m, pubkeys, signatures } = payments.p2ms({
input: scriptSig, input: scriptSig,
output: scriptPubKey output: scriptPubKey,
}, { allowIncomplete: true }); }, { allowIncomplete: true });
return { return {
prevOutType: SCRIPT_TYPES.P2MS, prevOutType: SCRIPT_TYPES.P2MS,
pubkeys: pubkeys, pubkeys: pubkeys,
signatures: signatures, signatures: signatures,
maxSignatures: m maxSignatures: m,
}; };
} }
} }
if (type === SCRIPT_TYPES.P2SH) { if (type === SCRIPT_TYPES.P2SH) {
const { output, redeem } = payments.p2sh({ const { output, redeem } = payments.p2sh({
input: scriptSig, input: scriptSig,
witness: witnessStack witness: witnessStack,
}); });
const outputType = classify.output(redeem.output); const outputType = classify.output(redeem.output);
const expanded = expandInput(redeem.input, redeem.witness, outputType, 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, witnessScript: expanded.witnessScript,
witnessScriptType: expanded.witnessScriptType, witnessScriptType: expanded.witnessScriptType,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
}; };
} }
if (type === SCRIPT_TYPES.P2WSH) { if (type === SCRIPT_TYPES.P2WSH) {
const { output, redeem } = payments.p2wsh({ const { output, redeem } = payments.p2wsh({
input: scriptSig, input: scriptSig,
witness: witnessStack witness: witnessStack,
}); });
const outputType = classify.output(redeem.output); const outputType = classify.output(redeem.output);
let expanded; let expanded;
@ -392,12 +397,12 @@ function expandInput(scriptSig, witnessStack, type, scriptPubKey) {
witnessScript: redeem.output, witnessScript: redeem.output,
witnessScriptType: expanded.prevOutType, witnessScriptType: expanded.prevOutType,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
}; };
} }
return { return {
prevOutType: SCRIPT_TYPES.NONSTANDARD, prevOutType: SCRIPT_TYPES.NONSTANDARD,
prevOutScript: scriptSig prevOutScript: scriptSig,
}; };
} }
// could be done in expandInput, but requires the original Transaction for hashForSignature // could be done in expandInput, but requires the original Transaction for hashForSignature
@ -444,7 +449,7 @@ function expandOutput(script, ourPubKey) {
return { return {
type, type,
pubkeys: [ourPubKey], pubkeys: [ourPubKey],
signatures: [undefined] signatures: [undefined],
}; };
} }
case SCRIPT_TYPES.P2WPKH: { case SCRIPT_TYPES.P2WPKH: {
@ -458,7 +463,7 @@ function expandOutput(script, ourPubKey) {
return { return {
type, type,
pubkeys: [ourPubKey], pubkeys: [ourPubKey],
signatures: [undefined] signatures: [undefined],
}; };
} }
case SCRIPT_TYPES.P2PK: { case SCRIPT_TYPES.P2PK: {
@ -466,7 +471,7 @@ function expandOutput(script, ourPubKey) {
return { return {
type, type,
pubkeys: [p2pk.pubkey], pubkeys: [p2pk.pubkey],
signatures: [undefined] signatures: [undefined],
}; };
} }
case SCRIPT_TYPES.P2MS: { case SCRIPT_TYPES.P2MS: {
@ -475,7 +480,7 @@ function expandOutput(script, ourPubKey) {
type, type,
pubkeys: p2ms.pubkeys, pubkeys: p2ms.pubkeys,
signatures: p2ms.pubkeys.map(() => undefined), 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) { function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
if (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 p2wshAlt = payments.p2wsh({ output: redeemScript });
const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); const p2sh = payments.p2sh({ redeem: { output: redeemScript } });
const p2shAlt = payments.p2sh({ redeem: p2wsh }); const p2shAlt = payments.p2sh({ redeem: p2wsh });
@ -494,7 +499,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
throw new Error('Redeem script inconsistent with prevOutScript'); 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) 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)) { if (input.signatures && input.signatures.some(x => x !== undefined)) {
expanded.signatures = input.signatures; expanded.signatures = input.signatures;
} }
@ -513,7 +521,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures, signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures maxSignatures: expanded.maxSignatures,
}; };
} }
if (redeemScript) { if (redeemScript) {
@ -531,7 +539,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
} }
const expanded = expandOutput(p2sh.redeem.output, ourPubKey); const expanded = expandOutput(p2sh.redeem.output, ourPubKey);
if (!expanded.pubkeys) 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)) { if (input.signatures && input.signatures.some(x => x !== undefined)) {
expanded.signatures = input.signatures; expanded.signatures = input.signatures;
} }
@ -549,7 +560,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures, signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures maxSignatures: expanded.maxSignatures,
}; };
} }
if (witnessScript) { if (witnessScript) {
@ -561,7 +572,10 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
} }
const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); const expanded = expandOutput(p2wsh.redeem.output, ourPubKey);
if (!expanded.pubkeys) 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)) { if (input.signatures && input.signatures.some(x => x !== undefined)) {
expanded.signatures = input.signatures; expanded.signatures = input.signatures;
} }
@ -578,7 +592,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures, signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures maxSignatures: expanded.maxSignatures,
}; };
} }
if (input.prevOutType && input.prevOutScript) { if (input.prevOutType && input.prevOutScript) {
@ -591,13 +605,16 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
throw new Error('PrevOutScript is missing'); throw new Error('PrevOutScript is missing');
const expanded = expandOutput(input.prevOutScript, ourPubKey); const expanded = expandOutput(input.prevOutScript, ourPubKey);
if (!expanded.pubkeys) 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)) { 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) { if (expanded.type === SCRIPT_TYPES.P2WPKH) {
signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; signScript = (payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output);
} }
return { return {
prevOutType: expanded.type, prevOutType: expanded.type,
@ -607,7 +624,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures, signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures maxSignatures: expanded.maxSignatures,
}; };
} }
const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output;
@ -618,7 +635,7 @@ function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
signScript: prevOutScript, signScript: prevOutScript,
signType: SCRIPT_TYPES.P2PKH, signType: SCRIPT_TYPES.P2PKH,
pubkeys: [ourPubKey], pubkeys: [ourPubKey],
signatures: [undefined] signatures: [undefined],
}; };
} }
function build(type, input, allowIncomplete) { 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 // 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) // 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 }); return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate });
} }
case SCRIPT_TYPES.P2SH: { case SCRIPT_TYPES.P2SH: {
@ -667,8 +684,8 @@ function build(type, input, allowIncomplete) {
redeem: { redeem: {
output: redeem.output || input.redeemScript, output: redeem.output || input.redeemScript,
input: redeem.input, input: redeem.input,
witness: redeem.witness witness: redeem.witness,
} },
}); });
} }
case SCRIPT_TYPES.P2WSH: { case SCRIPT_TYPES.P2WSH: {
@ -679,21 +696,20 @@ function build(type, input, allowIncomplete) {
redeem: { redeem: {
output: input.witnessScript, output: input.witnessScript,
input: redeem.input, input: redeem.input,
witness: redeem.witness witness: redeem.witness,
} },
}); });
} }
} }
} }
function canSign(input) { function canSign(input) {
return input.signScript !== undefined && return (input.signScript !== undefined &&
input.signType !== undefined && input.signType !== undefined &&
input.pubkeys !== undefined && input.pubkeys !== undefined &&
input.signatures !== undefined && input.signatures !== undefined &&
input.signatures.length === input.pubkeys.length && input.signatures.length === input.pubkeys.length &&
input.pubkeys.length > 0 && input.pubkeys.length > 0 &&
(input.hasWitness === false || (input.hasWitness === false || input.value !== undefined));
input.value !== undefined);
} }
function signatureHashType(buffer) { function signatureHashType(buffer) {
return buffer.readUInt8(buffer.length - 1); return buffer.readUInt8(buffer.length - 1);

View file

@ -10,7 +10,9 @@ function BIP32Path(value) {
return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/);
} }
exports.BIP32Path = BIP32Path; exports.BIP32Path = BIP32Path;
BIP32Path.toJSON = function () { return 'BIP32 derivation path'; }; BIP32Path.toJSON = function () {
return 'BIP32 derivation path';
};
const SATOSHI_MAX = 21 * 1e14; const SATOSHI_MAX = 21 * 1e14;
function Satoshi(value) { function Satoshi(value) {
return typeforce.UInt53(value) && value <= SATOSHI_MAX; return typeforce.UInt53(value) && value <= SATOSHI_MAX;
@ -23,11 +25,11 @@ exports.Network = typeforce.compile({
messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
bip32: { bip32: {
public: typeforce.UInt32, public: typeforce.UInt32,
private: typeforce.UInt32 private: typeforce.UInt32,
}, },
pubKeyHash: typeforce.UInt8, pubKeyHash: typeforce.UInt8,
scriptHash: typeforce.UInt8, scriptHash: typeforce.UInt8,
wif: typeforce.UInt8 wif: typeforce.UInt8,
}); });
exports.Buffer256bit = typeforce.BufferN(32); exports.Buffer256bit = typeforce.BufferN(32);
exports.Hash160bit = typeforce.BufferN(20); exports.Hash160bit = typeforce.BufferN(20);

2
types/index.d.ts vendored
View file

@ -5,7 +5,7 @@ import * as crypto from './crypto';
import * as networks from './networks'; import * as networks from './networks';
import * as payments from './payments'; import * as payments from './payments';
import * as script from './script'; 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 { Block } from './block';
export { Transaction } from './transaction'; export { Transaction } from './transaction';
export { TransactionBuilder } from './transaction_builder'; export { TransactionBuilder } from './transaction_builder';