From d3a4cfa3334f281d315774bb85f3cd607c0c4434 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Mon, 5 May 2014 10:43:24 -0400 Subject: [PATCH] remove eval eval is unsafe, and the way it was being used in Script and Script interpreter was not a good enough reason. This commit removes both uses of eval, then replaces all uses of OP_XXX with Opcode.map.OP_XXX since there's no reason for those constants to be global. --- lib/Script.js | 73 ++++----- lib/ScriptInterpreter.js | 327 +++++++++++++++++++-------------------- test/test.Opcode.js | 16 +- 3 files changed, 201 insertions(+), 215 deletions(-) diff --git a/lib/Script.js b/lib/Script.js index f8684b4..37bcf8e 100644 --- a/lib/Script.js +++ b/lib/Script.js @@ -4,11 +4,6 @@ var log = imports.log || require('../util/log'); var Opcode = imports.Opcode || require('./Opcode'); var buffertools = imports.buffertools || require('buffertools'); -// Make opcodes available as pseudo-constants -for (var i in Opcode.map) { - eval(i + " = " + Opcode.map[i] + ";"); -} - var util = imports.util || require('../util/util'); var Parser = imports.Parser || require('../util/BinaryParser'); var Put = imports.Put || require('bufferput'); @@ -51,18 +46,18 @@ Script.prototype.parse = function() { var opcode = parser.word8(); var len, chunk; - if (opcode > 0 && opcode < OP_PUSHDATA1) { + if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) { // Read some bytes of data, opcode value is the length of data this.chunks.push(parser.buffer(opcode)); - } else if (opcode === OP_PUSHDATA1) { + } else if (opcode === Opcode.map.OP_PUSHDATA1) { len = parser.word8(); chunk = parser.buffer(len); this.chunks.push(chunk); - } else if (opcode === OP_PUSHDATA2) { + } else if (opcode === Opcode.map.OP_PUSHDATA2) { len = parser.word16le(); chunk = parser.buffer(len); this.chunks.push(chunk); - } else if (opcode === OP_PUSHDATA4) { + } else if (opcode === Opcode.map.OP_PUSHDATA4) { len = parser.word32le(); chunk = parser.buffer(len); this.chunks.push(chunk); @@ -75,7 +70,7 @@ Script.prototype.parse = function() { Script.prototype.isPushOnly = function() { for (var i = 0; i < this.chunks.length; i++) { var op = this.chunks[i]; - if (!Buffer.isBuffer(op) && op > OP_16) { + if (!Buffer.isBuffer(op) && op > Opcode.map.OP_16) { return false; } } @@ -85,38 +80,38 @@ Script.prototype.isPushOnly = function() { Script.prototype.isP2SH = function() { return (this.chunks.length == 3 && - this.chunks[0] == OP_HASH160 && + this.chunks[0] == Opcode.map.OP_HASH160 && Buffer.isBuffer(this.chunks[1]) && this.chunks[1].length == 20 && - this.chunks[2] == OP_EQUAL); + this.chunks[2] == Opcode.map.OP_EQUAL); }; Script.prototype.isPubkey = function() { return (this.chunks.length == 2 && Buffer.isBuffer(this.chunks[0]) && - this.chunks[1] == OP_CHECKSIG); + this.chunks[1] == Opcode.map.OP_CHECKSIG); }; Script.prototype.isPubkeyHash = function() { return (this.chunks.length == 5 && - this.chunks[0] == OP_DUP && - this.chunks[1] == OP_HASH160 && + this.chunks[0] == Opcode.map.OP_DUP && + this.chunks[1] == Opcode.map.OP_HASH160 && Buffer.isBuffer(this.chunks[2]) && this.chunks[2].length == 20 && - this.chunks[3] == OP_EQUALVERIFY && - this.chunks[4] == OP_CHECKSIG); + this.chunks[3] == Opcode.map.OP_EQUALVERIFY && + this.chunks[4] == Opcode.map.OP_CHECKSIG); }; function isSmallIntOp(opcode) { - return ((opcode == OP_0) || - ((opcode >= OP_1) && (opcode <= OP_16))); + return ((opcode == Opcode.map.OP_0) || + ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); }; Script.prototype.isMultiSig = function() { return (this.chunks.length > 3 && isSmallIntOp(this.chunks[0]) && isSmallIntOp(this.chunks[this.chunks.length - 2]) && - this.chunks[this.chunks.length - 1] == OP_CHECKMULTISIG); + this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG); }; Script.prototype.isP2shScriptSig = function() { @@ -384,13 +379,13 @@ Script.prototype.writeN = function(n) { throw new Error("writeN: out of range value " + n); if (n == 0) - this.writeOp(OP_0); + this.writeOp(Opcode.map.OP_0); else - this.writeOp(OP_1 + n - 1); + this.writeOp(Opcode.map.OP_1 + n - 1); }; function prefixSize(data_length) { - if (data_length < OP_PUSHDATA1) { + if (data_length < Opcode.map.OP_PUSHDATA1) { return 1; } else if (data_length <= 0xff) { return 1 + 1; @@ -403,20 +398,20 @@ function prefixSize(data_length) { function encodeLen(data_length) { var buf = undefined; - if (data_length < OP_PUSHDATA1) { + if (data_length < Opcode.map.OP_PUSHDATA1) { buf = new Buffer(1); buf.writeUInt8(data_length, 0); } else if (data_length <= 0xff) { buf = new Buffer(1 + 1); - buf.writeUInt8(OP_PUSHDATA1, 0); + buf.writeUInt8(Opcode.map.OP_PUSHDATA1, 0); buf.writeUInt8(data_length, 1); } else if (data_length <= 0xffff) { buf = new Buffer(1 + 2); - buf.writeUInt8(OP_PUSHDATA2, 0); + buf.writeUInt8(Opcode.map.OP_PUSHDATA2, 0); buf.writeUInt16LE(data_length, 1); } else { buf = new Buffer(1 + 4); - buf.writeUInt8(OP_PUSHDATA4, 0); + buf.writeUInt8(Opcode.map.OP_PUSHDATA4, 0); buf.writeUInt32LE(data_length, 1); } @@ -469,7 +464,7 @@ Script.prototype.findAndDelete = function(chunk) { Script.createPubKeyOut = function(pubkey) { var script = new Script(); script.writeBytes(pubkey); - script.writeOp(OP_CHECKSIG); + script.writeOp(Opcode.map.OP_CHECKSIG); return script; }; @@ -478,11 +473,11 @@ Script.createPubKeyOut = function(pubkey) { */ Script.createPubKeyHashOut = function(pubKeyHash) { var script = new Script(); - script.writeOp(OP_DUP); - script.writeOp(OP_HASH160); + script.writeOp(Opcode.map.OP_DUP); + script.writeOp(Opcode.map.OP_HASH160); script.writeBytes(pubKeyHash); - script.writeOp(OP_EQUALVERIFY); - script.writeOp(OP_CHECKSIG); + script.writeOp(Opcode.map.OP_EQUALVERIFY); + script.writeOp(Opcode.map.OP_CHECKSIG); return script; }; @@ -514,15 +509,15 @@ Script.createMultisig = function(n_required, inKeys, opts) { script.writeBytes(key); }); script.writeN(keys.length); - script.writeOp(OP_CHECKMULTISIG); + script.writeOp(Opcode.map.OP_CHECKMULTISIG); return script; }; Script.createP2SH = function(scriptHash) { var script = new Script(); - script.writeOp(OP_HASH160); + script.writeOp(Opcode.map.OP_HASH160); script.writeBytes(scriptHash); - script.writeOp(OP_EQUAL); + script.writeOp(Opcode.map.OP_EQUAL); return script; }; @@ -626,16 +621,16 @@ Script.chunksToBuffer = function(chunks) { for (var i = 0, l = chunks.length; i < l; i++) { var data = chunks[i]; if (Buffer.isBuffer(data)) { - if (data.length < OP_PUSHDATA1) { + if (data.length < Opcode.map.OP_PUSHDATA1) { buf.word8(data.length); } else if (data.length <= 0xff) { - buf.word8(OP_PUSHDATA1); + buf.word8(Opcode.map.OP_PUSHDATA1); buf.word8(data.length); } else if (data.length <= 0xffff) { - buf.word8(OP_PUSHDATA2); + buf.word8(Opcode.map.OP_PUSHDATA2); buf.word16le(data.length); } else { - buf.word8(OP_PUSHDATA4); + buf.word8(Opcode.map.OP_PUSHDATA4); buf.word32le(data.length); } buf.put(data); diff --git a/lib/ScriptInterpreter.js b/lib/ScriptInterpreter.js index 51e0f7d..3bb72d5 100644 --- a/lib/ScriptInterpreter.js +++ b/lib/ScriptInterpreter.js @@ -14,11 +14,6 @@ var SIGHASH_NONE = 2; var SIGHASH_SINGLE = 3; var SIGHASH_ANYONECANPAY = 80; -// Make opcodes available as pseudo-constants -for (var i in Opcode.map) { - eval(i + " = " + Opcode.map[i] + ";"); -} - var intToBufferSM = Util.intToBufferSM var bufferSMToInt = Util.bufferSMToInt; @@ -74,101 +69,101 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, throw new Error("Max push value size exceeded (>520)"); } - if (opcode > OP_16 && ++opCount > 201) { + if (opcode > Opcode.map.OP_16 && ++opCount > 201) { throw new Error("Opcode limit exceeded (>200)"); } if (this.disableUnsafeOpcodes && "number" === typeof opcode && - (opcode === OP_CAT || - opcode === OP_SUBSTR || - opcode === OP_LEFT || - opcode === OP_RIGHT || - opcode === OP_INVERT || - opcode === OP_AND || - opcode === OP_OR || - opcode === OP_XOR || - opcode === OP_2MUL || - opcode === OP_2DIV || - opcode === OP_MUL || - opcode === OP_DIV || - opcode === OP_MOD || - opcode === OP_LSHIFT || - opcode === OP_RSHIFT)) { + (opcode === Opcode.map.OP_CAT || + opcode === Opcode.map.OP_SUBSTR || + opcode === Opcode.map.OP_LEFT || + opcode === Opcode.map.OP_RIGHT || + opcode === Opcode.map.OP_INVERT || + opcode === Opcode.map.OP_AND || + opcode === Opcode.map.OP_OR || + opcode === Opcode.map.OP_XOR || + opcode === Opcode.map.OP_2MUL || + opcode === Opcode.map.OP_2DIV || + opcode === Opcode.map.OP_MUL || + opcode === Opcode.map.OP_DIV || + opcode === Opcode.map.OP_MOD || + opcode === Opcode.map.OP_LSHIFT || + opcode === Opcode.map.OP_RSHIFT)) { throw new Error("Encountered a disabled opcode"); } if (exec && Buffer.isBuffer(opcode)) { this.stack.push(opcode); - } else if (exec || (OP_IF <= opcode && opcode <= OP_ENDIF)) + } else if (exec || (Opcode.map.OP_IF <= opcode && opcode <= Opcode.map.OP_ENDIF)) switch (opcode) { - case OP_0: + case Opcode.map.OP_0: this.stack.push(new Buffer([])); break; - case OP_1NEGATE: - case OP_1: - case OP_2: - case OP_3: - case OP_4: - case OP_5: - case OP_6: - case OP_7: - case OP_8: - case OP_9: - case OP_10: - case OP_11: - case OP_12: - case OP_13: - case OP_14: - case OP_15: - case OP_16: - var opint = opcode - OP_1 + 1; + case Opcode.map.OP_1NEGATE: + case Opcode.map.OP_1: + case Opcode.map.OP_2: + case Opcode.map.OP_3: + case Opcode.map.OP_4: + case Opcode.map.OP_5: + case Opcode.map.OP_6: + case Opcode.map.OP_7: + case Opcode.map.OP_8: + case Opcode.map.OP_9: + case Opcode.map.OP_10: + case Opcode.map.OP_11: + case Opcode.map.OP_12: + case Opcode.map.OP_13: + case Opcode.map.OP_14: + case Opcode.map.OP_15: + case Opcode.map.OP_16: + var opint = opcode - Opcode.map.OP_1 + 1; var opbuf = intToBufferSM(opint); this.stack.push(opbuf); break; - case OP_NOP: - case OP_NOP1: - case OP_NOP2: - case OP_NOP3: - case OP_NOP4: - case OP_NOP5: - case OP_NOP6: - case OP_NOP7: - case OP_NOP8: - case OP_NOP9: - case OP_NOP10: + case Opcode.map.OP_NOP: + case Opcode.map.OP_NOP1: + case Opcode.map.OP_NOP2: + case Opcode.map.OP_NOP3: + case Opcode.map.OP_NOP4: + case Opcode.map.OP_NOP5: + case Opcode.map.OP_NOP6: + case Opcode.map.OP_NOP7: + case Opcode.map.OP_NOP8: + case Opcode.map.OP_NOP9: + case Opcode.map.OP_NOP10: break; - case OP_IF: - case OP_NOTIF: + case Opcode.map.OP_IF: + case Opcode.map.OP_NOTIF: // if [statements] [else [statements]] endif var value = false; if (exec) { value = castBool(this.stackPop()); - if (opcode === OP_NOTIF) { + if (opcode === Opcode.map.OP_NOTIF) { value = !value; } } execStack.push(value); break; - case OP_ELSE: + case Opcode.map.OP_ELSE: if (execStack.length < 1) { throw new Error("Unmatched OP_ELSE"); } execStack[execStack.length - 1] = !execStack[execStack.length - 1]; break; - case OP_ENDIF: + case Opcode.map.OP_ENDIF: if (execStack.length < 1) { throw new Error("Unmatched OP_ENDIF"); } execStack.pop(); break; - case OP_VERIFY: + case Opcode.map.OP_VERIFY: var value = castBool(this.stackTop()); if (value) { this.stackPop(); @@ -177,27 +172,27 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, } break; - case OP_RETURN: + case Opcode.map.OP_RETURN: throw new Error("OP_RETURN"); - case OP_TOALTSTACK: + case Opcode.map.OP_TOALTSTACK: altStack.push(this.stackPop()); break; - case OP_FROMALTSTACK: + case Opcode.map.OP_FROMALTSTACK: if (altStack.length < 1) { throw new Error("OP_FROMALTSTACK with alt stack empty"); } this.stack.push(altStack.pop()); break; - case OP_2DROP: + case Opcode.map.OP_2DROP: // (x1 x2 -- ) this.stackPop(); this.stackPop(); break; - case OP_2DUP: + case Opcode.map.OP_2DUP: // (x1 x2 -- x1 x2 x1 x2) var v1 = this.stackTop(2); var v2 = this.stackTop(1); @@ -205,7 +200,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(v2); break; - case OP_3DUP: + case Opcode.map.OP_3DUP: // (x1 x2 -- x1 x2 x1 x2) var v1 = this.stackTop(3); var v2 = this.stackTop(2); @@ -215,7 +210,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(v3); break; - case OP_2OVER: + case Opcode.map.OP_2OVER: // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) var v1 = this.stackTop(4); var v2 = this.stackTop(3); @@ -223,7 +218,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(v2); break; - case OP_2ROT: + case Opcode.map.OP_2ROT: // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) var v1 = this.stackTop(6); var v2 = this.stackTop(5); @@ -232,13 +227,13 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(v2); break; - case OP_2SWAP: + case Opcode.map.OP_2SWAP: // (x1 x2 x3 x4 -- x3 x4 x1 x2) this.stackSwap(4, 2); this.stackSwap(3, 1); break; - case OP_IFDUP: + case Opcode.map.OP_IFDUP: // (x - 0 | x x) var value = this.stackTop(); if (castBool(value)) { @@ -246,23 +241,23 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, } break; - case OP_DEPTH: + case Opcode.map.OP_DEPTH: // -- stacksize var value = bignum(this.stack.length); this.stack.push(intToBufferSM(value)); break; - case OP_DROP: + case Opcode.map.OP_DROP: // (x -- ) this.stackPop(); break; - case OP_DUP: + case Opcode.map.OP_DUP: // (x -- x x) this.stack.push(this.stackTop()); break; - case OP_NIP: + case Opcode.map.OP_NIP: // (x1 x2 -- x2) if (this.stack.length < 2) { throw new Error("OP_NIP insufficient stack size"); @@ -270,13 +265,13 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.splice(this.stack.length - 2, 1); break; - case OP_OVER: + case Opcode.map.OP_OVER: // (x1 x2 -- x1 x2 x1) this.stack.push(this.stackTop(2)); break; - case OP_PICK: - case OP_ROLL: + case Opcode.map.OP_PICK: + case Opcode.map.OP_ROLL: // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) var n = castInt(this.stackPop()); @@ -284,13 +279,13 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, throw new Error("OP_PICK/OP_ROLL insufficient stack size"); } var value = this.stackTop(n + 1); - if (opcode === OP_ROLL) { + if (opcode === Opcode.map.OP_ROLL) { this.stack.splice(this.stack.length - n - 1, 1); } this.stack.push(value); break; - case OP_ROT: + case Opcode.map.OP_ROT: // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap @@ -298,12 +293,12 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stackSwap(2, 1); break; - case OP_SWAP: + case Opcode.map.OP_SWAP: // (x1 x2 -- x2 x1) this.stackSwap(2, 1); break; - case OP_TUCK: + case Opcode.map.OP_TUCK: // (x1 x2 -- x2 x1 x2) if (this.stack.length < 2) { throw new Error("OP_TUCK insufficient stack size"); @@ -311,7 +306,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.splice(this.stack.length - 2, 0, this.stackTop()); break; - case OP_CAT: + case Opcode.map.OP_CAT: // (x1 x2 -- out) var v1 = this.stackTop(2); var v2 = this.stackTop(1); @@ -320,7 +315,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(Buffer.concat([v1, v2])); break; - case OP_SUBSTR: + case Opcode.map.OP_SUBSTR: // (in begin size -- out) var buf = this.stackTop(3); var start = castInt(this.stackTop(2)); @@ -336,8 +331,8 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack[this.stack.length - 1] = buf.slice(start, start + len); break; - case OP_LEFT: - case OP_RIGHT: + case Opcode.map.OP_LEFT: + case Opcode.map.OP_RIGHT: // (in size -- out) var buf = this.stackTop(2); var size = castInt(this.stackTop(1)); @@ -348,20 +343,20 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, size = buf.length; } this.stackPop(); - if (opcode === OP_LEFT) { + if (opcode === Opcode.map.OP_LEFT) { this.stack[this.stack.length - 1] = buf.slice(0, size); } else { this.stack[this.stack.length - 1] = buf.slice(buf.length - size); } break; - case OP_SIZE: + case Opcode.map.OP_SIZE: // (in -- in size) var value = bignum(this.stackTop().length); this.stack.push(intToBufferSM(value)); break; - case OP_INVERT: + case Opcode.map.OP_INVERT: // (in - out) var buf = this.stackTop(); for (var i = 0, l = buf.length; i < l; i++) { @@ -369,24 +364,24 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, } break; - case OP_AND: - case OP_OR: - case OP_XOR: + case Opcode.map.OP_AND: + case Opcode.map.OP_OR: + case Opcode.map.OP_XOR: // (x1 x2 - out) var v1 = this.stackTop(2); var v2 = this.stackTop(1); this.stackPop(); this.stackPop(); var out = new Buffer(Math.max(v1.length, v2.length)); - if (opcode === OP_AND) { + if (opcode === Opcode.map.OP_AND) { for (var i = 0, l = out.length; i < l; i++) { out[i] = v1[i] & v2[i]; } - } else if (opcode === OP_OR) { + } else if (opcode === Opcode.map.OP_OR) { for (var i = 0, l = out.length; i < l; i++) { out[i] = v1[i] | v2[i]; } - } else if (opcode === OP_XOR) { + } else if (opcode === Opcode.map.OP_XOR) { for (var i = 0, l = out.length; i < l; i++) { out[i] = v1[i] ^ v2[i]; } @@ -394,8 +389,8 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(out); break; - case OP_EQUAL: - case OP_EQUALVERIFY: + case Opcode.map.OP_EQUAL: + case Opcode.map.OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL // (x1 x2 - bool) var v1 = this.stackTop(2); @@ -412,7 +407,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stackPop(); this.stackPop(); this.stack.push(new Buffer([value ? 1 : 0])); - if (opcode === OP_EQUALVERIFY) { + if (opcode === Opcode.map.OP_EQUALVERIFY) { if (value) { this.stackPop(); } else { @@ -421,136 +416,136 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, } break; - case OP_1ADD: - case OP_1SUB: - case OP_2MUL: - case OP_2DIV: - case OP_NEGATE: - case OP_ABS: - case OP_NOT: - case OP_0NOTEQUAL: + case Opcode.map.OP_1ADD: + case Opcode.map.OP_1SUB: + case Opcode.map.OP_2MUL: + case Opcode.map.OP_2DIV: + case Opcode.map.OP_NEGATE: + case Opcode.map.OP_ABS: + case Opcode.map.OP_NOT: + case Opcode.map.OP_0NOTEQUAL: // (in -- out) var num = bufferSMToInt(this.stackTop()); switch (opcode) { - case OP_1ADD: + case Opcode.map.OP_1ADD: num = num.add(bignum(1)); break; - case OP_1SUB: + case Opcode.map.OP_1SUB: num = num.sub(bignum(1)); break; - case OP_2MUL: + case Opcode.map.OP_2MUL: num = num.mul(bignum(2)); break; - case OP_2DIV: + case Opcode.map.OP_2DIV: num = num.div(bignum(2)); break; - case OP_NEGATE: + case Opcode.map.OP_NEGATE: num = num.neg(); break; - case OP_ABS: + case Opcode.map.OP_ABS: num = num.abs(); break; - case OP_NOT: + case Opcode.map.OP_NOT: num = bignum(num.cmp(0) == 0 ? 1 : 0); break; - case OP_0NOTEQUAL: + case Opcode.map.OP_0NOTEQUAL: num = bignum(num.cmp(0) == 0 ? 0 : 1); break; } this.stack[this.stack.length - 1] = intToBufferSM(num); break; - case OP_ADD: - case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_MOD: - case OP_LSHIFT: - case OP_RSHIFT: - case OP_BOOLAND: - case OP_BOOLOR: - case OP_NUMEQUAL: - case OP_NUMEQUALVERIFY: - case OP_NUMNOTEQUAL: - case OP_LESSTHAN: - case OP_GREATERTHAN: - case OP_LESSTHANOREQUAL: - case OP_GREATERTHANOREQUAL: - case OP_MIN: - case OP_MAX: + case Opcode.map.OP_ADD: + case Opcode.map.OP_SUB: + case Opcode.map.OP_MUL: + case Opcode.map.OP_DIV: + case Opcode.map.OP_MOD: + case Opcode.map.OP_LSHIFT: + case Opcode.map.OP_RSHIFT: + case Opcode.map.OP_BOOLAND: + case Opcode.map.OP_BOOLOR: + case Opcode.map.OP_NUMEQUAL: + case Opcode.map.OP_NUMEQUALVERIFY: + case Opcode.map.OP_NUMNOTEQUAL: + case Opcode.map.OP_LESSTHAN: + case Opcode.map.OP_GREATERTHAN: + case Opcode.map.OP_LESSTHANOREQUAL: + case Opcode.map.OP_GREATERTHANOREQUAL: + case Opcode.map.OP_MIN: + case Opcode.map.OP_MAX: // (x1 x2 -- out) var v1 = bufferSMToInt(this.stackTop(2)); var v2 = bufferSMToInt(this.stackTop(1)); var num; switch (opcode) { - case OP_ADD: + case Opcode.map.OP_ADD: num = v1.add(v2); break; - case OP_SUB: + case Opcode.map.OP_SUB: num = v1.sub(v2); break; - case OP_MUL: + case Opcode.map.OP_MUL: num = v1.mul(v2); break; - case OP_DIV: + case Opcode.map.OP_DIV: num = v1.div(v2); break; - case OP_MOD: + case Opcode.map.OP_MOD: num = v1.mod(v2); break; - case OP_LSHIFT: + case Opcode.map.OP_LSHIFT: if (v2.cmp(0) < 0 || v2.cmp(2048) > 0) { throw new Error("OP_LSHIFT parameter out of bounds"); } num = v1.shiftLeft(v2); break; - case OP_RSHIFT: + case Opcode.map.OP_RSHIFT: if (v2.cmp(0) < 0 || v2.cmp(2048) > 0) { throw new Error("OP_RSHIFT parameter out of bounds"); } num = v1.shiftRight(v2); break; - case OP_BOOLAND: + case Opcode.map.OP_BOOLAND: num = bignum((v1.cmp(0) != 0 && v2.cmp(0) != 0) ? 1 : 0); break; - case OP_BOOLOR: + case Opcode.map.OP_BOOLOR: num = bignum((v1.cmp(0) != 0 || v2.cmp(0) != 0) ? 1 : 0); break; - case OP_NUMEQUAL: - case OP_NUMEQUALVERIFY: + case Opcode.map.OP_NUMEQUAL: + case Opcode.map.OP_NUMEQUALVERIFY: num = bignum(v1.cmp(v2) == 0 ? 1 : 0); break; - case OP_NUMNOTEQUAL: + case Opcode.map.OP_NUMNOTEQUAL: ; num = bignum(v1.cmp(v2) != 0 ? 1 : 0); break; - case OP_LESSTHAN: + case Opcode.map.OP_LESSTHAN: num = bignum(v1.lt(v2) ? 1 : 0); break; - case OP_GREATERTHAN: + case Opcode.map.OP_GREATERTHAN: num = bignum(v1.gt(v2) ? 1 : 0); break; - case OP_LESSTHANOREQUAL: + case Opcode.map.OP_LESSTHANOREQUAL: num = bignum(v1.gt(v2) ? 0 : 1); break; - case OP_GREATERTHANOREQUAL: + case Opcode.map.OP_GREATERTHANOREQUAL: num = bignum(v1.lt(v2) ? 0 : 1); break; - case OP_MIN: + case Opcode.map.OP_MIN: num = (v1.lt(v2) ? v1 : v2); break; - case OP_MAX: + case Opcode.map.OP_MAX: num = (v1.gt(v2) ? v1 : v2); break; } @@ -558,7 +553,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stackPop(); this.stack.push(intToBufferSM(num)); - if (opcode === OP_NUMEQUALVERIFY) { + if (opcode === Opcode.map.OP_NUMEQUALVERIFY) { if (castBool(this.stackTop())) { this.stackPop(); } else { @@ -567,7 +562,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, } break; - case OP_WITHIN: + case Opcode.map.OP_WITHIN: // (x min max -- out) var v1 = bufferSMToInt(this.stackTop(3)); var v2 = bufferSMToInt(this.stackTop(2)); @@ -579,35 +574,35 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stack.push(intToBufferSM(value ? 1 : 0)); break; - case OP_RIPEMD160: - case OP_SHA1: - case OP_SHA256: - case OP_HASH160: - case OP_HASH256: + case Opcode.map.OP_RIPEMD160: + case Opcode.map.OP_SHA1: + case Opcode.map.OP_SHA256: + case Opcode.map.OP_HASH160: + case Opcode.map.OP_HASH256: // (in -- hash) var value = this.stackPop(); var hash; - if (opcode === OP_RIPEMD160) { + if (opcode === Opcode.map.OP_RIPEMD160) { hash = Util.ripe160(value); - } else if (opcode === OP_SHA1) { + } else if (opcode === Opcode.map.OP_SHA1) { hash = Util.sha1(value); - } else if (opcode === OP_SHA256) { + } else if (opcode === Opcode.map.OP_SHA256) { hash = Util.sha256(value); - } else if (opcode === OP_HASH160) { + } else if (opcode === Opcode.map.OP_HASH160) { hash = Util.sha256ripe160(value); - } else if (opcode === OP_HASH256) { + } else if (opcode === Opcode.map.OP_HASH256) { hash = Util.twoSha256(value); } this.stack.push(hash); break; - case OP_CODESEPARATOR: + case Opcode.map.OP_CODESEPARATOR: // Hash starts after the code separator hashStart = pc; break; - case OP_CHECKSIG: - case OP_CHECKSIGVERIFY: + case Opcode.map.OP_CHECKSIG: + case Opcode.map.OP_CHECKSIGVERIFY: // (sig pubkey -- bool) var sig = this.stackTop(2); var pubkey = this.stackTop(1); @@ -640,7 +635,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, this.stackPop(); this.stackPop(); this.stack.push(new Buffer([success ? 1 : 0])); - if (opcode === OP_CHECKSIGVERIFY) { + if (opcode === Opcode.map.OP_CHECKSIGVERIFY) { if (success) { this.stackPop(); } else { @@ -656,8 +651,8 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, // the next opcode from being executed. return; - case OP_CHECKMULTISIG: - case OP_CHECKMULTISIGVERIFY: + case Opcode.map.OP_CHECKMULTISIG: + case Opcode.map.OP_CHECKMULTISIGVERIFY: // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) var keysCount = castInt(this.stackPop()); if (keysCount < 0 || keysCount > 20) { @@ -729,7 +724,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, }.bind(this)); } else { this.stack.push(new Buffer([success ? 1 : 0])); - if (opcode === OP_CHECKMULTISIGVERIFY) { + if (opcode === Opcode.map.OP_CHECKMULTISIGVERIFY) { if (success) { this.stackPop(); } else { diff --git a/test/test.Opcode.js b/test/test.Opcode.js index 9a0ea66..b447b88 100644 --- a/test/test.Opcode.js +++ b/test/test.Opcode.js @@ -21,16 +21,12 @@ describe('Opcode', function() { should.exist(oc); }); it('should be able to create some constants', function() { - // TODO: test works in node but not in browser - for (var i in Opcode.map) { - eval('var ' + i + ' = ' + Opcode.map[i] + ';'); - } - should.exist(OP_VER); - should.exist(OP_HASH160); - should.exist(OP_RETURN); - should.exist(OP_EQUALVERIFY); - should.exist(OP_CHECKSIG); - should.exist(OP_CHECKMULTISIG); + should.exist(Opcode.map.OP_VER); + should.exist(Opcode.map.OP_HASH160); + should.exist(Opcode.map.OP_RETURN); + should.exist(Opcode.map.OP_EQUALVERIFY); + should.exist(Opcode.map.OP_CHECKSIG); + should.exist(Opcode.map.OP_CHECKMULTISIG); }); it('#asList should work', function() { var list = Opcode.asList();