From ea4d0dee030bf8a3a7a1369d23ad388783f5e157 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 28 Mar 2016 19:42:05 -0700 Subject: [PATCH] opcodes. --- lib/bcoin/mtx.js | 12 +- lib/bcoin/protocol/constants.js | 240 +++++++------- lib/bcoin/script.js | 545 ++++++++++++++++++-------------- test/node-test.js | 4 +- test/script-test.js | 63 +++- 5 files changed, 483 insertions(+), 381 deletions(-) diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index 3eb64ce0..962d3481 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -13,7 +13,7 @@ var constants = bcoin.protocol.constants; var network = bcoin.protocol.network; var Script = bcoin.script; var Witness = bcoin.script.witness; -var opc = constants.opcodes; +var opcodes = constants.opcodes; /** * MTX @@ -189,7 +189,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) { redeemScript = addr.program.encode(); vector = input.witness.items; dummy = new Buffer([]); - assert(addr.program.code[0] === opc['0'], 'Non-zero version passed to address.'); + assert(addr.program.code[0] === opcodes.OP_0, 'Non-zero version passed to address.'); if (addr.program.code[1].length === 32) { // P2WSH nested within pay-to-scripthash // (it had to be this complicated, didn't it?) @@ -206,7 +206,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) { redeemScript = addr.script.encode(); vector = input.script.code; prev = addr.script; - dummy = opc['0']; + dummy = opcodes.OP_0; } else { return false; } @@ -215,7 +215,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) { vector = input.witness.items; dummy = new Buffer([]); - if (prev.code[0] !== opc['0']) + if (prev.code[0] !== opcodes.OP_0) return false; if (prev.code[1].length === 32) { @@ -238,7 +238,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) { } else { // Wow, a normal output! Praise be to Jengus and Gord. vector = input.script.code; - dummy = opc['0']; + dummy = opcodes.OP_0; } if (prev.isPubkey()) { @@ -360,7 +360,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) { vector = input.script.code; len = vector.length; - dummy = opc['0']; + dummy = opcodes.OP_0; version = 0; // We need to grab the redeem script when diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index de9526cc..37f2a876 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -48,145 +48,143 @@ exports.filterFlags = { }; exports.opcodes = { - // 'false': 0x00, - '0': 0x00, + OP_FALSE: 0x00, + OP_0: 0x00, - pushdata1: 0x4c, - pushdata2: 0x4d, - pushdata4: 0x4e, + OP_PUSHDATA1: 0x4c, + OP_PUSHDATA2: 0x4d, + OP_PUSHDATA4: 0x4e, - '1negate': 0x4f, + OP_1NEGATE: 0x4f, - reserved: 0x50, + OP_RESERVED: 0x50, - // 'true': 0x51, - '1': 0x51, - '2': 0x52, - '3': 0x53, - '4': 0x54, - '5': 0x55, - '6': 0x56, - '7': 0x57, - '8': 0x58, - '9': 0x59, - '10': 0x5a, - '11': 0x5b, - '12': 0x5c, - '13': 0x5d, - '14': 0x5e, - '15': 0x5f, - '16': 0x60, + OP_TRUE: 0x51, + OP_1: 0x51, + OP_2: 0x52, + OP_3: 0x53, + OP_4: 0x54, + OP_5: 0x55, + OP_6: 0x56, + OP_7: 0x57, + OP_8: 0x58, + OP_9: 0x59, + OP_10: 0x5a, + OP_11: 0x5b, + OP_12: 0x5c, + OP_13: 0x5d, + OP_14: 0x5e, + OP_15: 0x5f, + OP_16: 0x60, - nop: 0x61, - ver: 0x62, - 'if': 0x63, - notif: 0x64, - verif: 0x65, - vernotif: 0x66, - 'else': 0x67, - endif: 0x68, - verify: 0x69, - 'return': 0x6a, + OP_NOP: 0x61, + OP_VER: 0x62, + OP_IF: 0x63, + OP_NOTIF: 0x64, + OP_VERIF: 0x65, + OP_VERNOTIF: 0x66, + OP_ELSE: 0x67, + OP_ENDIF: 0x68, + OP_VERIFY: 0x69, + OP_RETURN: 0x6a, - toaltstack: 0x6b, - fromaltstack: 0x6c, - '2drop': 0x6d, - '2dup': 0x6e, - '3dup': 0x6f, - '2over': 0x70, - '2rot': 0x71, - '2swap': 0x72, - ifdup: 0x73, - depth: 0x74, - drop: 0x75, - dup: 0x76, - nip: 0x77, - over: 0x78, - pick: 0x79, - roll: 0x7a, - rot: 0x7b, - swap: 0x7c, - tuck: 0x7d, + OP_TOALTSTACK: 0x6b, + OP_FROMALTSTACK: 0x6c, + OP_2DROP: 0x6d, + OP_2DUP: 0x6e, + OP_3DUP: 0x6f, + OP_2OVER: 0x70, + OP_2ROT: 0x71, + OP_2SWAP: 0x72, + OP_IFDUP: 0x73, + OP_DEPTH: 0x74, + OP_DROP: 0x75, + OP_DUP: 0x76, + OP_NIP: 0x77, + OP_OVER: 0x78, + OP_PICK: 0x79, + OP_ROLL: 0x7a, + OP_ROT: 0x7b, + OP_SWAP: 0x7c, + OP_TUCK: 0x7d, - cat: 0x7e, - substr: 0x7f, - left: 0x80, - right: 0x81, - size: 0x82, + OP_CAT: 0x7e, + OP_SUBSTR: 0x7f, + OP_LEFT: 0x80, + OP_RIGHT: 0x81, + OP_SIZE: 0x82, - invert: 0x83, - and: 0x84, - or: 0x85, - xor: 0x86, - equal: 0x87, - equalverify: 0x88, + OP_INVERT: 0x83, + OP_AND: 0x84, + OP_OR: 0x85, + OP_XOR: 0x86, + OP_EQUAL: 0x87, + OP_EQUALVERIFY: 0x88, - reserved1: 0x89, - reserved2: 0x8a, + OP_RESERVED1: 0x89, + OP_RESERVED2: 0x8a, - '1add': 0x8b, - '1sub': 0x8c, - '2mul': 0x8d, - '2div': 0x8e, - negate: 0x8f, - abs: 0x90, - not: 0x91, - '0notequal': 0x92, - add: 0x93, - sub: 0x94, - mul: 0x95, - div: 0x96, - mod: 0x97, - lshift: 0x98, - rshift: 0x99, - booland: 0x9a, - boolor: 0x9b, - numequal: 0x9c, - numequalverify: 0x9d, - numnotequal: 0x9e, - lessthan: 0x9f, - greaterthan: 0xa0, - lessthanorequal: 0xa1, - greaterthanorequal: 0xa2, - min: 0xa3, - max: 0xa4, - within: 0xa5, + OP_1ADD: 0x8b, + OP_1SUB: 0x8c, + OP_2MUL: 0x8d, + OP_2DIV: 0x8e, + OP_NEGATE: 0x8f, + OP_ABS: 0x90, + OP_NOT: 0x91, + OP_0NOTEQUAL: 0x92, + OP_ADD: 0x93, + OP_SUB: 0x94, + OP_MUL: 0x95, + OP_DIV: 0x96, + OP_MOD: 0x97, + OP_LSHIFT: 0x98, + OP_RSHIFT: 0x99, + OP_BOOLAND: 0x9a, + OP_BOOLOR: 0x9b, + OP_NUMEQUAL: 0x9c, + OP_NUMEQUALVERIFY: 0x9d, + OP_NUMNOTEQUAL: 0x9e, + OP_LESSTHAN: 0x9f, + OP_GREATERTHAN: 0xa0, + OP_LESSTHANOREQUAL: 0xa1, + OP_GREATERTHANOREQUAL: 0xa2, + OP_MIN: 0xa3, + OP_MAX: 0xa4, + OP_WITHIN: 0xa5, - ripemd160: 0xa6, - sha1: 0xa7, - sha256: 0xa8, - hash160: 0xa9, - hash256: 0xaa, - codeseparator: 0xab, - checksig: 0xac, - checksigverify: 0xad, - checkmultisig: 0xae, - checkmultisigverify: 0xaf, + OP_RIPEMD160: 0xa6, + OP_SHA1: 0xa7, + OP_SHA256: 0xa8, + OP_HASH160: 0xa9, + OP_HASH256: 0xaa, + OP_CODESEPARATOR: 0xab, + OP_CHECKSIG: 0xac, + OP_CHECKSIGVERIFY: 0xad, + OP_CHECKMULTISIG: 0xae, + OP_CHECKMULTISIGVERIFY: 0xaf, - // 'eval': 0xb0, - nop1: 0xb0, - // nop2: 0xb1, - checklocktimeverify: 0xb1, - // nop3: 0xb2, - checksequenceverify: 0xb2, - nop4: 0xb3, - nop5: 0xb4, - nop6: 0xb5, - nop7: 0xb6, - nop8: 0xb7, - nop9: 0xb8, - nop10: 0xb9, + OP_EVAL: 0xb0, + OP_NOP1: 0xb0, + OP_NOP2: 0xb1, + OP_CHECKLOCKTIMEVERIFY: 0xb1, + OP_NOP3: 0xb2, + OP_CHECKSEQUENCEVERIFY: 0xb2, + OP_NOP4: 0xb3, + OP_NOP5: 0xb4, + OP_NOP6: 0xb5, + OP_NOP7: 0xb6, + OP_NOP8: 0xb7, + OP_NOP9: 0xb8, + OP_NOP10: 0xb9, - pubkeyhash: 0xfd, - pubkey: 0xfe, - invalidopcode: 0xff + OP_PUBKEYHASH: 0xfd, + OP_PUBKEY: 0xfe, + OP_INVALIDOPCODE: 0xff }; exports.opcodesByVal = new Array(256); Object.keys(exports.opcodes).forEach(function(name) { var val = exports.opcodes[name]; - // if (val === 0x00 || (val >= 0x51 && val <= 0x60)) - // name = +name; exports.opcodesByVal[val] = name; }); diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index da327825..6250a5dd 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -10,7 +10,7 @@ var constants = bcoin.protocol.constants; var utils = require('./utils'); var assert = utils.assert; var BufferWriter = require('./writer'); -var opc = constants.opcodes; +var opcodes = constants.opcodes; function Witness(items) { if (!(this instanceof Witness)) @@ -84,18 +84,15 @@ Witness.prototype.getRedeem = function getRedeem() { }; Witness.fromString = function fromString(items) { - var i, op; + var i, op, symbol; items = items.trim().split(/\s+/); // Remove OP_ prefixes and lowercase for (i = 0; i < items.length; i++) { - op = items[i]; - if (typeof op === 'string') { - op = op.toLowerCase(); - if (op.indexOf('op_') === 0) - op = op.slice(3); - } + op = items[i].toLowerCase(); + if (op.indexOf('op_') === 0) + op = op.slice(3); items[i] = op; } @@ -113,15 +110,19 @@ Witness.fromString = function fromString(items) { op = new Buffer([1]); } else if (+op >= 1 && +op <= 16) { op = new Buffer([+op]); - } else if (constants.opcodes[op] == null) { - if (op[0] === '[') - op = op.slice(1, -1); - if (op.indexOf('0x') === 0) - op = op.substring(2); - assert(utils.isHex(op), 'Non hex-string.'); - op = new Buffer(op, 'hex'); } else { - assert(false, 'Non-stack item in witness string.'); + symbol = 'OP_' + op.toUpperCase(); + + if (opcodes[symbol] == null) { + if (op[0] === '[') + op = op.slice(1, -1); + if (op.indexOf('0x') === 0) + op = op.substring(2); + assert(utils.isHex(op), 'Non hex-string.'); + op = new Buffer(op, 'hex'); + } else { + assert(false, 'Non-stack item in witness string.'); + } } items[i] = op; @@ -130,6 +131,39 @@ Witness.fromString = function fromString(items) { return new Witness(items); }; +Witness.fromSymbolic = function fromSymbolic(items) { + var code = new Array(items.length); + var i, op, symbol; + + for (i = 0; i < items.length; i++) { + op = items[i]; + + if (Buffer.isBuffer(op)) { + code[i] = op; + continue; + } + + op = (op + '').toLowerCase(); + if (op.indexOf('op_') === 0) + op = op.slice(3); + + if (+op === -1) + op = new Buffer([0xff]); + else if (+op === 0 || op === 'false') + op = new Buffer([]); + else if (+op === 1 || op === 'true') + op = new Buffer([1]); + else if (+op >= 1 && +op <= 16) + op = new Buffer([+op]); + else + assert(false, 'Non-stack item in witness string.'); + + code[i] = op; + } + + return new Witness(code); +}; + Witness.isWitness = function isWitness(obj) { return obj && Array.isArray(obj.items) @@ -222,21 +256,21 @@ Stack.prototype._swap = function _swap(i1, i2) { Stack.prototype.toalt = function toalt() { if (this.length === 0) - throw new ScriptError('Stack too small.', opc.toaltstack); + throw new ScriptError('Stack too small.', opcodes.OP_TOALTSTACK); this.alt.push(this.pop()); }; Stack.prototype.fromalt = function fromalt() { if (this.alt.length === 0) - throw new ScriptError('Stack too small.', opc.fromaltstack); + throw new ScriptError('Stack too small.', opcodes.OP_FROMALTSTACK); this.push(this.alt.pop()); }; Stack.prototype.ifdup = function ifdup() { if (this.length === 0) - throw new ScriptError('Stack too small.', opc.ifdup); + throw new ScriptError('Stack too small.', opcodes.OP_IFDUP); if (Script.bool(this.top(-1))) this.push(Script.array(this.top(-1))); @@ -248,38 +282,38 @@ Stack.prototype.depth = function depth() { Stack.prototype.drop = function drop() { if (this.length === 0) - throw new ScriptError('Stack too small.', opc.drop); + throw new ScriptError('Stack too small.', opcodes.OP_DROP); this.pop(); }; Stack.prototype.dup = function dup() { if (this.length === 0) - throw new ScriptError('Stack too small.', opc.dup); + throw new ScriptError('Stack too small.', opcodes.OP_DUP); this.push(this.top(-1)); }; Stack.prototype.nip = function nip() { if (this.length < 2) - throw new ScriptError('Stack too small.', opc.nip); + throw new ScriptError('Stack too small.', opcodes.OP_NIP); this.splice(this.length - 2, 1); }; Stack.prototype.over = function over() { if (this.length < 2) - throw new ScriptError('Stack too small.', opc.over); + throw new ScriptError('Stack too small.', opcodes.OP_OVER); this.push(this.top(-2)); }; Stack.prototype.pick = function pick(flags) { - return this._pickroll(opc.pick, flags); + return this._pickroll(opcodes.OP_PICK, flags); }; Stack.prototype.roll = function roll(flags) { - return this._pickroll(opc.roll, flags); + return this._pickroll(opcodes.OP_ROLL, flags); }; Stack.prototype._pickroll = function pickroll(op, flags) { @@ -296,7 +330,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) { val = this.get(-n - 1); - if (op === opc.roll) + if (op === opcodes.OP_ROLL) this.splice(this.length - n - 1, 1); this.push(val); @@ -304,7 +338,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) { Stack.prototype.rot = function rot() { if (this.length < 3) - throw new ScriptError('Stack too small.', opc.rot); + throw new ScriptError('Stack too small.', opcodes.OP_ROT); this._swap(-3, -2); this._swap(-2, -1); @@ -312,21 +346,21 @@ Stack.prototype.rot = function rot() { Stack.prototype.swap = function swap() { if (this.length < 2) - throw new ScriptError('Stack too small.', opc.swap); + throw new ScriptError('Stack too small.', opcodes.OP_SWAP); this._swap(-2, -1); }; Stack.prototype.tuck = function tuck() { if (this.length < 2) - throw new ScriptError('Stack too small.', opc.tuck); + throw new ScriptError('Stack too small.', opcodes.OP_TUCK); this.splice(this.length - 2, 0, this.top(-1)); }; Stack.prototype.drop2 = function drop2() { if (this.length < 2) - throw new ScriptError('Stack too small.', opc['2drop']); + throw new ScriptError('Stack too small.', opcodes.OP_2DROP); this.pop(); this.pop(); @@ -336,7 +370,7 @@ Stack.prototype.dup2 = function dup2() { var v1, v2; if (this.length < 2) - throw new ScriptError('Stack too small.', opc['2dup']); + throw new ScriptError('Stack too small.', opcodes.OP_2DUP); v1 = this.top(-2); v2 = this.top(-1); @@ -349,7 +383,7 @@ Stack.prototype.dup3 = function dup3() { var v1, v2, v3; if (this.length < 3) - throw new ScriptError('Stack too small.', opc['3dup']); + throw new ScriptError('Stack too small.', opcodes.OP_3DUP); v1 = this.top(-3); v2 = this.top(-2); @@ -364,7 +398,7 @@ Stack.prototype.over2 = function over2() { var v1, v2; if (this.length < 4) - throw new ScriptError('Stack too small.', opc['2over']); + throw new ScriptError('Stack too small.', opcodes.OP_2OVER); v1 = this.top(-4); v2 = this.top(-3); @@ -377,7 +411,7 @@ Stack.prototype.rot2 = function rot2() { var v1, v2; if (this.length < 6) - throw new ScriptError('Stack too small.', opc['2rot']); + throw new ScriptError('Stack too small.', opcodes.OP_2ROT); v1 = this.top(-6); v2 = this.top(-5); @@ -394,7 +428,7 @@ Stack.prototype.swap2 = function swap2() { Stack.prototype.size = function size() { if (this.length < 1) - throw new ScriptError('Stack too small.', opc.size); + throw new ScriptError('Stack too small.', opcodes.OP_SIZE); this.push(Script.array(this.top(-1).length)); }; @@ -446,10 +480,10 @@ Script.prototype.getSubscript = function getSubscript(lastSep) { if (lastSep == null) lastSep = -1; - assert(lastSep <= 0 || this.code[lastSep] === opc.codeseparator); + assert(lastSep <= 0 || this.code[lastSep] === opcodes.OP_CODESEPARATOR); for (i = lastSep + 1; i < this.code.length; i++) { - if (this.code[i] !== opc.codeseparator) + if (this.code[i] !== opcodes.OP_CODESEPARATOR) res.push(this.code[i]); } @@ -471,11 +505,11 @@ Script.prototype._next = function _next(to, code, ip) { while (code[ip]) { op = code[ip]; - if (op === opc['if'] || op === opc.notif) + if (op === opcodes.OP_IF || op === opcodes.OP_NOTIF) depth++; - else if (op === opc['else']) + else if (op === opcodes.OP_ELSE) depth--; - else if (op === opc.endif) + else if (op === opcodes.OP_ENDIF) depth--; if (depth < 0) @@ -484,7 +518,7 @@ Script.prototype._next = function _next(to, code, ip) { if (depth === 0 && op === to) return ip; - if (op === opc['else']) + if (op === opcodes.OP_ELSE) depth++; ip++; @@ -538,44 +572,44 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version continue; } - if (op === opc['0']) { + if (op === opcodes.OP_0) { stack.push(new Buffer([])); continue; } - if (op >= opc['1'] && op <= opc['16']) { + if (op >= opcodes.OP_1 && op <= opcodes.OP_16) { stack.push(new Buffer([op - 0x50])); continue; } switch (op) { - case opc.nop: - case opc.nop1: - case opc.nop4: - case opc.nop5: - case opc.nop6: - case opc.nop7: - case opc.nop8: - case opc.nop9: - case opc.nop10: { + case opcodes.OP_NOP: + case opcodes.OP_NOP1: + case opcodes.OP_NOP4: + case opcodes.OP_NOP5: + case opcodes.OP_NOP6: + case opcodes.OP_NOP7: + case opcodes.OP_NOP8: + case opcodes.OP_NOP9: + case opcodes.OP_NOP10: { if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS) throw new ScriptError('Upgradable NOP used.', op, ip); break; } - case opc['1negate']: { + case opcodes.OP_1NEGATE: { stack.push(new Buffer([0xff])); break; } - case opc['if']: - case opc.notif: { + case opcodes.OP_IF: + case opcodes.OP_NOTIF: { if (stack.length < 1) throw new ScriptError('Stack too small.', op, ip); val = Script.bool(stack.pop()); - if (op === opc.notif) + if (op === opcodes.OP_NOTIF) val = !val; if_ = ip; - else_ = this._next(opc['else'], code, ip); - endif = this._next(opc.endif, code, ip); + else_ = this._next(opcodes.OP_ELSE, code, ip); + endif = this._next(opcodes.OP_ENDIF, code, ip); // Splice out the statement blocks we don't need if (val) { if (endif === -1) @@ -601,129 +635,129 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version ip--; break; } - case opc['else']: { + case opcodes.OP_ELSE: { throw new ScriptError('Unexpected else.', op, ip); } - case opc.endif: { + case opcodes.OP_ENDIF: { throw new ScriptError('Unexpected endif.', op, ip); } - case opc.verify: { + case opcodes.OP_VERIFY: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); if (!Script.bool(stack.pop())) throw new ScriptError('Verification failed.', op, ip); break; } - case opc['return']: { + case opcodes.OP_RETURN: { throw new ScriptError('Script returned.', op, ip); } - case opc.toaltstack: { + case opcodes.OP_TOALTSTACK: { stack.toalt(); break; } - case opc.fromaltstack: { + case opcodes.OP_FROMALTSTACK: { stack.fromalt(); break; } - case opc.ifdup: { + case opcodes.OP_IFDUP: { stack.ifdup(); break; } - case opc.depth: { + case opcodes.OP_DEPTH: { stack.depth(); break; } - case opc.drop: { + case opcodes.OP_DROP: { stack.drop(); break; } - case opc.dup: { + case opcodes.OP_DUP: { stack.dup(); break; } - case opc.nip: { + case opcodes.OP_NIP: { stack.nip(); break; } - case opc.over: { + case opcodes.OP_OVER: { stack.over(); break; } - case opc.pick: { + case opcodes.OP_PICK: { stack.pick(flags); break; } - case opc.roll: { + case opcodes.OP_ROLL: { stack.roll(flags); break; } - case opc.rot: { + case opcodes.OP_ROT: { stack.rot(); break; } - case opc.swap: { + case opcodes.OP_SWAP: { stack.swap(); break; } - case opc.tuck: { + case opcodes.OP_TUCK: { stack.tuck(); break; } - case opc['2drop']: { + case opcodes.OP_2DROP: { stack.drop2(); break; } - case opc['2dup']: { + case opcodes.OP_2DUP: { stack.dup2(); break; } - case opc['3dup']: { + case opcodes.OP_3DUP: { stack.dup3(); break; } - case opc['2over']: { + case opcodes.OP_2OVER: { stack.over2(); break; } - case opc['2rot']: { + case opcodes.OP_2ROT: { stack.rot2(); break; } - case opc['2swap']: { + case opcodes.OP_2SWAP: { stack.swap2(); break; } - case opc.size: { + case opcodes.OP_SIZE: { stack.size(); break; } - case opc['1add']: - case opc['1sub']: - case opc.negate: - case opc.abs: - case opc.not: - case opc['0notequal']: { + case opcodes.OP_1ADD: + case opcodes.OP_1SUB: + case opcodes.OP_NEGATE: + case opcodes.OP_ABS: + case opcodes.OP_NOT: + case opcodes.OP_0NOTEQUAL: { if (stack.length < 1) throw new ScriptError('Stack too small.', op, ip); n = Script.num(stack.pop(), flags); switch (op) { - case opc['1add']: + case opcodes.OP_1ADD: n.iadd(1); break; - case opc['1sub']: + case opcodes.OP_1SUB: n.isub(1); break; - case opc.negate: + case opcodes.OP_NEGATE: n = n.neg(); break; - case opc.abs: + case opcodes.OP_ABS: if (n.cmpn(0) < 0) n = n.neg(); break; - case opc.not: + case opcodes.OP_NOT: n = n.cmpn(0) === 0; break; - case opc['0notequal']: + case opcodes.OP_0NOTEQUAL: n = n.cmpn(0) !== 0; break; default: @@ -734,76 +768,76 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version stack.push(Script.array(n)); break; } - case opc.add: - case opc.sub: - case opc.booland: - case opc.boolor: - case opc.numequal: - case opc.numequalverify: - case opc.numnotequal: - case opc.lessthan: - case opc.greaterthan: - case opc.lessthanorequal: - case opc.greaterthanorequal: - case opc.min: - case opc.max: { + case opcodes.OP_ADD: + case opcodes.OP_SUB: + case opcodes.OP_BOOLAND: + case opcodes.OP_BOOLOR: + case opcodes.OP_NUMEQUAL: + case opcodes.OP_NUMEQUALVERIFY: + case opcodes.OP_NUMNOTEQUAL: + case opcodes.OP_LESSTHAN: + case opcodes.OP_GREATERTHAN: + case opcodes.OP_LESSTHANOREQUAL: + case opcodes.OP_GREATERTHANOREQUAL: + case opcodes.OP_MIN: + case opcodes.OP_MAX: { switch (op) { - case opc.add: - case opc.sub: - case opc.booland: - case opc.boolor: - case opc.numequal: - case opc.numequalverify: - case opc.numnotequal: - case opc.lessthan: - case opc.greaterthan: - case opc.lessthanorequal: - case opc.greaterthanorequal: - case opc.min: - case opc.max: + case opcodes.OP_ADD: + case opcodes.OP_SUB: + case opcodes.OP_BOOLAND: + case opcodes.OP_BOOLOR: + case opcodes.OP_NUMEQUAL: + case opcodes.OP_NUMEQUALVERIFY: + case opcodes.OP_NUMNOTEQUAL: + case opcodes.OP_LESSTHAN: + case opcodes.OP_GREATERTHAN: + case opcodes.OP_LESSTHANOREQUAL: + case opcodes.OP_GREATERTHANOREQUAL: + case opcodes.OP_MIN: + case opcodes.OP_MAX: if (stack.length < 2) throw new ScriptError('Stack too small.', op, ip); n2 = Script.num(stack.pop(), flags); n1 = Script.num(stack.pop(), flags); n = new bn(0, 'le'); switch (op) { - case opc.add: + case opcodes.OP_ADD: n = n1.add(n2); break; - case opc.sub: + case opcodes.OP_SUB: n = n1.sub(n2); break; - case opc.booland: + case opcodes.OP_BOOLAND: n = n1.cmpn(0) !== 0 && n2.cmpn(0) !== 0; break; - case opc.boolor: + case opcodes.OP_BOOLOR: n = n1.cmpn(0) !== 0 || n2.cmpn(0) !== 0; break; - case opc.numequal: + case opcodes.OP_NUMEQUAL: n = n1.cmp(n2) === 0; break; - case opc.numequalverify: + case opcodes.OP_NUMEQUALVERIFY: n = n1.cmp(n2) === 0; break; - case opc.numnotequal: + case opcodes.OP_NUMNOTEQUAL: n = n1.cmp(n2) !== 0; break; - case opc.lessthan: + case opcodes.OP_LESSTHAN: n = n1.cmp(n2) < 0; break; - case opc.greaterthan: + case opcodes.OP_GREATERTHAN: n = n1.cmp(n2) > 0; break; - case opc.lessthanorequal: + case opcodes.OP_LESSTHANOREQUAL: n = n1.cmp(n2) <= 0; break; - case opc.greaterthanorequal: + case opcodes.OP_GREATERTHANOREQUAL: n = n1.cmp(n2) >= 0; break; - case opc.min: + case opcodes.OP_MIN: n = n1.cmp(n2) < 0 ? n1 : n2; break; - case opc.max: + case opcodes.OP_MAX: n = n1.cmp(n2) > 0 ? n1 : n2; break; default: @@ -812,14 +846,14 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version if (typeof n === 'boolean') n = new bn(n ? 1 : 0, 'le'); res = Script.bool(n); - if (op === opc.numequalverify) { + if (op === opcodes.OP_NUMEQUALVERIFY) { if (!res) return false; } else { stack.push(Script.array(n)); } break; - case opc.within: + case opcodes.OP_WITHIN: if (stack.length < 3) throw new ScriptError('Stack too small.', op, ip); n3 = Script.num(stack.pop(), flags); @@ -832,46 +866,46 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version break; } - case opc.codeseparator: { + case opcodes.OP_CODESEPARATOR: { lastSep = ip; break; } - case opc.ripemd160: { + case opcodes.OP_RIPEMD160: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); stack.push(utils.ripemd160(stack.pop())); break; } - case opc.sha1: { + case opcodes.OP_SHA1: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); stack.push(utils.sha1(stack.pop())); break; } - case opc.sha256: { + case opcodes.OP_SHA256: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); stack.push(utils.sha256(stack.pop())); break; } - case opc.hash256: { + case opcodes.OP_HASH256: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); stack.push(utils.dsha256(stack.pop())); break; } - case opc.hash160: { + case opcodes.OP_HASH160: { if (stack.length === 0) throw new ScriptError('Stack too small.', op, ip); stack.push(utils.ripesha(stack.pop())); break; } - case opc.equalverify: - case opc.equal: { + case opcodes.OP_EQUALVERIFY: + case opcodes.OP_EQUAL: { if (stack.length < 2) throw new ScriptError('Stack too small.', op, ip); res = utils.isEqual(stack.pop(), stack.pop()); - if (op === opc.equalverify) { + if (op === opcodes.OP_EQUALVERIFY) { if (!res) throw new ScriptError('Equal verification failed.', op, ip); } else { @@ -879,8 +913,8 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version } break; } - case opc.checksigverify: - case opc.checksig: { + case opcodes.OP_CHECKSIGVERIFY: + case opcodes.OP_CHECKSIG: { if (!tx) throw new ScriptError('No TX passed in.', op, ip); @@ -904,7 +938,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version hash = tx.signatureHash(index, subscript, type, version); res = Script.checksig(hash, sig, key, flags); - if (op === opc.checksigverify) { + if (op === opcodes.OP_CHECKSIGVERIFY) { if (!res) throw new ScriptError('Signature verification failed.', op, ip); } else { @@ -913,8 +947,8 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version break; } - case opc.checkmultisigverify: - case opc.checkmultisig: { + case opcodes.OP_CHECKMULTISIGVERIFY: + case opcodes.OP_CHECKMULTISIG: { if (!tx) throw new ScriptError('No TX passed in.', op, ip); @@ -985,7 +1019,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version res = succ >= m; - if (op === opc.checkmultisigverify) { + if (op === opcodes.OP_CHECKMULTISIGVERIFY) { if (!res) throw new ScriptError('Signature verification failed.', op, ip); } else { @@ -994,7 +1028,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version break; } - case opc.checklocktimeverify: { + case opcodes.OP_CHECKLOCKTIMEVERIFY: { // OP_CHECKLOCKTIMEVERIFY = OP_NOP2 if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) { if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -1020,7 +1054,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version break; } - case opc.checksequenceverify: { + case opcodes.OP_CHECKSEQUENCEVERIFY: { // OP_CHECKSEQUENCEVERIFY = OP_NOP3 if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) { if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -1239,10 +1273,10 @@ Script.checkPush = function checkPush(value, flags) { return pushdata.opcode == null && pushdata.len === value.length; if (value.length <= 255) - return pushdata.opcode === constants.opcodes.pushdata1; + return pushdata.opcode === opcodes.OP_PUSHDATA1; if (value.length <= 65535) - return pushdata.opcode === constants.opcodes.pushdata2; + return pushdata.opcode === opcodes.OP_PUSHDATA2; return true; }; @@ -1262,7 +1296,7 @@ Script.isCode = function isCode(buf) { b = buf[i]; if (Buffer.isBuffer(b)) continue; - if (constants.opcodes[b] == null) + if (constants.opcodesByVal[b] == null) return false; } @@ -1275,16 +1309,16 @@ Script.prototype.concat = function concat(scripts) { }; Script.createPubkey = function createPubkey(key) { - return new Script([key, opc.checksig]); + return new Script([key, opcodes.OP_CHECKSIG]); }; Script.createPubkeyhash = function createPubkeyhash(hash) { return new Script([ - opc.dup, - opc.hash160, + opcodes.OP_DUP, + opcodes.OP_HASH160, hash, - opc.equalverify, - opc.checksig + opcodes.OP_EQUALVERIFY, + opcodes.OP_CHECKSIG ]); }; @@ -1295,23 +1329,23 @@ Script.createMultisig = function createMultisig(keys, m, n) { assert(m >= 1 && m <= n); assert(n >= 1 && n <= 15); - return new Script([opc[m]].concat( + return new Script([m + 0x50].concat( utils.sortKeys(keys), - [opc[n], opc.checkmultisig] + [n + 0x50, opcodes.OP_CHECKMULTISIG] )); }; Script.createScripthash = function createScripthash(hash) { return new Script([ - opc.hash160, + opcodes.OP_HASH160, hash, - opc.equal + opcodes.OP_EQUAL ]); }; Script.createNulldata = function createNulldata(flags) { return new Script([ - opc['return'], + opcodes.OP_RETURN, flags ]); }; @@ -1480,7 +1514,7 @@ Script.prototype.isPubkey = function isPubkey(key) { if (this.code.length !== 2) return false; - res = Script.isKey(this.code[0]) && this.code[1] === opc.checksig; + res = Script.isKey(this.code[0]) && this.code[1] === opcodes.OP_CHECKSIG; if (!res) return false; @@ -1499,11 +1533,11 @@ Script.prototype.isPubkeyhash = function isPubkeyhash(hash) { if (this.code.length !== 5) return false; - res = this.code[0] === opc.dup - && this.code[1] === opc.hash160 + res = this.code[0] === opcodes.OP_DUP + && this.code[1] === opcodes.OP_HASH160 && Script.isHash(this.code[2]) - && this.code[3] === opc.equalverify - && this.code[4] === opc.checksig; + && this.code[3] === opcodes.OP_EQUALVERIFY + && this.code[4] === opcodes.OP_CHECKSIG; if (!res) return false; @@ -1523,7 +1557,7 @@ Script.prototype.isMultisig = function isMultisig(keys) { if (this.code.length < 4) return false; - if (this.code[this.code.length - 1] !== opc.checkmultisig) + if (this.code[this.code.length - 1] !== opcodes.OP_CHECKMULTISIG) return false; n = Script.getSmall(this.code[this.code.length - 2]); @@ -1570,9 +1604,9 @@ Script.prototype.isScripthash = function isScripthash(hash) { if (this.code.length !== 3) return false; - res = this.code[0] === opc.hash160 + res = this.code[0] === opcodes.OP_HASH160 && Script.isHash(this.code[1]) - && this.code[2] === opc.equal; + && this.code[2] === opcodes.OP_EQUAL; if (!res) return false; @@ -1591,7 +1625,7 @@ Script.prototype.isNulldata = function isNulldata() { if (this.code.length !== 2) return false; - res = this.code[0] === opc['return'] && Script.isData(this.code[1]); + res = this.code[0] === opcodes.OP_RETURN && Script.isData(this.code[1]); if (!res) return false; @@ -1601,7 +1635,7 @@ Script.prototype.isNulldata = function isNulldata() { Script.prototype.isCommitment = function isCommitment() { return this.code.length >= 2 - && this.code[0] === opc['return'] + && this.code[0] === opcodes.OP_RETURN && Buffer.isBuffer(this.code[1]) && this.code[1].length === 36 && utils.readU32BE(this.code[1], 0) === 0xaa21a9ed; @@ -1624,8 +1658,8 @@ Script.prototype.isWitnessProgram = function isWitnessProgram() { if (!Buffer.isBuffer(this.code[1])) return false; - return (this.code[0] === opc['0'] - || (this.code[0] >= opc['1'] && this.code[0] <= opc['16'])) + return (this.code[0] === opcodes.OP_0 + || (this.code[0] >= opcodes.OP_1 && this.code[0] <= opcodes.OP_16)) && this.code[1].length >= 2 && this.code[1].length <= 32; }; @@ -1661,21 +1695,21 @@ Script.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() { if (!this.isWitnessProgram()) return false; - return this.code[0] === opc['0'] && this.code[1].length === 20; + return this.code[0] === opcodes.OP_0 && this.code[1].length === 20; }; Script.prototype.isWitnessScripthash = function isWitnessScripthash() { if (!this.isWitnessProgram()) return false; - return this.code[0] === opc['0'] && this.code[1].length === 32; + return this.code[0] === opcodes.OP_0 && this.code[1].length === 32; }; Script.createWitnessProgram = function createWitnessProgram(version, data) { assert(typeof version === 'number' && version >= 0 && version <= 16); assert(Buffer.isBuffer(data)); assert(data.length === 20 || data.length === 32); - return new Script([opc[version], data]); + return new Script([version === 0 ? 0 : version + 0x50, data]); }; Script.prototype.getInputType = function getInputType(prev) { @@ -1753,8 +1787,8 @@ Script.createOutputScript = function(options) { if (options.locktime != null) { script = new Script([ Script.array(options.locktime), - opc.checklocktimeverify, - opc.drop + opcodes.OP_CHECKLOCKTIMEVERIFY, + opcodes.OP_DROP ].concat(script.code)); } redeem = script; @@ -2200,8 +2234,11 @@ Script.format = function format(code) { if (Buffer.isBuffer(chunk)) return '[' + utils.toHex(chunk) + ']'; - if (typeof chunk === 'number') - return constants.opcodesByVal[chunk] || chunk; + if (typeof chunk === 'number') { + if (constants.opcodeByVal[chunk]) + return constants.opcodesByVal[chunk].slice(3).toLowerCase(); + return chunk; + } return chunk; }).join(' '); @@ -2211,8 +2248,12 @@ Script.prototype.isPushOnly = function isPushOnly() { var i, op; for (i = 0; i < this.code.length; i++) { op = this.code[i]; - if (Buffer.isBuffer(op) || op === opc['1negate'] || op === opc['0'] || (op >= opc['1'] && op <= opc['16'])) + if (Buffer.isBuffer(op) + || op === opcodes.OP_1NEGATE + || op === opcodes.OP_0 + || (op >= opcodes.OP_1 && op <= opcodes.OP_16)) { continue; + } return false; } return true; @@ -2229,13 +2270,13 @@ Script.prototype.getSigops = function getSigops(accurate) { if (Buffer.isBuffer(op)) continue; - if (constants.opcodes[op] == null) + if (constants.opcodesByVal[op] == null) return 0; - if (op === opc.checksig || op === opc.checksigverify) { + if (op === opcodes.OP_CHECKSIG || op === opcodes.OP_CHECKSIGVERIFY) { total++; - } else if (op === opc.checkmultisig || op === opc.checkmultisigverify) { - if (accurate && lastOp >= opc['1'] && lastOp <= opc['16']) + } else if (op === opcodes.OP_CHECKMULTISIG || op === opcodes.OP_CHECKMULTISIGVERIFY) { + if (accurate && lastOp >= opcodes.OP_1 && lastOp <= opcodes.OP_16) total += lastOp; else total += constants.script.maxPubkeysPerMultisig; @@ -2280,18 +2321,15 @@ Script.prototype.getArgs = function getArgs() { }; Script.fromString = function fromString(code) { - var i, op; + var i, op, symbol; code = code.trim().split(/\s+/); // Remove OP_ prefixes and lowercase for (i = 0; i < code.length; i++) { - op = code[i]; - if (typeof op === 'string') { - op = op.toLowerCase(); - if (op.indexOf('op_') === 0) - op = op.slice(3); - } + op = code[i].toLowerCase(); + if (op.indexOf('op_') === 0) + op = op.slice(3); code[i] = op; } @@ -2301,15 +2339,18 @@ Script.fromString = function fromString(code) { for (i = 0; i < code.length; i++) { op = code[i]; - if (op === '-1') { + if (op === '-1') op = '1negate'; - } else if (op === '0' || op === 'false') { - op = 0; - } else if (op === 'true') { - op = 1; - } else if (+op >= 1 && +op <= 16) { - op = +op; - } else if (constants.opcodes[op] == null) { + else if (op === '0' || op === 'false') + op = '0'; + else if (op === 'true') + op = '1'; + else if (+op >= 1 && +op <= 16) + op = +op + ''; + + symbol = 'OP_' + op.toUpperCase(); + + if (opcodes[symbol] == null) { if (op[0] === '[') op = op.slice(1, -1); if (op.indexOf('0x') === 0) @@ -2320,7 +2361,7 @@ Script.fromString = function fromString(code) { continue; } - code[i] = constants.opcodes[op]; + code[i] = opcodes[symbol]; } return new Script(code); @@ -2330,18 +2371,27 @@ Script.getSmall = function getSmall(op) { if (typeof op !== 'number') return null; - if (op === opc['0']) + if (op === opcodes.OP_0) return 0; - if (op >= opc['1'] && op <= opc['16']) + if (op >= opcodes.OP_1 && op <= opcodes.OP_16) return op - 0x50; return null; }; +Script.toSmall = function toSmall(op) { + assert(op >= 0 && op <= 16); + + if (op === 0) + return opcodes.OP_0; + + return op + 0x50; +}; + Script.fromSymbolic = function fromSymbolic(items) { var code = new Array(items.length); - var i, op; + var i, op, symbol; for (i = 0; i < items.length; i++) { op = items[i]; @@ -2351,16 +2401,22 @@ Script.fromSymbolic = function fromSymbolic(items) { continue; } + op = (op + '').toLowerCase(); + if (op.indexOf('op_') === 0) + op = op.slice(3); + if (+op === -1) op = '1negate'; else if (+op === 0 || op === 'false') - op = 0; + op = '0'; else if (+op === 1 || op === 'true') - op = 1; + op = '1'; else if (+op >= 1 && +op <= 16) - op = +op; + op = +op + ''; - code[i] = constants.opcodes[op]; + symbol = 'OP_' + op.toUpperCase(); + + code[i] = opcodes[symbol]; assert(code[i] != null, 'Unknown opcode.'); } @@ -2545,7 +2601,7 @@ Script.concat = function concat(scripts) { s = s.concat(scripts[0].code); for (i = 1; i < scripts.length; i++) { - s.push(opc.codeseparator); + s.push(opcodes.OP_CODESEPARATOR); s = s.concat(scripts[i].code); } @@ -2590,7 +2646,7 @@ Script.sign = function sign(msg, key, type) { Script.decode = function decode(buf) { var code = []; var off = 0; - var b, len; + var op, len; assert(Buffer.isBuffer(buf)); @@ -2601,62 +2657,62 @@ Script.decode = function decode(buf) { // NOTE 2: We use reference Buffer slices here. Larger // buffer slices should _never_ be passed in here. while (off < buf.length) { - b = buf[off++]; + op = buf[off++]; // Direct Push - // Next `b` bytes should be pushed to stack - if (b >= 0x01 && b <= 0x4b) { - code.push(buf.slice(off, off + b)); - off += b; + // Next `op` bytes should be pushed to stack + if (op >= 0x01 && op <= 0x4b) { + code.push(buf.slice(off, off + op)); + off += op; if (off > buf.length) { utils.hidden(code[code.length - 1], 'pushdata', { opcode: null, - len: b + len: op }); } continue; } if (off >= buf.length) { - code.push(b); + code.push(op); continue; } - if (b === constants.opcodes.pushdata1) { + if (op === opcodes.OP_PUSHDATA1) { len = buf[off]; off += 1; code.push(buf.slice(off, off + len)); off += len; if (len <= 0x4b || off > buf.length) { utils.hidden(code[code.length - 1], 'pushdata', { - opcode: b, + opcode: op, len: len }); } - } else if (b === constants.opcodes.pushdata2) { + } else if (op === opcodes.OP_PUSHDATA2) { len = utils.readU16(buf, off); off += 2; code.push(buf.slice(off, off + len)); off += len; if (len <= 0xff || off > buf.length) { utils.hidden(code[code.length - 1], 'pushdata', { - opcode: b, + opcode: op, len: len }); } - } else if (b === constants.opcodes.pushdata4) { + } else if (op === opcodes.OP_PUSHDATA4) { len = utils.readU32(buf, off); off += 4; code.push(buf.slice(off, off + len)); off += len; if (len <= 0xffff || off > buf.length) { utils.hidden(code[code.length - 1], 'pushdata', { - opcode: b, + opcode: op, len: len }); } } else { - code.push(b); + code.push(op); } } @@ -2665,7 +2721,6 @@ Script.decode = function decode(buf) { Script.encode = function encode(code) { var p = new BufferWriter(); - var opcodes = constants.opcodes; var i = 0; var op; @@ -2682,16 +2737,16 @@ Script.encode = function encode(code) { if (op.pushdata.opcode === null) { p.writeU8(op.pushdata.len); p.writeBytes(op); - } else if (op.pushdata.opcode === opcodes.pushdata1) { - p.writeU8(opcodes.pushdata1); + } else if (op.pushdata.opcode === opcodes.OP_PUSHDATA1) { + p.writeU8(opcodes.OP_PUSHDATA1); p.writeU8(op.pushdata.len); p.writeBytes(op); - } else if (op.pushdata.opcode === opcodes.pushdata2) { - p.writeU8(opcodes.pushdata2); + } else if (op.pushdata.opcode === opcodes.OP_PUSHDATA2) { + p.writeU8(opcodes.OP_PUSHDATA2); p.writeU16(op.pushdata.len); p.writeBytes(op); - } else if (op.pushdata.opcode === opcodes.pushdata4) { - p.writeU8(opcodes.pushdata4); + } else if (op.pushdata.opcode === opcodes.OP_PUSHDATA4) { + p.writeU8(opcodes.OP_PUSHDATA4); p.writeU32(op.pushdata.len); p.writeBytes(op); } @@ -2699,20 +2754,29 @@ Script.encode = function encode(code) { } // Standard minimaldata encoding if (op.length === 0) { - p.writeU8(opcodes['0']); + p.writeU8(opcodes.OP_0); } else if (op.length <= 0x4b) { + if (op.length === 1) { + if (op[0] === 0xff) { + p.writeU8(opcodes.OP_1NEGATE); + continue; + } else if (op[0] >= 0 && op[0] <= 16) { + p.writeU8(op[0] === 0 ? 0 : op[0] + 0x50); + continue; + } + } p.writeU8(op.length); p.writeBytes(op); } else if (op.length <= 0xff) { - p.writeU8(opcodes.pushdata1); + p.writeU8(opcodes.OP_PUSHDATA1); p.writeU8(op.length); p.writeBytes(op); } else if (op.length <= 0xffff) { - p.writeU8(opcodes.pushdata2); + p.writeU8(opcodes.OP_PUSHDATA2); p.writeU16(op.length); p.writeBytes(op); } else { - p.writeU8(opcodes.pushdata4); + p.writeU8(opcodes.OP_PUSHDATA4); p.writeU32(op.length); p.writeBytes(op); } @@ -2743,10 +2807,11 @@ function ScriptError(msg, op, ip) { Error.captureStackTrace(this, ScriptError); this.type = 'ScriptError'; if (Buffer.isBuffer(op)) - op = 'pushdata[' + op.length + ']'; + op = 'PUSHDATA[' + op.length + ']'; if (op || ip != null) { msg += '('; if (op) { + op = constants.opcodesByVal[op] || op; msg += 'op=' + op; if (ip != null) msg += ', '; diff --git a/test/node-test.js b/test/node-test.js index ea6b2355..3818a81d 100644 --- a/test/node-test.js +++ b/test/node-test.js @@ -3,7 +3,7 @@ var bcoin = require('../'); var constants = bcoin.protocol.constants; var utils = bcoin.utils; var assert = utils.assert; -var opc = constants.opcodes; +var opcodes = constants.opcodes; describe('Wallet', function() { process.env.BCOIN_DB = 'memdown'; @@ -31,7 +31,7 @@ describe('Wallet', function() { // Coinbase var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000 - var prev = new bcoin.script([w.publicKey, opc['checksig']]); + var prev = new bcoin.script([w.publicKey, opcodes.OP_CHECKSIG]); var dummyInput = { prevout: { hash: constants.oneHash, diff --git a/test/script-test.js b/test/script-test.js index e297fe1b..3509ef38 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -2,7 +2,7 @@ var assert = require('assert'); var bcoin = require('../'); var Script = bcoin.script; var Stack = bcoin.script.stack; -var opc = bcoin.protocol.constants.opcodes; +var opcodes = bcoin.protocol.constants.opcodes; describe('Script', function() { it('should encode/decode script', function() { @@ -20,7 +20,7 @@ describe('Script', function() { assert.equal( bcoin.utils.toHex(decoded[1]), '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'); - assert.equal(decoded[2], opc['checksig']); + assert.equal(decoded[2], opcodes.OP_CHECKSIG); var dst = bcoin.script.encode(decoded); assert.equal(bcoin.utils.toHex(dst), src); @@ -50,40 +50,79 @@ describe('Script', function() { }); it('should handle if statements correctly', function () { - var inputScript = new Script([opc['1'], opc['2']]); - var prevOutScript = new Script([opc['2'], opc.equal, opc['if'], opc[3], opc['else'], opc[4], opc.endif, opc[5]]); + var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); + var prevOutScript = new Script([ + opcodes.OP_2, + opcodes.OP_EQUAL, + opcodes.OP_IF, + opcodes.OP_3, + opcodes.OP_ELSE, + opcodes.OP_4, + opcodes.OP_ENDIF, + opcodes.OP_5 + ]); var stack = new Stack(); inputScript.execute(stack); var res = prevOutScript.execute(stack); assert(res); assert.deepEqual(stack.slice(), [[1], [3], [5]]); - var inputScript = new Script([opc[1], opc[2]]); - var prevOutScript = new Script([opc[9], opc['equal'], opc['if'], opc[3], opc['else'], opc[4], opc['endif'], opc[5]]); + var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); + var prevOutScript = new Script([ + opcodes.OP_9, + opcodes.OP_EQUAL, + opcodes.OP_IF, + opcodes.OP_3, + opcodes.OP_ELSE, + opcodes.OP_4, + opcodes.OP_ENDIF, + opcodes.OP_5 + ]); var stack = new Stack(); inputScript.execute(stack); var res = prevOutScript.execute(stack); assert(res); assert.deepEqual(stack.slice(), [[1], [4], [5]]); - var inputScript = new Script([opc[1], opc[2]]); - var prevOutScript = new Script([opc[2], opc['equal'], opc['if'], opc[3], opc['endif'], opc[5]]); + var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); + var prevOutScript = new Script([ + opcodes.OP_2, + opcodes.OP_EQUAL, + opcodes.OP_IF, + opcodes.OP_3, + opcodes.OP_ENDIF, + opcodes.OP_5 + ]); var stack = new Stack(); inputScript.execute(stack); var res = prevOutScript.execute(stack); assert(res); assert.deepEqual(stack.slice(), [[1], [3], [5]]); - var inputScript = new Script([opc[1], opc[2]]); - var prevOutScript = new Script([opc[9], opc['equal'], opc['if'], opc[3], opc['endif'], opc[5]]); + var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); + var prevOutScript = new Script([ + opcodes.OP_9, + opcodes.OP_EQUAL, + opcodes.OP_IF, + opcodes.OP_3, + opcodes.OP_ENDIF, + opcodes.OP_5 + ]); var stack = new Stack(); inputScript.execute(stack); var res = prevOutScript.execute(stack); assert(res); assert.deepEqual(stack.slice(), [[1], [5]]); - var inputScript = new Script([opc[1], opc[2]]); - var prevOutScript = new Script([opc[9], opc['equal'], opc['notif'], opc[3], opc['endif'], opc[5]]); + var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); + var prevOutScript = new Script([ + opcodes.OP_9, + opcodes.OP_EQUAL, + opcodes.OP_NOTIF, + opcodes.OP_3, + opcodes.OP_ENDIF, + opcodes.OP_5 + ]); var stack = new Stack(); inputScript.execute(stack); var res = prevOutScript.execute(stack);