Skip to content

Commit 113e6c6

Browse files
committed
txbuilder: refactor
1 parent b30f8a8 commit 113e6c6

File tree

1 file changed

+62
-59
lines changed

1 file changed

+62
-59
lines changed

src/transaction_builder.js

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@ var ops = require('bitcoin-ops')
77
var typeforce = require('typeforce')
88
var types = require('./types')
99
var scriptTypes = bscript.types
10-
var SIGNABLE = [bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG]
11-
var P2SH = SIGNABLE.concat([bscript.types.P2WPKH, bscript.types.P2WSH])
1210

1311
var ECPair = require('./ecpair')
1412
var ECSignature = require('./ecsignature')
1513
var Transaction = require('./transaction')
1614

1715
function supportedType (type) {
18-
return SIGNABLE.indexOf(type) !== -1
16+
return [
17+
bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG
18+
].indexOf(type) !== -1
1919
}
2020

2121
function supportedP2SHType (type) {
22-
return P2SH.indexOf(type) !== -1
22+
return supportedType(type) ||
23+
[bscript.types.P2WPKH, bscript.types.P2WSH].indexOf(type) !== -1
2324
}
2425

2526
function extractChunks (type, chunks, script) {
@@ -381,91 +382,92 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
381382
input.witness = witness
382383
}
383384

385+
function enforceMinSigs (allowIncomplete, signatures, pubKeys, n, m) {
386+
if (allowIncomplete) {
387+
if (signatures.length !== n) return
388+
if (pubKeys.length !== m) return
389+
return true
390+
}
391+
392+
if (signatures.length !== n) throw new Error('Not enough signatures provided')
393+
if (pubKeys.length !== m) throw new Error('Invalid number of pubKeys')
394+
return true
395+
}
396+
384397
function buildRawScriptSig (type, signatures, pubKeys, allowIncomplete) {
385398
if (type === scriptTypes.P2WPKH) {
386-
if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return bscript.witnessPubKeyHash.input.encodeRaw(signatures[0], pubKeys[0])
387-
} else if (type === scriptTypes.P2PKH) {
388-
if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return bscript.pubKeyHash.input.encodeRaw(signatures[0], pubKeys[0])
389-
} else if (type === scriptTypes.P2PK) {
390-
if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return bscript.pubKey.input.encodeRaw(signatures[0])
391-
} else if (type === scriptTypes.MULTISIG) {
392-
if (signatures.length > 0) {
393-
signatures = signatures.map(function (signature) {
394-
return signature || ops.OP_0
395-
})
399+
if (!enforceMinSigs(allowIncomplete, signatures, pubKeys, 1, 1)) return []
400+
return bscript.witnessPubKeyHash.input.encodeRaw(signatures[0], pubKeys[0])
401+
}
396402

397-
if (!allowIncomplete) {
398-
// remove blank signatures
399-
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
400-
}
403+
if (type === scriptTypes.P2PKH) {
404+
if (!enforceMinSigs(allowIncomplete, signatures, pubKeys, 1, 1)) return []
405+
return bscript.pubKeyHash.input.encodeRaw(signatures[0], pubKeys[0])
406+
}
407+
408+
if (type === scriptTypes.MULTISIG) {
409+
signatures = signatures.map(function (signature) {
410+
return signature || ops.OP_0
411+
})
401412

402-
return bscript.multisig.input.encodeRaw(signatures)
413+
if (!allowIncomplete) {
414+
// remove blank signatures
415+
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
403416
}
404-
} else {
405-
throw new Error('Not yet supported')
417+
418+
return bscript.multisig.input.encodeRaw(signatures)
419+
}
420+
421+
if (type === scriptTypes.P2PK) {
422+
if (!enforceMinSigs(allowIncomplete, signatures, [], 1, 0)) return []
423+
return bscript.pubKey.input.encodeRaw(signatures[0])
406424
}
407425

408-
if (!allowIncomplete) throw new Error('Not enough signatures provided')
409426
return []
410427
}
411428

412429
function buildInput (input, allowIncomplete) {
413430
var scriptType = input.prevOutType
414-
var rawScript = []
431+
var rawScript = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
415432
var rawWitness = []
416433

417-
if (supportedType(scriptType)) {
418-
rawScript = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
419-
}
420-
421-
var p2sh = false
434+
var isP2SH = false
422435
if (scriptType === bscript.types.P2SH) {
423-
// We can remove this error later when we have a guarantee prepareInput
424-
// rejects unsignable scripts - it MUST be signable at this point.
425-
if (!allowIncomplete && !supportedP2SHType(input.redeemScriptType)) {
426-
throw new Error('Impossible to sign this type')
427-
}
428-
429-
if (supportedType(input.redeemScriptType)) {
430-
rawScript = buildRawScriptSig(input.redeemScriptType, input.signatures, input.pubKeys, allowIncomplete)
431-
}
436+
scriptType = input.redeemScriptType
432437

433-
// If it wasn't SIGNABLE, it's witness, defer to that
434-
if (input.redeemScriptType) {
435-
p2sh = true
436-
scriptType = input.redeemScriptType
438+
if (scriptType !== bscript.types.P2WSH) {
439+
rawScript = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
440+
if (!allowIncomplete && !rawScript.length) throw new Error('Cannot build script for ' + scriptType)
437441
}
442+
isP2SH = true
438443
}
439444

440445
switch (scriptType) {
441446
case bscript.types.P2WPKH:
442-
rawWitness = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
447+
rawWitness = rawScript
448+
rawScript = []
443449
break
444450

445451
case bscript.types.P2WSH:
446-
// We can remove this check later
447-
if (!allowIncomplete && !supportedType(input.witnessScriptType)) {
448-
throw new Error('Impossible to sign this type')
449-
}
452+
scriptType = input.witnessScriptType
453+
rawWitness = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
454+
if (!allowIncomplete && !rawWitness.length) throw new Error('Cannot build witness for ' + scriptType)
450455

451-
if (supportedType(input.witnessScriptType)) {
452-
rawWitness = buildRawScriptSig(input.witnessScriptType, input.signatures, input.pubKeys, allowIncomplete)
456+
if (input.witnessScript) {
453457
rawWitness.push(input.witnessScript)
454-
scriptType = input.witnessScriptType
455458
}
456459

457460
break
458461
}
459462

460-
// append redeemScript if necessary
461-
if (p2sh) {
463+
if (isP2SH) {
462464
rawScript.push(input.redeemScript)
463465
}
464466

465467
return {
466468
type: scriptType,
467-
script: bscript.compile(rawScript),
468-
witness: bscript.toStack(rawWitness)
469+
rawScript: rawScript,
470+
rawWitness: rawWitness
469471
}
470472
}
471473

@@ -638,14 +640,15 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) {
638640
var result = buildInput(input, allowIncomplete)
639641

640642
// skip if no result
641-
if (!allowIncomplete) {
642-
if (!supportedType(result.type) && result.type !== bscript.types.P2WPKH) {
643-
throw new Error(result.type + ' not supported')
644-
}
643+
if (!allowIncomplete &&
644+
result.rawScript.length === 0 &&
645+
result.rawWitness.length === 0
646+
) {
647+
throw new Error(result.type + ' not supported')
645648
}
646649

647-
tx.setInputScript(i, result.script)
648-
tx.setWitness(i, result.witness)
650+
tx.setInputScript(i, bscript.compile(result.rawScript))
651+
tx.setWitness(i, bscript.toStack(result.rawWitness))
649652
})
650653

651654
if (!allowIncomplete) {

0 commit comments

Comments
 (0)