diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 1ae9f766..1b749851 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -70,11 +70,13 @@ function Witness(items, mutable) { /** * Inspect a Witness object. + * @method * @returns {String} Human-readable script. */ +Witness.prototype.toString = Witness.prototype.inspect = function inspect() { - return Script.format(this.items); + return Witness.format(this.items); }; /** @@ -237,75 +239,6 @@ Witness.fromRaw = function fromRaw(data, enc) { return new Witness(Witness.parseRaw(data, enc)); }; -/** - * Parse a formatted script - * string into a witness object. _Must_ - * contain only stack items (no non-push - * opcodes). - * @param {String} items - Script string. - * @returns {Witness} - * @throws Parse error. - */ - -Witness.fromString = function fromString(items) { - var i, op, symbol; - - if (typeof items !== 'string') - return new Witness(); - - items = items.trim(); - - if (items.length === 0) - return new Witness(); - - items = items.split(/\s+/); - - for (i = 0; i < items.length; i++) { - op = items[i].toLowerCase(); - - if (op.indexOf('op_') === 0) - op = op.slice(3); - - if (op === '-1' || op === '1negate') { - op = STACK_NEGATE; - } else if (op === '0' || op === 'false') { - op = STACK_FALSE; - } else if (op === 'true') { - op = STACK_TRUE; - } else if (+op >= 1 && +op <= 16) { - op = new Buffer([+op]); - } else { - symbol = 'OP_' + op.toUpperCase(); - if (opcodes[symbol] == null) { - if (op[0] === '\'' || op[0] === '"') { - op = op.slice(1, -1); - op = new Buffer(op, 'ascii'); - items[i] = op; - continue; - } - if (/^-?\d+$/.test(op)) { - op = new bn(op, 10); - op = Script.array(op); - items[i] = op; - continue; - } - if (op[0] === '[') - op = op.slice(1, -1); - if (op.indexOf('0x') === 0) - op = op.slice(2); - assert(utils.isHex(op), 'Non-stack item in witness string.'); - op = new Buffer(op, 'hex'); - } else { - assert(false, 'Non-stack item in witness string.'); - } - } - - items[i] = op; - } - - return new Witness(items); -}; - /** * Parse a test script/array * string into a witness object. _Must_ @@ -316,14 +249,14 @@ Witness.fromString = function fromString(items) { * @throws Parse error. */ -Witness.fromTestString = function fromTestString(items) { +Witness.fromString = function fromString(items) { var result; if (!Array.isArray(items)) { if (typeof items !== 'string') return new Witness(); - items = items.trim(); + items = items.trim().split(/\s+/); } if (items.length === 0) @@ -381,6 +314,18 @@ Witness.fromSymbolic = function fromSymbolic(items) { return new Witness(code); }; +/** + * Format script code into a human readable-string. + * @param {Array} code + * @returns {String} Human-readable string. + */ + +Witness.format = function format(items) { + return items.map(function(chunk) { + return chunk.toString('hex'); + }).join(' '); +}; + /** * Test an object to see if it is a Witness. * @param {Object} obj @@ -414,11 +359,13 @@ function Stack(items) { /** * Inspect the stack. + * @method * @returns {String} Human-readable stack. */ +Stack.prototype.toString = Stack.prototype.inspect = function inspect() { - return Script.format(this.items); + return Witness.format(this.items); }; Stack.prototype.__defineGetter__('length', function() { @@ -939,9 +886,11 @@ Script.prototype.clone = function clone(mutable) { /** * Inspect the script. + * @method * @returns {String} Human-readable script code. */ +Script.prototype.toString = Script.prototype.inspect = function inspect() { return Script.format(this.code); }; @@ -3396,32 +3345,48 @@ Script.isLowDER = function isLowDER(sig) { */ Script.format = function format(code) { - var scripts = []; + return code.map(function(chunk) { + var op, size; - if (Array.isArray(code)) { - scripts.push({ code: code }); - } else if (code instanceof Stack) { - scripts.push({ code: code.items }); - } else if (code instanceof Witness) { - scripts.push({ code: code.items }); - } else if (code instanceof Script) { - scripts.push(code); - } else if (code instanceof bcoin.input) { - scripts.push(code.script); - if (code.witness.length > 0) - scripts.push({ code: code.witness.items }); - if (code.coin) { - scripts.push(code.coin.script); - if (code.coin.script.isScripthash()) - scripts.push(code.coin.script.getRedeem()); + if (Buffer.isBuffer(chunk)) { + op = chunk.op; + if (op == null) { + if (chunk.length === 0) { + op = opcodes.OP_0; + } else if (chunk.length <= 0x4b) { + if (chunk.length === 1) { + if (chunk[0] === 0) { + op = opcodes.OP_0; + return constants.opcodesByVal[op]; + } else if (chunk[0] >= 1 && chunk[0] <= 16) { + op = chunk[0] + 0x50; + return constants.opcodesByVal[op]; + } else if (chunk[0] === 0x81) { + op = opcodes.OP_1NEGATE; + return constants.opcodesByVal[op]; + } + } + op = chunk.length; + } else if (chunk.length <= 0xff) { + op = opcodes.OP_PUSHDATA1; + } else if (chunk.length <= 0xffff) { + op = opcodes.OP_PUSHDATA2; + } else if (chunk.length <= 0xffffffff) { + op = opcodes.OP_PUSHDATA4; + } + } + size = chunk.length.toString(16); + if (size.length < 2) + size = '0' + size; + if (!constants.opcodesByVal[op]) { + op = op.toString(16); + if (op.length < 2) + op = '0' + op; + return '0x' + op + ' 0x' + chunk.toString('hex'); + } + op = constants.opcodesByVal[op]; + return op + ' 0x' + size + ' 0x' + chunk.toString('hex'); } - } else if (code instanceof bcoin.output) { - scripts.push(code.script); - } - - return Script.concat(scripts).map(function(chunk) { - if (Buffer.isBuffer(chunk)) - return '[' + chunk.toString('hex') + ']'; assert(typeof chunk === 'number'); @@ -3432,7 +3397,7 @@ Script.format = function format(code) { if (chunk.length < 2) chunk = '0' + chunk; - return 'UNKNOWN(' + chunk + ')'; + return '0x' + chunk; }).join(' '); }; @@ -3531,63 +3496,6 @@ Script.prototype.getArgs = function getArgs() { return -1; }; -/** - * Parse a formatted script - * string into a script object. - * @param {String} items - Script string. - * @returns {Script} - * @throws Parse error. - */ - -Script.fromString = function fromString(code) { - var i, op, symbol; - - if (typeof code !== 'string') - return new Script(); - - code = code.trim(); - - if (code.length === 0) - return new Script(); - - code = code.split(/\s+/); - - for (i = 0; i < code.length; i++) { - op = code[i]; - - symbol = op.toUpperCase(); - if (symbol.indexOf('OP_') !== 0) - symbol = 'OP_' + symbol; - - if (opcodes[symbol] == null) { - if (op[0] === '\'' || op[0] === '"') { - op = op.slice(1, -1); - op = new Buffer(op, 'ascii'); - code[i] = op; - continue; - } - if (/^-?\d+$/.test(op)) { - op = new bn(op, 10); - op = Script.array(op); - code[i] = op; - continue; - } - if (op[0] === '[') - op = op.slice(1, -1); - if (op.indexOf('0x') === 0) - op = op.slice(2); - assert(utils.isHex(op), 'Unknown opcode.'); - op = new Buffer(op, 'hex'); - code[i] = op; - continue; - } - - code[i] = opcodes[symbol]; - } - - return new Script(code); -}; - /** * Parse a bitcoind test script * string into a script object. @@ -3596,7 +3504,7 @@ Script.fromString = function fromString(code) { * @throws Parse error. */ -Script.fromTestString = function fromTestString(code) { +Script.fromString = function fromString(code) { var i, op, symbol, p; if (typeof code !== 'string') diff --git a/test/script-test.js b/test/script-test.js index c4d974cf..408e22d4 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -143,7 +143,7 @@ describe('Script', function() { it('should handle bad size pushes correctly.', function () { var err; var stack = new bcoin.script.stack(); - var s = bcoin.script.fromTestString( + var s = bcoin.script.fromString( 'OP_1 OP_DUP OP_PUSHDATA1' ); assert(utils.equals(s.raw, new Buffer('51764c', 'hex'))); @@ -156,7 +156,7 @@ describe('Script', function() { } assert(err); assert(err.code === 'BAD_OPCODE'); - var s = bcoin.script.fromTestString( + var s = bcoin.script.fromString( 'OP_1 OP_DUP OP_PUSHDATA2 0x01' ); assert(utils.equals(s.raw, new Buffer('51764d01', 'hex'))); @@ -170,7 +170,7 @@ describe('Script', function() { } assert(err); assert(err.code === 'BAD_OPCODE'); - var s = bcoin.script.fromTestString( + var s = bcoin.script.fromString( 'OP_1 OP_DUP OP_PUSHDATA4 0x0001' ); assert(utils.equals(s.raw, new Buffer('51764e0001', 'hex'))); @@ -184,7 +184,7 @@ describe('Script', function() { } assert(err); assert(err.code === 'BAD_OPCODE'); - var s = bcoin.script.fromTestString( + var s = bcoin.script.fromString( 'OP_1 OP_DUP OP_PUSHDATA1 0x02 0x01' ); assert(utils.equals(s.raw, new Buffer('51764c0201', 'hex'))); @@ -198,7 +198,7 @@ describe('Script', function() { } assert(err); assert(err.code === 'BAD_OPCODE'); - var s = bcoin.script.fromTestString( + var s = bcoin.script.fromString( 'OP_1 OP_DUP OP_PUSHDATA2 0x0200 0x01' ); assert(utils.equals(s.raw, new Buffer('51764d020001', 'hex'))); @@ -275,9 +275,9 @@ describe('Script', function() { comments += ' (' + expected + ')'; - witness = bcoin.witness.fromTestString(witness); - input = bcoin.script.fromTestString(input); - output = bcoin.script.fromTestString(output); + witness = bcoin.witness.fromString(witness); + input = bcoin.script.fromString(input); + output = bcoin.script.fromString(output); var flag = 0; for (var i = 0; i < flags.length; i++) { diff --git a/test/tx-test.js b/test/tx-test.js index fffdc2c6..53f8cbe2 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -152,7 +152,7 @@ describe('TX', function() { coins.forEach(function(data) { var hash = data[0]; var index = data[1]; - var script = bcoin.script.fromTestString(data[2]); + var script = bcoin.script.fromString(data[2]); var value = data[3]; var coin = new bcoin.coin({ version: 1,