diff --git a/src/templates/index.js b/src/templates/index.js index 78a8eba..666075e 100644 --- a/src/templates/index.js +++ b/src/templates/index.js @@ -17,6 +17,9 @@ var types = { P2WSH: 'witnessscripthash' } +var SIGNABLE_SCRIPTS = [types.MULTISIG, types.P2PKH, types.P2PK] +var P2SH_SCRIPTS = SIGNABLE_SCRIPTS.concat([types.P2WPKH, types.P2WSH]) + function classifyOutput (script) { if (witnessPubKeyHash.output.check(script)) return types.P2WPKH if (witnessScriptHash.output.check(script)) return types.P2WSH @@ -54,10 +57,61 @@ function classifyWitness (script, allowIncomplete) { return types.NONSTANDARD } +function solveOutput (scriptCode) { + if (!(scriptCode instanceof Buffer)) { + throw new Error('Argument 0 for solveScript must be a Buffer') + } + + var outputType = classifyOutput(scriptCode) + var solvedBy = null + var requiredSigs = null + + switch (outputType) { + // We can only determine the relevant hash from these, not if it's signable + case types.P2SH: + solvedBy = scriptHash.output.decode(scriptCode) + break + case types.P2WSH: + solvedBy = witnessScriptHash.output.decode(scriptCode) + break + + // P2WPKH is separate from other signable types, it's best viewed as a special case for P2PKH + // Not included in canSign. + case types.P2WPKH: + solvedBy = witnessPubKeyHash.output.decode(scriptCode) + requiredSigs = 1 + break + + // We can immediately solve signatures for these + // When adding a new script type, edit here + case types.P2PK: + solvedBy = pubKey.output.decode(scriptCode) + requiredSigs = 1 + break + case types.P2PKH: + solvedBy = pubKeyHash.output.decode(scriptCode) + requiredSigs = 1 + break + case types.MULTISIG: + solvedBy = multisig.output.decode(scriptCode) + requiredSigs = solvedBy.m + break + } + + return { + type: outputType, + script: scriptCode, + solvedBy: solvedBy, + canSign: SIGNABLE_SCRIPTS.indexOf(outputType) !== -1, + requiredSigs: requiredSigs + } +} + module.exports = { classifyInput: classifyInput, classifyOutput: classifyOutput, classifyWitness: classifyWitness, + solveOutput: solveOutput, multisig: multisig, nullData: nullData, pubKey: pubKey, @@ -65,5 +119,7 @@ module.exports = { scriptHash: scriptHash, witnessPubKeyHash: witnessPubKeyHash, witnessScriptHash: witnessScriptHash, - types: types + types: types, + SIGNABLE_SCRIPTS: SIGNABLE_SCRIPTS, + P2SH_SCRIPTS: P2SH_SCRIPTS } diff --git a/test/script.js b/test/script.js index f1fe1f6..802a484 100644 --- a/test/script.js +++ b/test/script.js @@ -105,6 +105,30 @@ describe('script', function () { }) }) + describe('solveOutput', function () { + fixtures.valid.forEach(function (f) { + var script + if (f.scriptPubKeyHex) { + script = new Buffer(f.scriptPubKeyHex, 'hex') + } else if (f.scriptPubKey) { + script = bscript.fromASM(f.scriptPubKey) + } else { + return + } + + it('solves ' + bscript.toASM(script) + ' as ' + f.type, function () { + var solution = bscript.solveOutput(script) + assert.equal(solution.type, f.type) + if ([bscript.types.P2SH].concat(bscript.P2SH_SCRIPTS).indexOf(f.type) === -1) { + assert.equal(solution.solvedBy, null) + } + if (solution.canSign) { + assert.notEqual(solution.requiredSigs, null) + } + }) + }) + }) + describe('SCRIPT_VERIFY_MINIMALDATA policy', function () { fixtures.valid.forEach(function (f) { if (f.scriptSigHex) {