Browse Source

Merge pull request #1201 from bitcoinjs/p2msmore

tests: add extra P2MS testing fixtures
v4
junderw 6 years ago
parent
commit
b4bab427f8
No known key found for this signature in database GPG Key ID: B256185D3A971908
  1. 6
      src/classify.js
  2. 36
      src/transaction_builder.js
  3. 23
      test/fixtures/transaction_builder.json

6
src/classify.js

@ -9,7 +9,7 @@ const witnessScriptHash = require('./templates/witnessscripthash')
const witnessCommitment = require('./templates/witnesscommitment') const witnessCommitment = require('./templates/witnesscommitment')
const types = { const types = {
MULTISIG: 'multisig', P2MS: 'multisig',
NONSTANDARD: 'nonstandard', NONSTANDARD: 'nonstandard',
NULLDATA: 'nulldata', NULLDATA: 'nulldata',
P2PK: 'pubkey', P2PK: 'pubkey',
@ -30,7 +30,7 @@ function classifyOutput (script) {
const chunks = decompile(script) const chunks = decompile(script)
if (!chunks) throw new TypeError('Invalid script') if (!chunks) throw new TypeError('Invalid script')
if (multisig.output.check(chunks)) return types.MULTISIG if (multisig.output.check(chunks)) return types.P2MS
if (pubKey.output.check(chunks)) return types.P2PK if (pubKey.output.check(chunks)) return types.P2PK
if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT
if (nullData.output.check(chunks)) return types.NULLDATA if (nullData.output.check(chunks)) return types.NULLDATA
@ -45,7 +45,7 @@ function classifyInput (script, allowIncomplete) {
if (pubKeyHash.input.check(chunks)) return types.P2PKH if (pubKeyHash.input.check(chunks)) return types.P2PKH
if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH
if (multisig.input.check(chunks, allowIncomplete)) return types.MULTISIG if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS
if (pubKey.input.check(chunks)) return types.P2PK if (pubKey.input.check(chunks)) return types.P2PK
return types.NONSTANDARD return types.NONSTANDARD

36
src/transaction_builder.js

@ -56,16 +56,17 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) {
} }
} }
case SCRIPT_TYPES.MULTISIG: { case SCRIPT_TYPES.P2MS: {
const { pubkeys, signatures } = payments.p2ms({ const { m, pubkeys, signatures } = payments.p2ms({
input: scriptSig, input: scriptSig,
output: scriptPubKey output: scriptPubKey
}, { allowIncomplete: true }) }, { allowIncomplete: true })
return { return {
prevOutType: SCRIPT_TYPES.MULTISIG, prevOutType: SCRIPT_TYPES.P2MS,
pubkeys: pubkeys, pubkeys: pubkeys,
signatures: signatures signatures: signatures,
maxSignatures: m
} }
} }
} }
@ -126,7 +127,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) {
// could be done in expandInput, but requires the original Transaction for hashForSignature // could be done in expandInput, but requires the original Transaction for hashForSignature
function fixMultisigOrder (input, transaction, vin) { function fixMultisigOrder (input, transaction, vin) {
if (input.redeemScriptType !== SCRIPT_TYPES.MULTISIG || !input.redeemScript) return if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return
if (input.pubkeys.length === input.signatures.length) return if (input.pubkeys.length === input.signatures.length) return
const unmatched = input.signatures.concat() const unmatched = input.signatures.concat()
@ -202,12 +203,13 @@ function expandOutput (script, ourPubKey) {
} }
} }
case SCRIPT_TYPES.MULTISIG: { case SCRIPT_TYPES.P2MS: {
const p2ms = payments.p2ms({ output: script }) const p2ms = payments.p2ms({ output: script })
return { return {
type, type,
pubkeys: p2ms.pubkeys, pubkeys: p2ms.pubkeys,
signatures: p2ms.pubkeys.map(() => undefined) signatures: p2ms.pubkeys.map(() => undefined),
maxSignatures: p2ms.m
} }
} }
} }
@ -250,7 +252,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures
} }
} }
@ -288,7 +291,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures
} }
} }
@ -321,7 +325,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures
} }
} }
@ -351,7 +356,8 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
signType: expanded.type, signType: expanded.type,
pubkeys: expanded.pubkeys, pubkeys: expanded.pubkeys,
signatures: expanded.signatures signatures: expanded.signatures,
maxSignatures: expanded.maxSignatures
} }
} }
@ -392,14 +398,18 @@ function build (type, input, allowIncomplete) {
return payments.p2pk({ signature: signatures[0] }) return payments.p2pk({ signature: signatures[0] })
} }
case SCRIPT_TYPES.MULTISIG: { case SCRIPT_TYPES.P2MS: {
const m = input.maxSignatures
if (allowIncomplete) { if (allowIncomplete) {
signatures = signatures.map(x => x || ops.OP_0) signatures = signatures.map(x => x || ops.OP_0)
} else { } else {
signatures = signatures.filter(x => x) signatures = signatures.filter(x => x)
} }
return payments.p2ms({ signatures }, { allowIncomplete }) // if the transaction is not not complete (complete), or if signatures.length === m, validate
// otherwise, the number of OP_0's may be >= m, so don't validate (boo)
const validate = !allowIncomplete || (m === signatures.length)
return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate })
} }
case SCRIPT_TYPES.P2SH: { case SCRIPT_TYPES.P2SH: {
const redeem = build(input.redeemScriptType, input, allowIncomplete) const redeem = build(input.redeemScriptType, input, allowIncomplete)

23
test/fixtures/transaction_builder.json

@ -1917,6 +1917,29 @@
} }
] ]
}, },
{
"description": "Incomplete Transaction P2SH(P2MS 2/3), missing signature",
"exception": "Not enough signatures provided",
"network": "testnet",
"inputs": [
{
"txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"vout": 0,
"signs": [
{
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG"
}
]
}
],
"outputs": [
{
"script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
"value": 1000
}
]
},
{ {
"description": "Duplicate transaction outs", "description": "Duplicate transaction outs",
"exception": "Duplicate TxOut: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:0", "exception": "Duplicate TxOut: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:0",

Loading…
Cancel
Save