Skip to content

Commit f94ac6c

Browse files
committed
txbuilder: refactor
1 parent 2eed466 commit f94ac6c

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) {
@@ -385,91 +386,92 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
385386
input.witness = witness
386387
}
387388

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

401-
if (!allowIncomplete) {
402-
// remove blank signatures
403-
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
404-
}
407+
if (type === scriptTypes.P2PKH) {
408+
if (!enforceMinSigs(allowIncomplete, signatures, pubKeys, 1, 1)) return []
409+
return bscript.pubKeyHash.input.encodeRaw(signatures[0], pubKeys[0])
410+
}
411+
412+
if (type === scriptTypes.MULTISIG) {
413+
signatures = signatures.map(function (signature) {
414+
return signature || ops.OP_0
415+
})
405416

406-
return bscript.multisig.input.encodeRaw(signatures)
417+
if (!allowIncomplete) {
418+
// remove blank signatures
419+
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
407420
}
408-
} else {
409-
throw new Error('Not yet supported')
421+
422+
return bscript.multisig.input.encodeRaw(signatures)
423+
}
424+
425+
if (type === scriptTypes.P2PK) {
426+
if (!enforceMinSigs(allowIncomplete, signatures, [], 1, 0)) return []
427+
return bscript.pubKey.input.encodeRaw(signatures[0])
410428
}
411429

412-
if (!allowIncomplete) throw new Error('Not enough signatures provided')
413430
return []
414431
}
415432

416433
function buildInput (input, allowIncomplete) {
417434
var scriptType = input.prevOutType
418-
var rawScript = []
435+
var rawScript = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
419436
var rawWitness = []
420437

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

437-
// If it wasn't SIGNABLE, it's witness, defer to that
438-
if (input.redeemScriptType) {
439-
p2sh = true
440-
scriptType = input.redeemScriptType
442+
if (scriptType !== bscript.types.P2WSH) {
443+
rawScript = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
444+
if (!allowIncomplete && !rawScript.length) throw new Error('Cannot build script for ' + scriptType)
441445
}
446+
isP2SH = true
442447
}
443448

444449
switch (scriptType) {
445450
case bscript.types.P2WPKH:
446-
rawWitness = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
451+
rawWitness = rawScript
452+
rawScript = []
447453
break
448454

449455
case bscript.types.P2WSH:
450-
// We can remove this check later
451-
if (!allowIncomplete && !supportedType(input.witnessScriptType)) {
452-
throw new Error('Impossible to sign this type')
453-
}
456+
scriptType = input.witnessScriptType
457+
rawWitness = buildRawScriptSig(scriptType, input.signatures, input.pubKeys, allowIncomplete)
458+
if (!allowIncomplete && !rawWitness.length) throw new Error('Cannot build witness for ' + scriptType)
454459

455-
if (supportedType(input.witnessScriptType)) {
456-
rawWitness = buildRawScriptSig(input.witnessScriptType, input.signatures, input.pubKeys, allowIncomplete)
460+
if (input.witnessScript) {
457461
rawWitness.push(input.witnessScript)
458-
scriptType = input.witnessScriptType
459462
}
460463

461464
break
462465
}
463466

464-
// append redeemScript if necessary
465-
if (p2sh) {
467+
if (isP2SH) {
466468
rawScript.push(input.redeemScript)
467469
}
468470

469471
return {
470472
type: scriptType,
471-
script: bscript.compile(rawScript),
472-
witness: bscript.toStack(rawWitness)
473+
rawScript: rawScript,
474+
rawWitness: rawWitness
473475
}
474476
}
475477

@@ -642,14 +644,15 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) {
642644
var result = buildInput(input, allowIncomplete)
643645

644646
// skip if no result
645-
if (!allowIncomplete) {
646-
if (!supportedType(result.type) && result.type !== bscript.types.P2WPKH) {
647-
throw new Error(result.type + ' not supported')
648-
}
647+
if (!allowIncomplete &&
648+
result.rawScript.length === 0 &&
649+
result.rawWitness.length === 0
650+
) {
651+
throw new Error(result.type + ' not supported')
649652
}
650653

651-
tx.setInputScript(i, result.script)
652-
tx.setWitness(i, result.witness)
654+
tx.setInputScript(i, bscript.compile(result.rawScript))
655+
tx.setWitness(i, bscript.toStack(result.rawWitness))
653656
})
654657

655658
if (!allowIncomplete) {

0 commit comments

Comments
 (0)