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:
parent
0e04026d87
commit
d3a4cfa333
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue