From d26db89a2151a83a74ff9bf1aa5a65f36f83e73f Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 21 Aug 2016 11:04:56 -0700 Subject: [PATCH] mtx: refactor. --- lib/bcoin/mtx.js | 191 +++++++++++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 73 deletions(-) diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index 1ee5ca08..6f464659 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -700,81 +700,111 @@ MTX.prototype.signature = function signature(index, prev, key, type, version) { */ MTX.prototype.isSigned = function isSigned() { - var i, input, prev, vector, m, len, j; - - for (i = 0; i < this.inputs.length; i++) { - input = this.inputs[i]; - - // We can't check for signatures unless - // we have the previous output. - if (!input.coin) + for (var i = 0; i < this.inputs.length; i++) { + if (!this.isInputSigned(i)) return false; + } +}; - // Get the prevout's script - prev = input.coin.script; +/** + * Test whether an input is fully-signed. + * @param {Number} index + * @returns {Boolean} + */ - // Script length, needed for multisig - vector = input.script; - len = vector.length; +MTX.prototype.isInputSigned = function isInputSigned(index) { + var input = this.inputs[index]; + var prev, vector, m, redeem, j, result; - // We need to grab the redeem script when - // signing p2sh transactions. - if (prev.isScripthash()) { - prev = input.script.getRedeem(); - if (!prev) - return false; - len = vector.length - 1; - } - - // If the output script is a witness program, - // we have to switch the vector to the witness - // and potentially alter the length. - if (prev.isWitnessScripthash()) { - prev = input.witness.getRedeem(); - if (!prev) - return false; - vector = input.witness; - len = vector.length - 1; - } else if (prev.isWitnessPubkeyhash()) { - prev = Script.fromPubkeyhash(prev.get(1)); - vector = input.witness; - len = vector.length; - } - - if (prev.isPubkey()) { - if (!Script.isSignature(vector.get(0))) - return false; - continue; - } - - if (prev.isPubkeyhash()) { - if (!Script.isSignature(vector.get(0))) - return false; - continue; - } - - if (prev.isMultisig()) { - // Grab `m` value (number of required sigs). - m = prev.getSmall(0); - - // Ensure all members are signatures. - for (j = 1; j < len; j++) { - if (!Script.isSignature(vector.get(j))) - return false; - } - - // Ensure we have the correct number - // of required signatures. - if (len - 1 !== m) - return false; - - continue; - } + assert(input, 'Input does not exist.'); + // We can't check for signatures unless + // we have the previous output. + if (!input.coin) return false; + + // Get the prevout's script + prev = input.coin.script; + + // Script length, needed for multisig + vector = input.script; + redeem = false; + + // We need to grab the redeem script when + // signing p2sh transactions. + if (prev.isScripthash()) { + prev = input.script.getRedeem(); + if (!prev) + return false; + redeem = true; } - return true; + // If the output script is a witness program, + // we have to switch the vector to the witness + // and potentially alter the length. + if (prev.isWitnessScripthash()) { + prev = input.witness.getRedeem(); + if (!prev) + return false; + vector = input.witness; + redeem = true; + } else if (prev.isWitnessPubkeyhash()) { + prev = Script.fromPubkeyhash(prev.get(1)); + vector = input.witness; + redeem = false; + } + + if (redeem) { + redeem = vector.pop(); + result = this.isVectorSigned(prev); + vector.push(redeem); + return result; + } + + return this.isVectorSigned(prev, vector); +}; + +/** + * Test whether a vector is fully-signed. + * @param {Script} prev + * @param {Script|Witness} vector + * @returns {Boolean} + */ + +MTX.prototype.isVectorSigned = function isVectorSigned(prev, vector) { + var m; + + if (prev.isPubkey()) { + if (!Script.isSignature(vector.get(0))) + return false; + return true; + } + + if (prev.isPubkeyhash()) { + if (!Script.isSignature(vector.get(0))) + return false; + return true; + } + + if (prev.isMultisig()) { + // Grab `m` value (number of required sigs). + m = prev.getSmall(0); + + // Ensure all members are signatures. + for (j = 1; j < vector.length; j++) { + if (!Script.isSignature(vector.get(j))) + return false; + } + + // Ensure we have the correct number + // of required signatures. + if (vector.length - 1 !== m) + return false; + + return true; + } + + return false; }; /** @@ -879,7 +909,7 @@ MTX.prototype.signAsync = function signAsync(ring, type, callback) { */ MTX.prototype.isScripted = function isScripted() { - var i, input; + var i; if (this.outputs.length === 0) return false; @@ -888,12 +918,27 @@ MTX.prototype.isScripted = function isScripted() { return false; for (i = 0; i < this.inputs.length; i++) { - input = this.inputs[i]; - - if (input.script.raw.length === 0 - && input.witness.items.length === 0) { + if (!this.isInputScripted(i)) return false; - } + } + + return true; +}; + +/** + * Test whether the input at least + * has all script templates built. + * @returns {Boolean} + */ + +MTX.prototype.isInputScripted = function isInputScripted(index) { + var input = this.inputs[index]; + + assert(input, 'Input does not exist.'); + + if (input.script.raw.length === 0 + && input.witness.items.length === 0) { + return false; } return true;