accurate scripting error messages.
This commit is contained in:
parent
4d7124830a
commit
ce0c6f4fc7
@ -587,7 +587,7 @@ Stack.prototype._swap = function _swap(i1, i2) {
|
||||
|
||||
Stack.prototype.toalt = function toalt() {
|
||||
if (this.length === 0)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_TOALTSTACK);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_TOALTSTACK);
|
||||
|
||||
this.alt.push(this.pop());
|
||||
};
|
||||
@ -599,7 +599,7 @@ Stack.prototype.toalt = function toalt() {
|
||||
|
||||
Stack.prototype.fromalt = function fromalt() {
|
||||
if (this.alt.length === 0)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_FROMALTSTACK);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_FROMALTSTACK);
|
||||
|
||||
this.push(this.alt.pop());
|
||||
};
|
||||
@ -611,7 +611,7 @@ Stack.prototype.fromalt = function fromalt() {
|
||||
|
||||
Stack.prototype.ifdup = function ifdup() {
|
||||
if (this.length === 0)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_IFDUP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_IFDUP);
|
||||
|
||||
if (Script.bool(this.top(-1)))
|
||||
this.push(Script.array(this.top(-1)));
|
||||
@ -633,7 +633,7 @@ Stack.prototype.depth = function depth() {
|
||||
|
||||
Stack.prototype.drop = function drop() {
|
||||
if (this.length === 0)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_DROP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_DROP);
|
||||
|
||||
this.pop();
|
||||
};
|
||||
@ -645,7 +645,7 @@ Stack.prototype.drop = function drop() {
|
||||
|
||||
Stack.prototype.dup = function dup() {
|
||||
if (this.length === 0)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_DUP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_DUP);
|
||||
|
||||
this.push(this.top(-1));
|
||||
};
|
||||
@ -657,7 +657,7 @@ Stack.prototype.dup = function dup() {
|
||||
|
||||
Stack.prototype.nip = function nip() {
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_NIP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_NIP);
|
||||
|
||||
this.splice(this.length - 2, 1);
|
||||
};
|
||||
@ -669,7 +669,7 @@ Stack.prototype.nip = function nip() {
|
||||
|
||||
Stack.prototype.over = function over() {
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_OVER);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_OVER);
|
||||
|
||||
this.push(this.top(-2));
|
||||
};
|
||||
@ -698,13 +698,13 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
|
||||
var val, n;
|
||||
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', op);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op);
|
||||
|
||||
val = this.pop();
|
||||
n = Script.num(val, flags).toNumber();
|
||||
|
||||
if (n < 0 || n >= this.length)
|
||||
throw new ScriptError('Bad value.', op);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op);
|
||||
|
||||
val = this.top(-n - 1);
|
||||
|
||||
@ -721,7 +721,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
|
||||
|
||||
Stack.prototype.rot = function rot() {
|
||||
if (this.length < 3)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_ROT);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_ROT);
|
||||
|
||||
this._swap(-3, -2);
|
||||
this._swap(-2, -1);
|
||||
@ -734,7 +734,7 @@ Stack.prototype.rot = function rot() {
|
||||
|
||||
Stack.prototype.swap = function swap() {
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_SWAP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_SWAP);
|
||||
|
||||
this._swap(-2, -1);
|
||||
};
|
||||
@ -746,7 +746,7 @@ Stack.prototype.swap = function swap() {
|
||||
|
||||
Stack.prototype.tuck = function tuck() {
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_TUCK);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_TUCK);
|
||||
|
||||
this.splice(this.length - 2, 0, this.top(-1));
|
||||
};
|
||||
@ -758,7 +758,7 @@ Stack.prototype.tuck = function tuck() {
|
||||
|
||||
Stack.prototype.drop2 = function drop2() {
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_2DROP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2DROP);
|
||||
|
||||
this.pop();
|
||||
this.pop();
|
||||
@ -773,7 +773,7 @@ Stack.prototype.dup2 = function dup2() {
|
||||
var v1, v2;
|
||||
|
||||
if (this.length < 2)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_2DUP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2DUP);
|
||||
|
||||
v1 = this.top(-2);
|
||||
v2 = this.top(-1);
|
||||
@ -791,7 +791,7 @@ Stack.prototype.dup3 = function dup3() {
|
||||
var v1, v2, v3;
|
||||
|
||||
if (this.length < 3)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_3DUP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_3DUP);
|
||||
|
||||
v1 = this.top(-3);
|
||||
v2 = this.top(-2);
|
||||
@ -811,7 +811,7 @@ Stack.prototype.over2 = function over2() {
|
||||
var v1, v2;
|
||||
|
||||
if (this.length < 4)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_2OVER);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2OVER);
|
||||
|
||||
v1 = this.top(-4);
|
||||
v2 = this.top(-3);
|
||||
@ -829,7 +829,7 @@ Stack.prototype.rot2 = function rot2() {
|
||||
var v1, v2;
|
||||
|
||||
if (this.length < 6)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_2ROT);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2ROT);
|
||||
|
||||
v1 = this.top(-6);
|
||||
v2 = this.top(-5);
|
||||
@ -846,7 +846,7 @@ Stack.prototype.rot2 = function rot2() {
|
||||
|
||||
Stack.prototype.swap2 = function swap2() {
|
||||
if (this.length < 4)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_2SWAP);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2SWAP);
|
||||
|
||||
this._swap(-4, -2);
|
||||
this._swap(-3, -1);
|
||||
@ -859,7 +859,7 @@ Stack.prototype.swap2 = function swap2() {
|
||||
|
||||
Stack.prototype.size = function size() {
|
||||
if (this.length < 1)
|
||||
throw new ScriptError('Stack too small.', opcodes.OP_SIZE);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_SIZE);
|
||||
|
||||
this.push(Script.array(this.top(-1).length));
|
||||
};
|
||||
@ -1064,28 +1064,28 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
stack.negate = 0;
|
||||
|
||||
if (this.getSize() > constants.script.MAX_SIZE)
|
||||
throw new ScriptError('Script too large.');
|
||||
throw new ScriptError('SCRIPT_SIZE', null, -1);
|
||||
|
||||
for (ip = 0; ip < this.code.length; ip++) {
|
||||
op = this.code[ip];
|
||||
|
||||
if (Buffer.isBuffer(op)) {
|
||||
if (!Script.checkPush(op))
|
||||
throw new ScriptError('Pushdata out of range.', op, ip);
|
||||
throw new ScriptError('BAD_OPCODE', op, ip);
|
||||
if (op.length > constants.script.MAX_PUSH)
|
||||
throw new ScriptError('Pushdata too large.', op, ip);
|
||||
throw new ScriptError('PUSH_SIZE', op, ip);
|
||||
// Note that minimaldata is not checked
|
||||
// on unexecuted branches of code.
|
||||
if (stack.negate === 0) {
|
||||
if (!Script.checkMinimal(op, flags))
|
||||
throw new ScriptError('Push verification failed.', op, ip);
|
||||
throw new ScriptError('MINIMALDATA', op, ip);
|
||||
stack.push(op);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op > opcodes.OP_16 && ++opCount > constants.script.MAX_OPS)
|
||||
throw new ScriptError('Too many opcodes.', op, ip);
|
||||
throw new ScriptError('OP_COUNT', op, ip);
|
||||
|
||||
// It's very important to make a distiction
|
||||
// here: these opcodes will fail _even if they
|
||||
@ -1107,7 +1107,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
|| op == opcodes.OP_MOD
|
||||
|| op == opcodes.OP_LSHIFT
|
||||
|| op == opcodes.OP_RSHIFT) {
|
||||
throw new ScriptError('Disabled opcode.', op, ip);
|
||||
throw new ScriptError('DISABLED_OPCODE', op, ip);
|
||||
}
|
||||
|
||||
if (op >= opcodes.OP_IF && op <= opcodes.OP_ENDIF) {
|
||||
@ -1116,7 +1116,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_NOTIF: {
|
||||
if (stack.negate === 0) {
|
||||
if (stack.length < 1)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
|
||||
val = Script.bool(stack.pop());
|
||||
if (op === opcodes.OP_NOTIF)
|
||||
val = !val;
|
||||
@ -1131,7 +1131,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
}
|
||||
case opcodes.OP_ELSE: {
|
||||
if (stack.state.length === 0)
|
||||
throw new ScriptError('Unexpected else.', op, ip);
|
||||
throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
|
||||
stack.state[stack.state.length - 1] ^= 1;
|
||||
if (stack.state[stack.state.length - 1] === 0)
|
||||
stack.negate++;
|
||||
@ -1141,14 +1141,14 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
}
|
||||
case opcodes.OP_ENDIF: {
|
||||
if (stack.state.length === 0)
|
||||
throw new ScriptError('Unexpected endif.', op, ip);
|
||||
throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
|
||||
if (stack.state.pop() === 0)
|
||||
stack.negate--;
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_VERIF:
|
||||
case opcodes.OP_VERNOTIF: {
|
||||
throw new ScriptError('Unknown opcode.', op, ip);
|
||||
throw new ScriptError('BAD_OPCODE', op, ip);
|
||||
}
|
||||
default: {
|
||||
assert.fatal(false, 'Fatal script error.');
|
||||
@ -1160,24 +1160,92 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
if (stack.negate !== 0)
|
||||
continue;
|
||||
|
||||
if (op === opcodes.OP_0) {
|
||||
stack.push(STACK_FALSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op >= opcodes.OP_1 && op <= opcodes.OP_16) {
|
||||
stack.push(new Buffer([op - 0x50]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op === opcodes.OP_1NEGATE) {
|
||||
stack.push(STACK_NEGATE);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case opcodes.OP_NOP:
|
||||
case opcodes.OP_0: {
|
||||
stack.push(STACK_FALSE);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_1NEGATE: {
|
||||
stack.push(STACK_NEGATE);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_1:
|
||||
case opcodes.OP_2:
|
||||
case opcodes.OP_3:
|
||||
case opcodes.OP_4:
|
||||
case opcodes.OP_5:
|
||||
case opcodes.OP_6:
|
||||
case opcodes.OP_7:
|
||||
case opcodes.OP_8:
|
||||
case opcodes.OP_9:
|
||||
case opcodes.OP_10:
|
||||
case opcodes.OP_11:
|
||||
case opcodes.OP_12:
|
||||
case opcodes.OP_13:
|
||||
case opcodes.OP_14:
|
||||
case opcodes.OP_15:
|
||||
case opcodes.OP_16: {
|
||||
stack.push(new Buffer([op - 0x50]));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_NOP: {
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKLOCKTIMEVERIFY: {
|
||||
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
||||
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
throw new ScriptError('DISCOURAGE_UPGRADABLE_NOPS', op, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('NO_TX', op, ip);
|
||||
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), flags, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
|
||||
|
||||
locktime = locktime.uand(utils.U32).toNumber();
|
||||
|
||||
if (!Script.checkLocktime(locktime, tx, index))
|
||||
throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKSEQUENCEVERIFY: {
|
||||
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
|
||||
if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
throw new ScriptError('DISCOURAGE_UPGRADABLE_NOPS', op, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('NO_TX', op, ip);
|
||||
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), flags, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
|
||||
|
||||
locktime = locktime.uand(utils.U32).toNumber();
|
||||
|
||||
if ((locktime & constants.sequence.DISABLE_FLAG) !== 0)
|
||||
break;
|
||||
|
||||
if (!Script.checkSequence(locktime, tx, index))
|
||||
throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_NOP1:
|
||||
case opcodes.OP_NOP4:
|
||||
case opcodes.OP_NOP5:
|
||||
@ -1187,18 +1255,18 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_NOP9:
|
||||
case opcodes.OP_NOP10: {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||
throw new ScriptError('DISCOURAGE_UPGRADABLE_NOPS', op, ip);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_VERIFY: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
if (!Script.bool(stack.pop()))
|
||||
throw new ScriptError('Verification failed.', op, ip);
|
||||
throw new ScriptError('VERIFY', op, ip);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_RETURN: {
|
||||
throw new ScriptError('Script returned.', op, ip);
|
||||
throw new ScriptError('OP_RETURN', op, ip);
|
||||
}
|
||||
case opcodes.OP_TOALTSTACK: {
|
||||
stack.toalt();
|
||||
@ -1208,6 +1276,30 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
stack.fromalt();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2DROP: {
|
||||
stack.drop2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2DUP: {
|
||||
stack.dup2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_3DUP: {
|
||||
stack.dup3();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2OVER: {
|
||||
stack.over2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2ROT: {
|
||||
stack.rot2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2SWAP: {
|
||||
stack.swap2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_IFDUP: {
|
||||
stack.ifdup();
|
||||
break;
|
||||
@ -1252,34 +1344,23 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
stack.tuck();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2DROP: {
|
||||
stack.drop2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2DUP: {
|
||||
stack.dup2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_3DUP: {
|
||||
stack.dup3();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2OVER: {
|
||||
stack.over2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2ROT: {
|
||||
stack.rot2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2SWAP: {
|
||||
stack.swap2();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SIZE: {
|
||||
stack.size();
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_EQUAL:
|
||||
case opcodes.OP_EQUALVERIFY: {
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
res = utils.equals(stack.pop(), stack.pop());
|
||||
if (op === opcodes.OP_EQUALVERIFY) {
|
||||
if (!res)
|
||||
throw new ScriptError('VERIFY', op, ip);
|
||||
} else {
|
||||
stack.push(res ? STACK_TRUE : STACK_FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_1ADD:
|
||||
case opcodes.OP_1SUB:
|
||||
case opcodes.OP_2MUL:
|
||||
@ -1289,7 +1370,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_NOT:
|
||||
case opcodes.OP_0NOTEQUAL: {
|
||||
if (stack.length < 1)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
n = Script.num(stack.pop(), flags);
|
||||
switch (op) {
|
||||
case opcodes.OP_1ADD:
|
||||
@ -1342,8 +1423,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_LESSTHANOREQUAL:
|
||||
case opcodes.OP_GREATERTHANOREQUAL:
|
||||
case opcodes.OP_MIN:
|
||||
case opcodes.OP_MAX:
|
||||
case opcodes.OP_WITHIN: {
|
||||
case opcodes.OP_MAX: {
|
||||
switch (op) {
|
||||
case opcodes.OP_ADD:
|
||||
case opcodes.OP_SUB:
|
||||
@ -1364,7 +1444,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_MIN:
|
||||
case opcodes.OP_MAX:
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
n2 = Script.num(stack.pop(), flags);
|
||||
n1 = Script.num(stack.pop(), flags);
|
||||
n = new bn(0);
|
||||
@ -1386,12 +1466,12 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
break;
|
||||
case opcodes.OP_LSHIFT:
|
||||
if (n2.cmpn(0) < 0 || n2.cmpn(2048) > 0)
|
||||
throw new ScriptError('Shift out of range.', op, ip);
|
||||
throw new ScriptError('BAD_SHIFT', op, ip);
|
||||
n = n1.ushln(n2.toNumber());
|
||||
break;
|
||||
case opcodes.OP_RSHIFT:
|
||||
if (n2.cmpn(0) < 0 || n2.cmpn(2048) > 0)
|
||||
throw new ScriptError('Shift out of range.', op, ip);
|
||||
throw new ScriptError('BAD_SHIFT', op, ip);
|
||||
n = n1.ushrn(n2.toNumber());
|
||||
break;
|
||||
case opcodes.OP_BOOLAND:
|
||||
@ -1434,78 +1514,66 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
n = new bn(n ? 1 : 0);
|
||||
if (op === opcodes.OP_NUMEQUALVERIFY) {
|
||||
if (!Script.bool(n))
|
||||
throw new ScriptError('Verify failed.', op, ip);
|
||||
throw new ScriptError('NUMEQUALVERIFY', op, ip);
|
||||
} else {
|
||||
stack.push(Script.array(n));
|
||||
}
|
||||
break;
|
||||
case opcodes.OP_WITHIN:
|
||||
if (stack.length < 3)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
n3 = Script.num(stack.pop(), flags);
|
||||
n2 = Script.num(stack.pop(), flags);
|
||||
n1 = Script.num(stack.pop(), flags);
|
||||
val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0;
|
||||
stack.push(val ? STACK_TRUE : STACK_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_WITHIN: {
|
||||
if (stack.length < 3)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
n3 = Script.num(stack.pop(), flags);
|
||||
n2 = Script.num(stack.pop(), flags);
|
||||
n1 = Script.num(stack.pop(), flags);
|
||||
val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0;
|
||||
stack.push(val ? STACK_TRUE : STACK_FALSE);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_RIPEMD160: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
stack.push(utils.ripemd160(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SHA1: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
stack.push(utils.sha1(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SHA256: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
stack.push(utils.sha256(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_HASH256: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
stack.push(utils.dsha256(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_HASH160: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
stack.push(utils.ripesha(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CODESEPARATOR: {
|
||||
lastSep = ip;
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_RIPEMD160: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
stack.push(utils.ripemd160(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SHA1: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
stack.push(utils.sha1(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SHA256: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
stack.push(utils.sha256(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_HASH256: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
stack.push(utils.dsha256(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_HASH160: {
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
stack.push(utils.ripesha(stack.pop()));
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_EQUALVERIFY:
|
||||
case opcodes.OP_EQUAL: {
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
res = utils.equals(stack.pop(), stack.pop());
|
||||
if (op === opcodes.OP_EQUALVERIFY) {
|
||||
if (!res)
|
||||
throw new ScriptError('Equal verification failed.', op, ip);
|
||||
} else {
|
||||
stack.push(res ? STACK_TRUE : STACK_FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKSIGVERIFY:
|
||||
case opcodes.OP_CHECKSIG: {
|
||||
if (!tx)
|
||||
throw new ScriptError('No TX passed in.', op, ip);
|
||||
throw new ScriptError('NO_TX', op, ip);
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
key = stack.pop();
|
||||
sig = stack.pop();
|
||||
@ -1514,11 +1582,11 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
if (version === 0)
|
||||
subscript.removeData(sig);
|
||||
|
||||
if (!Script.isValidKey(key, flags))
|
||||
throw new ScriptError('Key is not valid.', op, ip);
|
||||
|
||||
if (!Script.isValidSignature(sig, flags))
|
||||
throw new ScriptError('Signature is not valid.', op, ip);
|
||||
throw new ScriptError('SIG_DER_OR_HASHTYPE', op, ip);
|
||||
|
||||
if (!Script.isValidKey(key, flags))
|
||||
throw new ScriptError('PUBKEYTYPE', op, ip);
|
||||
|
||||
type = sig[sig.length - 1];
|
||||
|
||||
@ -1527,7 +1595,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
res = Script.checksig(hash, sig, key, flags);
|
||||
if (op === opcodes.OP_CHECKSIGVERIFY) {
|
||||
if (!res)
|
||||
throw new ScriptError('Signature verification failed.', op, ip);
|
||||
throw new ScriptError('CHECKSIGVERIFY', op, ip);
|
||||
} else {
|
||||
stack.push(res ? STACK_TRUE : STACK_FALSE);
|
||||
}
|
||||
@ -1537,40 +1605,40 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_CHECKMULTISIGVERIFY:
|
||||
case opcodes.OP_CHECKMULTISIG: {
|
||||
if (!tx)
|
||||
throw new ScriptError('No TX passed in.', op, ip);
|
||||
throw new ScriptError('NO_TX', op, ip);
|
||||
|
||||
i = 1;
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
n = Script.num(stack.top(-i), flags).toNumber();
|
||||
|
||||
if (!(n >= 0 && n <= constants.script.MAX_MULTISIG_PUBKEYS))
|
||||
throw new ScriptError('`n` is out of bounds.', op, ip);
|
||||
throw new ScriptError('PUBKEY_COUNT', op, ip);
|
||||
|
||||
opCount += n;
|
||||
|
||||
if (opCount > constants.script.MAX_OPS)
|
||||
throw new ScriptError('Too many ops.', op, ip);
|
||||
throw new ScriptError('OP_COUNT', op, ip);
|
||||
|
||||
i++;
|
||||
ikey = i;
|
||||
i += n;
|
||||
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('`n` exceeds stack size.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
m = Script.num(stack.top(-i), flags).toNumber();
|
||||
|
||||
if (!(m >= 0 && m <= n))
|
||||
throw new ScriptError('`m` is out of bounds.', op, ip);
|
||||
throw new ScriptError('SIG_COUNT', op, ip);
|
||||
|
||||
i++;
|
||||
isig = i;
|
||||
i += m;
|
||||
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('`m` exceeds stack size.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
subscript = this.getSubscript(lastSep);
|
||||
|
||||
@ -1586,10 +1654,10 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
key = stack.top(-ikey);
|
||||
|
||||
if (!Script.isValidSignature(sig, flags))
|
||||
throw new ScriptError('Signature is not valid.', op, ip);
|
||||
throw new ScriptError('SIG_DER_OR_HASHTYPE', op, ip);
|
||||
|
||||
if (!Script.isValidKey(key, flags))
|
||||
throw new ScriptError('Key is not valid.', op, ip);
|
||||
throw new ScriptError('PUBKEYTYPE', op, ip);
|
||||
|
||||
type = sig[sig.length - 1];
|
||||
hash = tx.signatureHash(index, subscript, type, version);
|
||||
@ -1610,97 +1678,42 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
stack.pop();
|
||||
|
||||
if (stack.length < 1)
|
||||
throw new ScriptError('No dummy present.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
if (flags & constants.flags.VERIFY_NULLDUMMY) {
|
||||
if (!Script.isDummy(stack.top(-1)))
|
||||
throw new ScriptError('Dummy did not verify.', op, ip);
|
||||
throw new ScriptError('VERIFY_NULLDUMMY', op, ip);
|
||||
}
|
||||
|
||||
stack.pop();
|
||||
|
||||
if (op === opcodes.OP_CHECKMULTISIGVERIFY) {
|
||||
if (!res)
|
||||
throw new ScriptError('Signature verification failed.', op, ip);
|
||||
throw new ScriptError('CHECKMULTISIGVERIFY', op, ip);
|
||||
} else {
|
||||
stack.push(res ? STACK_TRUE : STACK_FALSE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKLOCKTIMEVERIFY: {
|
||||
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
||||
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('No TX passed in.', op, ip);
|
||||
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), flags, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('Negative locktime.', op, ip);
|
||||
|
||||
locktime = locktime.uand(utils.U32).toNumber();
|
||||
|
||||
if (!Script.checkLocktime(locktime, tx, index))
|
||||
throw new ScriptError('Locktime verification failed.', op, ip);
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKSEQUENCEVERIFY: {
|
||||
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
|
||||
if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('No TX passed in.', op, ip);
|
||||
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), flags, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('Negative sequence.', op, ip);
|
||||
|
||||
locktime = locktime.uand(utils.U32).toNumber();
|
||||
|
||||
if ((locktime & constants.sequence.DISABLE_FLAG) !== 0)
|
||||
break;
|
||||
|
||||
if (!Script.checkSequence(locktime, tx, index))
|
||||
throw new ScriptError('Sequence verification failed.', op, ip);
|
||||
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CAT: {
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
v2 = stack.pop();
|
||||
v1 = stack.pop();
|
||||
stack.push(Buffer.concat([v1, v2]));
|
||||
if (stack.top(-1).length > constants.script.MAX_PUSH)
|
||||
throw new ScriptError('Push data too large.', op, ip);
|
||||
throw new ScriptError('PUSH_SIZE', op, ip);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_SUBSTR: {
|
||||
if (stack.length < 3)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
v3 = Script.num(stack.pop(), flags).toNumber(); // end
|
||||
v2 = Script.num(stack.pop(), flags).toNumber(); // begin
|
||||
v1 = stack.pop(); // string
|
||||
if (v2 < 0 || v3 < v2)
|
||||
throw new ScriptError('String begin or end out of range.', op, ip);
|
||||
throw new ScriptError('STRING_OUT_OF_RANGE', op, ip);
|
||||
if (v2 > v1.length)
|
||||
v2 = v1.length;
|
||||
if (v3 > v1.length)
|
||||
@ -1711,11 +1724,11 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_LEFT:
|
||||
case opcodes.OP_RIGHT: {
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
v2 = Script.num(stack.pop(), flags).toNumber(); // size
|
||||
v1 = stack.pop(); // string
|
||||
if (v2 < 0)
|
||||
throw new ScriptError('String size is negative.', op, ip);
|
||||
throw new ScriptError('STRING_OUT_OF_RANGE', op, ip);
|
||||
if (v2 > v1.length)
|
||||
v2 = v1.length;
|
||||
if (op === opcodes.OP_LEFT)
|
||||
@ -1727,7 +1740,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
}
|
||||
case opcodes.OP_INVERT: {
|
||||
if (stack.length < 1)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
val = utils.slice(stack.pop());
|
||||
for (i = 0; i < val.length; i++)
|
||||
val[i] = ~val[i] & 0xff;
|
||||
@ -1738,7 +1751,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
case opcodes.OP_OR:
|
||||
case opcodes.OP_XOR: {
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('Stack too small.', op, ip);
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
v2 = stack.pop();
|
||||
v1 = utils.slice(stack.pop());
|
||||
if (v1.length < v2.length) {
|
||||
@ -1765,16 +1778,16 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new ScriptError('Unknown opcode.', op, ip);
|
||||
throw new ScriptError('BAD_OPCODE', op, ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.getSize() > constants.script.MAX_STACK)
|
||||
throw new ScriptError('Stack size too large.', op, ip);
|
||||
throw new ScriptError('STACK_SIZE', op, ip);
|
||||
|
||||
if (stack.state.length !== 0)
|
||||
throw new ScriptError('Expected endif.', op, ip);
|
||||
throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -4279,33 +4292,41 @@ Script.isScript = function isScript(obj) {
|
||||
* @global
|
||||
* @constructor
|
||||
* @extends Error
|
||||
* @param {String} msg - Error message.
|
||||
* @param {String} code - Error code.
|
||||
* @param {(Number|String)?} op - Opcode.
|
||||
* @param {Number?} ip - Instruction pointer.
|
||||
* @property {String} message - Error message.
|
||||
* @property {String} code - Original code passed in.
|
||||
* @property {String?} op - Symbolic opcode.
|
||||
* @property {Number?} ip - Instruction pointer.
|
||||
*/
|
||||
|
||||
function ScriptError(msg, op, ip) {
|
||||
function ScriptError(code, op, ip) {
|
||||
Error.call(this);
|
||||
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, ScriptError);
|
||||
|
||||
this.type = 'ScriptError';
|
||||
this.code = code;
|
||||
|
||||
if (Buffer.isBuffer(op))
|
||||
op = 'PUSHDATA[' + op.length + ']';
|
||||
|
||||
if (op || ip != null) {
|
||||
msg += '(';
|
||||
code += '(';
|
||||
if (op) {
|
||||
op = constants.opcodesByVal[op] || op;
|
||||
msg += 'op=' + op;
|
||||
code += 'op=' + op;
|
||||
if (ip != null)
|
||||
msg += ', ';
|
||||
code += ', ';
|
||||
}
|
||||
if (ip != null)
|
||||
msg += 'ip=' + ip;
|
||||
code += 'ip=' + ip;
|
||||
code + ')';
|
||||
}
|
||||
this.message = msg;
|
||||
|
||||
this.message = code;
|
||||
this.op = op;
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user