Daniel Cousens
7 years ago
18 changed files with 2696 additions and 2 deletions
@ -0,0 +1,19 @@ |
|||||
|
const p2ms = require('./p2ms') |
||||
|
const p2pk = require('./p2pk') |
||||
|
const p2pkh = require('./p2pkh') |
||||
|
const p2sh = require('./p2sh') |
||||
|
const p2wpkh = require('./p2wpkh') |
||||
|
const p2wsh = require('./p2wsh') |
||||
|
|
||||
|
module.exports = { |
||||
|
p2ms: p2ms, |
||||
|
p2pk: p2pk, |
||||
|
p2pkh: p2pkh, |
||||
|
p2sh: p2sh, |
||||
|
p2wpkh: p2wpkh, |
||||
|
p2wsh: p2wsh |
||||
|
} |
||||
|
|
||||
|
// TODO
|
||||
|
// OP_RETURN
|
||||
|
// witness commitment
|
@ -0,0 +1,30 @@ |
|||||
|
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 |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function value (f) { |
||||
|
let value |
||||
|
return function () { |
||||
|
if (value !== undefined) return value |
||||
|
value = f() |
||||
|
return value |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { prop, value } |
@ -0,0 +1,140 @@ |
|||||
|
let lazy = require('./lazy') |
||||
|
let typef = require('typeforce') |
||||
|
let OPS = require('bitcoin-ops') |
||||
|
let ecc = require('tiny-secp256k1') |
||||
|
|
||||
|
let bscript = require('../script') |
||||
|
let BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
let 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.output && |
||||
|
!(a.pubkeys && a.m !== undefined) |
||||
|
) throw new TypeError('Not enough data') |
||||
|
opts = opts || { validate: true } |
||||
|
|
||||
|
function isAcceptableSignature (x) { |
||||
|
return bscript.isCanonicalScriptSignature(x) || (opts.allowIncomplete && (x === OPS.OP_0)) |
||||
|
} |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
let network = a.network || BITCOIN_NETWORK |
||||
|
let o = { network } |
||||
|
|
||||
|
let chunks |
||||
|
let decoded = false |
||||
|
function decode (output) { |
||||
|
if (decoded) return |
||||
|
decoded = true |
||||
|
chunks = bscript.decompile(output) |
||||
|
let om = chunks[0] - OP_INT_BASE |
||||
|
let on = chunks[chunks.length - 2] - OP_INT_BASE |
||||
|
o.m = om |
||||
|
o.n = on |
||||
|
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 || |
||||
|
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.equals(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 |
@ -0,0 +1,80 @@ |
|||||
|
let lazy = require('./lazy') |
||||
|
let typef = require('typeforce') |
||||
|
let OPS = require('bitcoin-ops') |
||||
|
let ecc = require('tiny-secp256k1') |
||||
|
|
||||
|
let bscript = require('../script') |
||||
|
let BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
|
||||
|
// input: {signature}
|
||||
|
// output: {pubKey} OP_CHECKSIG
|
||||
|
function p2pk (a, opts) { |
||||
|
if ( |
||||
|
!a.output && |
||||
|
!a.pubkey |
||||
|
) throw new TypeError('Not enough data') |
||||
|
opts = opts || { validate: true } |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
let _chunks = lazy.value(function () { return bscript.decompile(a.input) }) |
||||
|
|
||||
|
let network = a.network || BITCOIN_NETWORK |
||||
|
let 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.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.signature) { |
||||
|
if (a.input && !a.input.equals(o.input)) throw new TypeError('Input mismatch') |
||||
|
} |
||||
|
|
||||
|
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') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Object.assign(o, a) |
||||
|
} |
||||
|
|
||||
|
module.exports = p2pk |
@ -0,0 +1,127 @@ |
|||||
|
let lazy = require('./lazy') |
||||
|
let typef = require('typeforce') |
||||
|
let OPS = require('bitcoin-ops') |
||||
|
let ecc = require('tiny-secp256k1') |
||||
|
|
||||
|
let baddress = require('../address') |
||||
|
let bcrypto = require('../crypto') |
||||
|
let bscript = require('../script') |
||||
|
let BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
|
||||
|
// 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 = opts || { validate: true } |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
let _address = lazy.value(function () { return baddress.fromBase58Check(a.address) }) |
||||
|
let _chunks = lazy.value(function () { return bscript.decompile(a.input) }) |
||||
|
|
||||
|
let network = a.network || BITCOIN_NETWORK |
||||
|
let o = { network } |
||||
|
|
||||
|
lazy.prop(o, 'address', function () { |
||||
|
if (!o.hash) return |
||||
|
return baddress.toBase58Check(o.hash, network.pubKeyHash) |
||||
|
}) |
||||
|
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 [] |
||||
|
}) |
||||
|
|
||||
|
// extended validation
|
||||
|
if (opts.validate) { |
||||
|
let hash |
||||
|
if (a.address) { |
||||
|
if (_address().version !== network.pubKeyHash) throw new TypeError('Network mismatch') |
||||
|
if (_address().hash.length !== 20) throw new TypeError('Invalid address') |
||||
|
else hash = _address().hash |
||||
|
} |
||||
|
|
||||
|
if (a.hash) { |
||||
|
if (hash && !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') |
||||
|
|
||||
|
if (hash && !hash.equals(a.output.slice(3, 23))) throw new TypeError('Hash mismatch') |
||||
|
else hash = a.output.slice(3, 23) |
||||
|
} |
||||
|
|
||||
|
if (a.pubkey) { |
||||
|
let pkh = bcrypto.hash160(a.pubkey) |
||||
|
if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') |
||||
|
else hash = pkh |
||||
|
} |
||||
|
|
||||
|
if (a.input) { |
||||
|
let 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') |
||||
|
|
||||
|
let pkh = bcrypto.hash160(chunks[1]) |
||||
|
if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Object.assign(o, a) |
||||
|
} |
||||
|
|
||||
|
module.exports = p2pkh |
@ -0,0 +1,176 @@ |
|||||
|
const lazy = require('./lazy') |
||||
|
const typef = require('typeforce') |
||||
|
const OPS = require('bitcoin-ops') |
||||
|
|
||||
|
const baddress = require('../address') |
||||
|
const bcrypto = require('../crypto') |
||||
|
const bscript = require('../script') |
||||
|
const BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
|
||||
|
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 = opts || { validate: true } |
||||
|
|
||||
|
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.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) |
||||
|
|
||||
|
const network = a.network || BITCOIN_NETWORK |
||||
|
const o = { network } |
||||
|
|
||||
|
const _address = lazy.value(function () { return baddress.fromBase58Check(a.address) }) |
||||
|
const _chunks = lazy.value(function () { return bscript.decompile(a.input) }) |
||||
|
const _redeem = lazy.value(function () { |
||||
|
const chunks = _chunks() |
||||
|
return { |
||||
|
network: 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 |
||||
|
return baddress.toBase58Check(o.hash, network.scriptHash) |
||||
|
}) |
||||
|
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) 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 |
||||
|
if (a.address) { |
||||
|
if (_address().version !== network.scriptHash) throw new TypeError('Network mismatch') |
||||
|
if (_address().hash.length !== 20) throw new TypeError('Invalid address') |
||||
|
else hash = _address().hash |
||||
|
} |
||||
|
|
||||
|
if (a.hash) { |
||||
|
if (hash && !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 && !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?
|
||||
|
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 && !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 (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') |
||||
|
} |
||||
|
|
||||
|
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) |
||||
|
} |
||||
|
|
||||
|
module.exports = p2sh |
@ -0,0 +1,124 @@ |
|||||
|
let lazy = require('./lazy') |
||||
|
let typef = require('typeforce') |
||||
|
let OPS = require('bitcoin-ops') |
||||
|
let ecc = require('tiny-secp256k1') |
||||
|
|
||||
|
let baddress = require('../address') |
||||
|
let bcrypto = require('../crypto') |
||||
|
let bscript = require('../script') |
||||
|
let BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
|
||||
|
let 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 = opts || { validate: true } |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
let _address = lazy.value(function () { return baddress.fromBech32(a.address) }) |
||||
|
|
||||
|
let network = a.network || BITCOIN_NETWORK |
||||
|
let o = { network } |
||||
|
|
||||
|
lazy.prop(o, 'address', function () { |
||||
|
if (!o.hash) return |
||||
|
return baddress.toBech32(o.hash, 0x00, network.bech32) |
||||
|
}) |
||||
|
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 |
||||
|
if (a.address) { |
||||
|
if (network && network.bech32 !== _address().prefix) throw new TypeError('Network mismatch') |
||||
|
if (_address().version !== 0x00) throw new TypeError('Invalid version') |
||||
|
if (_address().data.length !== 20) throw new TypeError('Invalid data') |
||||
|
if (hash && !hash.equals(_address().data)) throw new TypeError('Hash mismatch') |
||||
|
else hash = _address().data |
||||
|
} |
||||
|
|
||||
|
if (a.pubkey) { |
||||
|
let pkh = bcrypto.hash160(a.pubkey) |
||||
|
if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') |
||||
|
else hash = pkh |
||||
|
} |
||||
|
|
||||
|
if (a.hash) { |
||||
|
if (hash && !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 && !hash.equals(a.output.slice(2))) throw new TypeError('Hash mismatch') |
||||
|
else hash = a.output.slice(2) |
||||
|
} |
||||
|
|
||||
|
if (a.witness) { |
||||
|
if (a.witness.length !== 2) throw new TypeError('Input is invalid') |
||||
|
if (!bscript.isCanonicalScriptSignature(a.witness[0])) throw new TypeError('Input has invalid signature') |
||||
|
if (!ecc.isPoint(a.witness[1])) throw new TypeError('Input 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') |
||||
|
|
||||
|
let pkh = bcrypto.hash160(a.witness[1]) |
||||
|
if (hash && !hash.equals(pkh)) throw new TypeError('Hash mismatch') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Object.assign(o, a) |
||||
|
} |
||||
|
|
||||
|
module.exports = p2wpkh |
@ -0,0 +1,154 @@ |
|||||
|
let lazy = require('./lazy') |
||||
|
let typef = require('typeforce') |
||||
|
let OPS = require('bitcoin-ops') |
||||
|
|
||||
|
let baddress = require('../address') |
||||
|
let bcrypto = require('../crypto') |
||||
|
let bscript = require('../script') |
||||
|
let BITCOIN_NETWORK = require('../networks').bitcoin |
||||
|
|
||||
|
let 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 = opts || { validate: true } |
||||
|
|
||||
|
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.Buffer, |
||||
|
witness: typef.maybe(typef.arrayOf(typef.Buffer)) |
||||
|
}), |
||||
|
input: typef.maybe(typef.BufferN(0)), |
||||
|
witness: typef.maybe(typef.arrayOf(typef.Buffer)) |
||||
|
}, a) |
||||
|
|
||||
|
let _address = lazy.value(function () { return baddress.fromBech32(a.address) }) |
||||
|
let _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input) }) |
||||
|
|
||||
|
let network = a.network || BITCOIN_NETWORK |
||||
|
let o = { network } |
||||
|
|
||||
|
lazy.prop(o, 'address', function () { |
||||
|
if (!o.hash) return |
||||
|
return baddress.toBech32(o.hash, 0x00, network.bech32) |
||||
|
}) |
||||
|
lazy.prop(o, 'hash', function () { |
||||
|
if (a.output) return a.output.slice(2) |
||||
|
if (a.address) return baddress.fromBech32(a.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) { |
||||
|
let 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.witness) return |
||||
|
return [].concat(a.redeem.witness, a.redeem.output) |
||||
|
}) |
||||
|
|
||||
|
// extended validation
|
||||
|
if (opts.validate) { |
||||
|
let hash |
||||
|
if (a.address) { |
||||
|
if (_address().prefix !== network.bech32) throw new TypeError('Network mismatch') |
||||
|
if (_address().version !== 0x00) throw new TypeError('Invalid version') |
||||
|
if (_address().data.length !== 32) throw new TypeError('Invalid data') |
||||
|
else hash = _address().data |
||||
|
} |
||||
|
|
||||
|
if (a.hash) { |
||||
|
if (hash && !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') |
||||
|
let hash2 = a.output.slice(2) |
||||
|
if (hash && !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) throw new TypeError('Ambiguous witness source') |
||||
|
|
||||
|
// is the redeem output non-empty?
|
||||
|
if (bscript.decompile(a.redeem.output).length === 0) throw new TypeError('Redeem.output is invalid') |
||||
|
|
||||
|
// match hash against other sources
|
||||
|
let hash2 = bcrypto.sha256(a.redeem.output) |
||||
|
if (hash && !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.equals(a.witness[a.witness.length - 1])) throw new TypeError('Witness and redeem.output mismatch') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Object.assign(o, a) |
||||
|
} |
||||
|
|
||||
|
module.exports = p2wsh |
@ -0,0 +1,40 @@ |
|||||
|
{ |
||||
|
"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" |
||||
|
} |
||||
|
} |
@ -0,0 +1,378 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "output from output", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 2, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
], |
||||
|
"signatures": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from m/pubkeys", |
||||
|
"arguments": { |
||||
|
"m": 1, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 1, |
||||
|
"n": 2, |
||||
|
"output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
], |
||||
|
"signatures": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from m/pubkeys/signatures", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000003" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 3, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000003" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 300602010002010001 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from output/signatures", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 3, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000003" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 300602010002010001 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from input/output", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"input": "OP_0 300602010002010001 300602010102010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 3, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000003" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 300602010002010001 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from input/output, even if incomplete", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"input": "OP_0 OP_0 300602010102010001" |
||||
|
}, |
||||
|
"options": { |
||||
|
"allowIncomplete": true |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 2, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
0, |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 OP_0 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from output/signatures, even if incomplete", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"signatures": [ |
||||
|
0, |
||||
|
"300602010102010001" |
||||
|
] |
||||
|
}, |
||||
|
"options": { |
||||
|
"allowIncomplete": true |
||||
|
}, |
||||
|
"expected": { |
||||
|
"m": 2, |
||||
|
"n": 2, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
0, |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 OP_0 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"m": 2 |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non OP_INT chunk (m)", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non OP_INT chunk (n)", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_1 OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Missing OP_CHECKMULTISIG", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_1 OP_2 OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "m is 0", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_0 OP_2 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "n is 0 (m > n)", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_2 OP_0 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "m > n", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_3 OP_2 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "n !== output pubkeys", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_2 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non-canonical output public key", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_1 ffff OP_1 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "n mismatch", |
||||
|
"arguments": { |
||||
|
"n": 2, |
||||
|
"output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_1 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "m mismatch", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_1 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkeys mismatch", |
||||
|
"arguments": { |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
], |
||||
|
"output": "OP_1 030000000000000000000000000000000000000000000000000000000000000002 OP_1 OP_CHECKMULTISIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkey count mismatch", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"n": 3, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkey count cannot be less than m", |
||||
|
"arguments": { |
||||
|
"m": 4, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough signatures provided", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Too many signatures provided", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010002010001", |
||||
|
"300602010002010001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Missing OP_0", |
||||
|
"exception": "Input is invalid", |
||||
|
"arguments": { |
||||
|
"m": 2, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
], |
||||
|
"input": "OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid signature\\(s\\)", |
||||
|
"arguments": { |
||||
|
"m": 1, |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
], |
||||
|
"input": "OP_0 ffffffffffffffff" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"m": [ "output" ], |
||||
|
"n": [ "output", [ "m", "pubkeys" ] ], |
||||
|
"output": [ "output", [ "m", "pubkeys" ] ], |
||||
|
"pubkeys": [ "output" ], |
||||
|
"signatures": [ ["input", "output"] ], |
||||
|
"input": [ ["signatures", "output"] ], |
||||
|
"witness": [ ["input", "output"] ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2ms", |
||||
|
"m": 2, |
||||
|
"n": 3, |
||||
|
"output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG", |
||||
|
"pubkeys": [ |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000003" |
||||
|
], |
||||
|
"signatures": [ |
||||
|
"300602010002010001", |
||||
|
"300602010102010001" |
||||
|
], |
||||
|
"input": "OP_0 300602010002010001 300602010102010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "output from output", |
||||
|
"arguments": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signatures": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from pubkey", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", |
||||
|
"signatures": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from output/signature", |
||||
|
"arguments": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", |
||||
|
"signature": "300602010002010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"input": "300602010002010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from pubkey/signature", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", |
||||
|
"input": "300602010002010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from input/output", |
||||
|
"arguments": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", |
||||
|
"input": "300602010002010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"input": "300602010002010001" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"signature": "300602010002010001" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non-canonical signature", |
||||
|
"exception": "Expected property \"signature\" of type \\?isCanonicalScriptSignature, got Buffer", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "3044" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Unexpected OP_RESERVED", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non-canonical output public key", |
||||
|
"exception": "Output pubkey is invalid", |
||||
|
"arguments": { |
||||
|
"output": "ffff OP_CHECKSIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Unexpected OP_0 (at end)", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG OP_0" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkey mismatch", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000002 OP_CHECKSIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Too many chunks", |
||||
|
"exception": "Input is invalid", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"input": "300602010002010001 OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid signature", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"input": "ffffffffffffffff" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"output": [ "pubkey" ], |
||||
|
"pubkey": [ "output" ], |
||||
|
"signature": [ ["input", "output"] ], |
||||
|
"input": [ ["signature", "output"] ], |
||||
|
"witness": [ ["input", "output"] ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2pk", |
||||
|
"output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG", |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"input": "300602010002010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,214 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "output from address", |
||||
|
"arguments": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from hash", |
||||
|
"arguments": { |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from output", |
||||
|
"arguments": { |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from pubkey", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from pubkey/signature", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "input/output from input", |
||||
|
"arguments": { |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"signature": "300602010002010001" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Unexpected OP_RESERVED", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Unexpected OP_DUP", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_DUP OP_DUP 168b992bcfc44050310b3a94bd0771136d0b28d137 OP_EQUALVERIFY" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Hash too short (too many chunks)", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_DUP OP_DUP 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_TRUE OP_EQUALVERIFY" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non-minimally encoded (non BIP62 compliant)", |
||||
|
"exception": "Expected property \"output\" of type Buffer\\(Length: 25\\), got Buffer\\(Length: 26\\)", |
||||
|
"arguments": { |
||||
|
"outputHex": "76a94c14aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkey mismatch", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid signature", |
||||
|
"arguments": { |
||||
|
"input": "ffffffffffffffffff 030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid pubkey", |
||||
|
"arguments": { |
||||
|
"input": "300602010002010001 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Input has unexpected data", |
||||
|
"exception": "Input is invalid", |
||||
|
"arguments": { |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001 ffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "H(pubkey) != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != output.hash", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"output": "OP_DUP OP_HASH160 ffffffffffffffffffffffffffffffffffffffff OP_EQUALVERIFY OP_CHECKSIG" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "H(input.pubkey) != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff", |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"address": [ "address", "output", "hash", "pubkey", "input" ], |
||||
|
"hash": [ "address", "output", "hash", "pubkey", "input" ], |
||||
|
"output": [ "address", "output", "hash", "pubkey", "input" ], |
||||
|
"pubkey": [ "input" ], |
||||
|
"signature": [ "input" ], |
||||
|
"input": [ [ "pubkey", "signature" ] ], |
||||
|
"witness": [ "input" ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2pkh", |
||||
|
"address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"witness": [] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,346 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "p2sh-*, out (from address)", |
||||
|
"arguments": { |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-*, out (from hash)", |
||||
|
"arguments": { |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT", |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-*, out (from output)", |
||||
|
"arguments": { |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT", |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2pkh, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"address": "this is P2PKH context, unknown and ignored by P2SH", |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT", |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2wpkh, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"hash": "this is P2WPKH context, unknown and ignored by P2SH", |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc", |
||||
|
"output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2pk, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG", |
||||
|
"pubkey": "this is P2WPKH context, unknown and ignored by P2SH" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "36TibC8RrPB9WrBdPoGXhHqDHJosyFVtVQ", |
||||
|
"hash": "3454c084887afe854e80221c69d6282926f809c4", |
||||
|
"output": "OP_HASH160 3454c084887afe854e80221c69d6282926f809c4 OP_EQUAL", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2pkh, in and out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT", |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac", |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2wpkh, in and out (from redeem w/ witness)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc", |
||||
|
"output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL", |
||||
|
"input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2pk, in and out (from input)", |
||||
|
"arguments": { |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 2103e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058ac" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "36TibC8RrPB9WrBdPoGXhHqDHJosyFVtVQ", |
||||
|
"hash": "3454c084887afe854e80221c69d6282926f809c4", |
||||
|
"output": "OP_HASH160 3454c084887afe854e80221c69d6282926f809c4 OP_EQUAL", |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"witness": [] |
||||
|
}, |
||||
|
"witness": [] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2wpkh, in and out (from input AND witness)", |
||||
|
"arguments": { |
||||
|
"input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc", |
||||
|
"output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL", |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Non-minimally encoded (non BIP62 compliant)", |
||||
|
"exception": "Expected property \"output\" of type Buffer\\(Length: 23\\), got Buffer\\(Length: 24\\)", |
||||
|
"arguments": { |
||||
|
"outputHex": "a94c14c286a1af0947f58d1ad787385b1c2c4a976f9e7187" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Expected OP_HASH160", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "Unexpected OP_RESERVED", |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffff OP_EQUAL OP_RESERVED" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != output.hash", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"output": "OP_HASH160 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff", |
||||
|
"output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "H(redeem.output) != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff", |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input too short", |
||||
|
"arguments": { |
||||
|
"input": "" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input too short", |
||||
|
"arguments": { |
||||
|
"inputHex": "01ff02ff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input is invalid", |
||||
|
"arguments": { |
||||
|
"input": "OP_0 OP_0" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Redeem.input mismatch", |
||||
|
"arguments": { |
||||
|
"input": "OP_0 02ffff", |
||||
|
"redeem": { |
||||
|
"input": "OP_CHECKSIG", |
||||
|
"output": "ffff" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Redeem.output mismatch", |
||||
|
"arguments": { |
||||
|
"input": "OP_0 02ffff", |
||||
|
"redeem": { |
||||
|
"input": "OP_0", |
||||
|
"output": "fff3" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Redeem.output too short", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"input": "OP_0", |
||||
|
"output": "" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Redeem.output too short", |
||||
|
"arguments": { |
||||
|
"inputHex": "021000" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff", |
||||
|
"redeem": { |
||||
|
"input": "OP_0", |
||||
|
"output": "ffff" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Empty input", |
||||
|
"arguments": { |
||||
|
"inputHex": "01ff" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"address": [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ], |
||||
|
"hash": [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ], |
||||
|
"output": [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ], |
||||
|
"redeem.output": [ [ "input", "witness" ] ], |
||||
|
"redeem.input": [ [ "input", "witness" ] ], |
||||
|
"redeem.witness": [ [ "input", "witness" ] ], |
||||
|
"input": [ "redeem" ], |
||||
|
"witness": [ "redeem" ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2sh-p2pkh", |
||||
|
"address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT", |
||||
|
"hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086", |
||||
|
"output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL", |
||||
|
"redeem": { |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"witness": [] |
||||
|
}, |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac", |
||||
|
"witness": [] |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2sh-p2wpkh", |
||||
|
"address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu", |
||||
|
"hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc", |
||||
|
"output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL", |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
}, |
||||
|
"input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,195 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "output from address", |
||||
|
"arguments": { |
||||
|
"address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727", |
||||
|
"output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from hash", |
||||
|
"arguments": { |
||||
|
"hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d", |
||||
|
"output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from output", |
||||
|
"arguments": { |
||||
|
"output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d", |
||||
|
"hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output from pubkey", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"signature": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "witness/output from pubkey/signature", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "witness/output from witness", |
||||
|
"arguments": { |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"input": "" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": { |
||||
|
"signature": "300602010002010001" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Output is invalid", |
||||
|
"description": "Unexpected OP", |
||||
|
"arguments": { |
||||
|
"output": "OP_RESERVED ea6d525c0c955d90d3dbd29a81ef8bfb79003727" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Pubkey mismatch", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000002" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffff", |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid signature", |
||||
|
"arguments": { |
||||
|
"witness": [ |
||||
|
"ffffffffffffffffff", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Input has invalid pubkey", |
||||
|
"arguments": { |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"address": [ "address", "output", "hash", "pubkey", "witness" ], |
||||
|
"hash": [ "address", "output", "hash", "pubkey", "witness" ], |
||||
|
"output": [ "address", "output", "hash", "pubkey", "witness" ], |
||||
|
"pubkey": [ "witness" ], |
||||
|
"signature": [ "witness" ], |
||||
|
"input": [ "witness" ], |
||||
|
"witness": [ [ "pubkey", "signature" ] ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2wpkh", |
||||
|
"address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm", |
||||
|
"hash": "168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1", |
||||
|
"pubkey": "030000000000000000000000000000000000000000000000000000000000000001", |
||||
|
"signature": "300602010002010001", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"300602010002010001", |
||||
|
"030000000000000000000000000000000000000000000000000000000000000001" |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,326 @@ |
|||||
|
{ |
||||
|
"valid": [ |
||||
|
{ |
||||
|
"description": "p2wsh-*, out (from address)", |
||||
|
"arguments": { |
||||
|
"address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-*, out (from hash)", |
||||
|
"arguments": { |
||||
|
"hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q", |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-*, out (from output)", |
||||
|
"arguments": { |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0" |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q", |
||||
|
"hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"redeem": null, |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2pkh, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"address": "this is P2PKH context, unknown and ignored by p2wsh", |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar", |
||||
|
"hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2wpkh, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"hash": "this is P2WPKH context, unknown and ignored by p2wsh", |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2pk, out (from redeem)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG", |
||||
|
"pubkey": "this is P2WPKH context, unknown and ignored by p2wsh" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q", |
||||
|
"hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"input": null, |
||||
|
"witness": null |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2pkh, in and out (from redeem, transformed to witness)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar", |
||||
|
"hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"redeem": { |
||||
|
"input": "" |
||||
|
}, |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2wpkh, in and out (from redeem w/ witness)", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"0014c30afa58ae0673b00a45b5c17dff4633780f1400" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2pk, in and out (from witness)", |
||||
|
"arguments": { |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"2103e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058ac" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q", |
||||
|
"hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0", |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501" |
||||
|
] |
||||
|
}, |
||||
|
"input": "" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2wpkh, in and out (from witness)", |
||||
|
"arguments": { |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"0014c30afa58ae0673b00a45b5c17dff4633780f1400" |
||||
|
] |
||||
|
}, |
||||
|
"expected": { |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"invalid": [ |
||||
|
{ |
||||
|
"exception": "Not enough data", |
||||
|
"arguments": {} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "address.hash != output.hash", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"output": "OP_0 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "output.hash != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", |
||||
|
"output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"description": "H(redeem.output) != H", |
||||
|
"exception": "Hash mismatch", |
||||
|
"arguments": { |
||||
|
"hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", |
||||
|
"redeem": { |
||||
|
"output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Output is invalid", |
||||
|
"arguments": { |
||||
|
"output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff OP_EQUAL" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Redeem.output is invalid", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Non push-only scriptSig", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_TRUE", |
||||
|
"input": "OP_HASH256" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Witness and redeem.output mismatch", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_TRUE", |
||||
|
"input": "OP_0" |
||||
|
}, |
||||
|
"witness": [ |
||||
|
"02ffff" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"exception": "Witness and redeem.witness mismatch", |
||||
|
"arguments": { |
||||
|
"redeem": { |
||||
|
"output": "OP_TRUE", |
||||
|
"witness": [ |
||||
|
"01" |
||||
|
] |
||||
|
}, |
||||
|
"witness": [ |
||||
|
"00", |
||||
|
"02ffff" |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"dynamic": { |
||||
|
"depends": { |
||||
|
"address": [ "address", "output", "hash", "redeem.output", "witness" ], |
||||
|
"hash": [ "address", "output", "hash", "redeem.output", "witness" ], |
||||
|
"output": [ "address", "output", "hash", "redeem.output", "witness" ], |
||||
|
"redeem.output": [ "witness" ], |
||||
|
"redeem.input": [ [ "input", "witness" ], "witness" ], |
||||
|
"input": [ "witness" ], |
||||
|
"witness": [ "redeem" ] |
||||
|
}, |
||||
|
"details": [ |
||||
|
{ |
||||
|
"description": "p2wsh-p2pkh", |
||||
|
"disabled": [ |
||||
|
"redeem.input" |
||||
|
], |
||||
|
"address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar", |
||||
|
"hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1", |
||||
|
"redeem": { |
||||
|
"output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG", |
||||
|
"input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"witness": null |
||||
|
}, |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac" |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"description": "p2wsh-p2wpkh", |
||||
|
"address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e", |
||||
|
"hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d", |
||||
|
"redeem": { |
||||
|
"output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400", |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058" |
||||
|
] |
||||
|
}, |
||||
|
"input": "", |
||||
|
"witness": [ |
||||
|
"3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501", |
||||
|
"03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058", |
||||
|
"0014c30afa58ae0673b00a45b5c17dff4633780f1400" |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
/* global describe, it */ |
||||
|
|
||||
|
const assert = require('assert') |
||||
|
const u = require('./payments.utils') |
||||
|
|
||||
|
;['p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(function (p) { |
||||
|
describe(p, function () { |
||||
|
const fn = require('../src/payments/' + p) |
||||
|
const fixtures = require('./fixtures/' + p) |
||||
|
|
||||
|
fixtures.valid.forEach(function (f, i) { |
||||
|
const args = u.preform(f.arguments) |
||||
|
|
||||
|
it(f.description + ' as expected', function () { |
||||
|
const actual = fn(args, f.options) |
||||
|
u.equate(actual, f.expected, f.arguments) |
||||
|
}) |
||||
|
|
||||
|
it(f.description + ' as expected (no validation)', function () { |
||||
|
const actual = fn(args, Object.assign({}, f.options, { |
||||
|
validate: false |
||||
|
})) |
||||
|
|
||||
|
u.equate(actual, f.expected, f.arguments) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
fixtures.invalid.forEach(function (f) { |
||||
|
it('throws ' + (f.description || f.exception), function () { |
||||
|
const args = u.preform(f.arguments) |
||||
|
|
||||
|
assert.throws(function () { |
||||
|
fn(args, f.options) |
||||
|
}, new RegExp(f.exception)) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
// cross-verify dynamically too
|
||||
|
if (!fixtures.dynamic) return |
||||
|
const { depends, details } = fixtures.dynamic |
||||
|
|
||||
|
details.forEach(function (f) { |
||||
|
const detail = u.preform(f) |
||||
|
const disabled = {} |
||||
|
if (f.disabled) f.disabled.forEach(function (k) { disabled[k] = true }) |
||||
|
|
||||
|
for (let key in depends) { |
||||
|
if (key in disabled) continue |
||||
|
const dependencies = depends[key] |
||||
|
|
||||
|
dependencies.forEach(function (dependency) { |
||||
|
if (!Array.isArray(dependency)) dependency = [dependency] |
||||
|
|
||||
|
const args = {} |
||||
|
dependency.forEach(function (d) { u.from(d, detail, args) }) |
||||
|
const expected = u.from(key, detail) |
||||
|
|
||||
|
it(f.description + ', ' + key + ' derives from ' + JSON.stringify(dependency), function () { |
||||
|
u.equate(fn(args), expected) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,128 @@ |
|||||
|
let t = require('assert') |
||||
|
let bscript = require('../src/script') |
||||
|
let bnetworks = require('../src/networks') |
||||
|
|
||||
|
function tryHex (x) { |
||||
|
if (Buffer.isBuffer(x)) return x.toString('hex') |
||||
|
if (Array.isArray(x)) return x.map(tryHex) |
||||
|
return x |
||||
|
} |
||||
|
function tryASM (x) { |
||||
|
if (Buffer.isBuffer(x)) return bscript.toASM(x) |
||||
|
return x |
||||
|
} |
||||
|
function asmToBuffer (x) { |
||||
|
if (x === '') return Buffer.alloc(0) |
||||
|
return bscript.fromASM(x) |
||||
|
} |
||||
|
function carryOver (a, b) { |
||||
|
for (let k in b) { |
||||
|
if (k in a && k === 'redeem') { |
||||
|
carryOver(a[k], b[k]) |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// don't, the value was specified
|
||||
|
if (k in a) continue |
||||
|
|
||||
|
// otherwise, expect match
|
||||
|
a[k] = b[k] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
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`) |
||||
|
} |
||||
|
|
||||
|
function equate (a, b, args) { |
||||
|
b = Object.assign({}, b) |
||||
|
carryOver(b, args) |
||||
|
|
||||
|
// by null, we mean 'undefined', but JSON
|
||||
|
if (b.input === null) b.input = undefined |
||||
|
if (b.output === null) b.output = undefined |
||||
|
if (b.witness === null) b.witness = undefined |
||||
|
if (b.redeem) { |
||||
|
if (b.redeem.input === null) b.redeem.input = undefined |
||||
|
if (b.redeem.output === null) b.redeem.output = undefined |
||||
|
if (b.redeem.witness === null) b.redeem.witness = undefined |
||||
|
} |
||||
|
|
||||
|
equateBase(a, b, '') |
||||
|
if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.') |
||||
|
if (b.network) t.deepEqual(a.network, b.network, 'Inequal *.network') |
||||
|
|
||||
|
// contextual
|
||||
|
if (b.signature === null) b.signature = 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') |
||||
|
} |
||||
|
|
||||
|
function preform (x) { |
||||
|
x = Object.assign({}, x) |
||||
|
|
||||
|
if (x.network) x.network = bnetworks[x.network] |
||||
|
if (typeof x.inputHex === 'string') { |
||||
|
x.input = Buffer.from(x.inputHex, 'hex') |
||||
|
delete x.inputHex |
||||
|
} |
||||
|
if (typeof x.outputHex === 'string') { |
||||
|
x.output = Buffer.from(x.outputHex, 'hex') |
||||
|
delete x.outputHex |
||||
|
} |
||||
|
if (typeof x.output === 'string') x.output = asmToBuffer(x.output) |
||||
|
if (typeof x.input === 'string') x.input = asmToBuffer(x.input) |
||||
|
if (Array.isArray(x.witness)) { |
||||
|
x.witness = x.witness.map(function (y) { |
||||
|
return Buffer.from(y, 'hex') |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
if (x.hash) x.hash = Buffer.from(x.hash, 'hex') |
||||
|
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(function (y) { return Buffer.from(y, 'hex') }) |
||||
|
if (x.signatures) x.signatures = x.signatures.map(function (y) { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') }) |
||||
|
if (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(function (y) { return Buffer.from(y, 'hex') }) |
||||
|
x.redeem.network = bnetworks[x.redeem.network] || x.network || bnetworks.bitcoin |
||||
|
} |
||||
|
|
||||
|
return x |
||||
|
} |
||||
|
|
||||
|
function from (path, object, result) { |
||||
|
path = path.split('.') |
||||
|
result = result || {} |
||||
|
|
||||
|
let r = result |
||||
|
path.forEach((k, i) => { |
||||
|
if (i < path.length - 1) { |
||||
|
r[k] = r[k] || {} |
||||
|
|
||||
|
// recurse
|
||||
|
r = r[k] |
||||
|
object = object[k] |
||||
|
} else { |
||||
|
r[k] = object[k] |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
return result |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
from, |
||||
|
equate, |
||||
|
preform |
||||
|
} |
Loading…
Reference in new issue