From a1e9999f29d154f0da91ee781525796fc5926c84 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 11 Jun 2017 23:37:55 -0700 Subject: [PATCH] script: refactor execution. --- lib/script/common.js | 23 +++++++++------------- lib/script/opcode.js | 20 +++++++++++++++++++ lib/script/script.js | 47 +++++++++++++++++++++----------------------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/lib/script/common.js b/lib/script/common.js index 09d8842e..f48da1c5 100644 --- a/lib/script/common.js +++ b/lib/script/common.js @@ -814,7 +814,7 @@ exports.array = function(value) { * @constructor * @extends Error * @param {String} code - Error code. - * @param {Number} op - Opcode. + * @param {Opcode} op - Opcode. * @param {Number?} ip - Instruction pointer. * @property {String} message - Error message. * @property {String} code - Original code passed in. @@ -834,21 +834,16 @@ exports.ScriptError = function ScriptError(code, op, ip) { this.type = 'ScriptError'; this.code = code; this.message = code; - this.op = op != null ? op : -1; - this.ip = ip != null ? ip : -1; + this.op = -1; + this.ip = -1; - if (typeof op === 'number') { - if (exports.opcodesByVal[op]) - op = exports.opcodesByVal[op]; - else if (op !== -1) - op = util.hex8(op); - - this.message += ' (op=' + op + ','; - this.message += ' ip=' + this.ip + ')'; - } else if (typeof op === 'string') { + if (typeof op === 'string') { this.message = op; - this.op = -1; - this.ip = -1; + } else if (op) { + this.op = op.value; + this.ip = ip; + this.message += ' (op=' + op.toSymbol() + ','; + this.message += ' ip=' + ip + ')'; } }; diff --git a/lib/script/opcode.js b/lib/script/opcode.js index e26cfca1..bdbcfd98 100644 --- a/lib/script/opcode.js +++ b/lib/script/opcode.js @@ -388,6 +388,26 @@ Opcode.fromSymbol = function fromSymbol(name) { return Opcode.fromOp(op); }; +/** + * Convert opcode to its symbolic representation. + * @returns {String} + */ + +Opcode.prototype.toSymbol = function toSymbol() { + var op = this.value; + var symbol; + + if (op === -1) + op = 0xff; + + symbol = common.opcodesByVal[op]; + + if (symbol == null) + symbol = util.hex8(op); + + return symbol; +}; + /** * Test whether an object an Opcode. * @param {Object} obj diff --git a/lib/script/script.js b/lib/script/script.js index 513589ae..ad1e8dac 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -508,10 +508,9 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers var state = []; var negate = 0; var minimal = false; - var op, code, data; var val, v1, v2, v3; var num, n1, n2, n3; - var m, n, key, sig; + var op, m, n, key, sig; var type, subscript, hash; var ikey, isig, ikey2; var i, j, res, locktime; @@ -529,29 +528,27 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers throw new ScriptError('SCRIPT_SIZE'); for (ip = 0; ip < this.code.length; ip++) { - code = this.code[ip]; - op = code.value; - data = code.data; + op = this.code[ip]; - if (op === -1) + if (op.value === -1) throw new ScriptError('BAD_OPCODE', op, ip); - if (data) { - if (data.length > consensus.MAX_SCRIPT_PUSH) + if (op.data) { + if (op.data.length > consensus.MAX_SCRIPT_PUSH) throw new ScriptError('PUSH_SIZE', op, ip); // Note that minimaldata is not checked // on unexecuted branches of code. if (negate === 0) { - if (minimal && !code.isMinimal()) + if (minimal && !op.isMinimal()) throw new ScriptError('MINIMALDATA', op, ip); - stack.push(data); + stack.push(op.data); } continue; } - if (op > opcodes.OP_16 && ++opCount > consensus.MAX_SCRIPT_OPS) + if (op.value > opcodes.OP_16 && ++opCount > consensus.MAX_SCRIPT_OPS) throw new ScriptError('OP_COUNT', op, ip); // It's very important to make a distiction @@ -559,7 +556,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers // are in unexecuted branches of code_. Whereas // a totally unknown opcode is fine as long as it // is unexecuted. - switch (op) { + switch (op.value) { case opcodes.OP_CAT: case opcodes.OP_SUBSTR: case opcodes.OP_LEFT: @@ -578,8 +575,8 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers throw new ScriptError('DISABLED_OPCODE', op, ip); } - if (op >= opcodes.OP_IF && op <= opcodes.OP_ENDIF) { - switch (op) { + if (op.value >= opcodes.OP_IF && op.value <= opcodes.OP_ENDIF) { + switch (op.value) { case opcodes.OP_IF: case opcodes.OP_NOTIF: { val = false; @@ -600,7 +597,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers val = Script.bool(val); - if (op === opcodes.OP_NOTIF) + if (op.value === opcodes.OP_NOTIF) val = !val; stack.pop(); @@ -649,7 +646,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (negate !== 0) continue; - switch (op) { + switch (op.value) { case opcodes.OP_0: { stack.push(STACK_FALSE); break; @@ -677,7 +674,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers case opcodes.OP_14: case opcodes.OP_15: case opcodes.OP_16: { - stack.push(Buffer.from([op - 0x50])); + stack.push(Buffer.from([op.value - 0x50])); break; } case opcodes.OP_NOP: { @@ -893,7 +890,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers val = stack.top(-num - 1); - if (op === opcodes.OP_ROLL) + if (op.value === opcodes.OP_ROLL) stack.remove(-num - 1); stack.push(val); @@ -939,7 +936,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers res = util.equal(v1, v2); - // if (op == opcodes.OP_NOTEQUAL) + // if (op.value == opcodes.OP_NOTEQUAL) // res = !res; stack.pop(); @@ -947,7 +944,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.push(res ? STACK_TRUE : STACK_FALSE); - if (op === opcodes.OP_EQUALVERIFY) { + if (op.value === opcodes.OP_EQUALVERIFY) { if (!res) throw new ScriptError('EQUALVERIFY', op, ip); stack.pop(); @@ -968,7 +965,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers num = Script.num(stack.top(-1), minimal); - switch (op) { + switch (op.value) { case opcodes.OP_1ADD: num.iaddn(1); break; @@ -1030,7 +1027,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers n1 = Script.num(stack.top(-2), minimal); n2 = Script.num(stack.top(-1), minimal); - switch (op) { + switch (op.value) { case opcodes.OP_ADD: num = n1.iadd(n2); break; @@ -1103,7 +1100,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.pop(); stack.push(Script.array(num)); - if (op === opcodes.OP_NUMEQUALVERIFY) { + if (op.value === opcodes.OP_NUMEQUALVERIFY) { if (!Script.bool(stack.top(-1))) throw new ScriptError('NUMEQUALVERIFY', op, ip); stack.pop(); @@ -1203,7 +1200,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.push(res ? STACK_TRUE : STACK_FALSE); - if (op === opcodes.OP_CHECKSIGVERIFY) { + if (op.value === opcodes.OP_CHECKSIGVERIFY) { if (!res) throw new ScriptError('CHECKSIGVERIFY', op, ip); stack.pop(); @@ -1305,7 +1302,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers stack.push(res ? STACK_TRUE : STACK_FALSE); - if (op === opcodes.OP_CHECKMULTISIGVERIFY) { + if (op.value === opcodes.OP_CHECKMULTISIGVERIFY) { if (!res) throw new ScriptError('CHECKMULTISIGVERIFY', op, ip); stack.pop();