diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 75cae0af..be0405be 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -68,6 +68,16 @@ Witness.prototype.inspect = function inspect() { return Witness.format(this.items); }; +/** + * Format the witness object as bitcoind asm. + * @param {Boolean?} decode - Attempt to decode hash types. + * @returns {String} Human-readable script. + */ + +Witness.prototype.toASM = function toASM(decode) { + return Script.formatASM(this.items, decode); +}; + /** * Clone the witness object. Note that the raw * encoded witness data will be lost. This is @@ -357,6 +367,16 @@ Stack.prototype.inspect = function inspect() { return Witness.format(this.items); }; +/** + * Format the stack as bitcoind asm. + * @param {Boolean?} decode - Attempt to decode hash types. + * @returns {String} Human-readable script. + */ + +Stack.prototype.toASM = function toASM(decode) { + return Script.formatASM(this.items, decode); +}; + Stack.prototype.__defineGetter__('length', function() { return this.items.length; }); @@ -884,6 +904,16 @@ Script.prototype.inspect = function inspect() { return Script.format(this.code); }; +/** + * Format the script as bitcoind asm. + * @param {Boolean?} decode - Attempt to decode hash types. + * @returns {String} Human-readable script. + */ + +Script.prototype.toASM = function toASM(decode) { + return Script.formatASM(this.code, decode); +}; + /** * Encode the script to a Buffer. Note that this * will _not_ contain the varint size before it. @@ -2768,6 +2798,15 @@ Script.prototype.isWitnessScripthash = function isWitnessScripthash() { return this.code[0] === opcodes.OP_0 && this.code[1].length === 32; }; +/** + * Test whether the output script is unspendable. + * @returns {Boolean} + */ + +Script.prototype.isUnspendable = function isUnspendable() { + return this.code.length > 0 && this.code[0] === opcodes.OP_RETURN; +}; + /** * "Guess" the type of the input script. * This method is not 100% reliable. @@ -3433,6 +3472,60 @@ Script.format = function format(code) { }).join(' '); }; +/** + * Format script code into bitcoind asm format. + * @param {Array} code + * @param {Boolean?} decode - Attempt to decode hash types. + * @returns {String} Human-readable string. + */ + +Script.formatASM = function formatASM(code, decode) { + var out = []; + var i, op, type, symbol; + + for (i = 0; i < code.length; i++) { + op = code[i]; + + if (Script.isBadPush(op)) { + out.push('[error]'); + break; + } + + if (Buffer.isBuffer(op)) { + if (op.length <= 4) { + op = Script.num(op, constants.flags.VERIFY_NONE); + out.push(op.toNumber()); + continue; + } + + if (decode && code[0] !== opcodes.OP_RETURN) { + symbol = ''; + if (Script.isSignatureEncoding(op)) { + type = op[op.length - 1]; + symbol = constants.hashTypeByVal[type & 0x1f] || ''; + if (symbol) { + if (type & constants.hashType.ANYONECANPAY) + symbol += '|ANYONECANPAY'; + symbol = '[' + symbol + ']'; + } + op = op.slice(0, -1); + } + out.push(op.toString('hex') + symbol); + continue; + } + + out.push(op.toString('hex')); + continue; + } + + op = constants.opcodesByVal[op] || 'OP_UNKNOWN'; + + out.push(op); + } + + return out.join(' '); +}; + /** * Test the script to see if it contains only push ops. * Push ops are: OP_1NEGATE, OP_0-OP_16 and all PUSHDATAs.