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.
This commit is contained in:
Ryan X. Charles 2014-05-05 10:43:24 -04:00
parent 0e04026d87
commit d3a4cfa333
3 changed files with 201 additions and 215 deletions

View File

@ -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);

View File

@ -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:
// <expression> 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 {

View File

@ -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();