script errors.
This commit is contained in:
parent
e9c0e24b21
commit
e89ed67843
@ -221,21 +221,21 @@ Stack.prototype._swap = function _swap(i1, i2) {
|
|||||||
|
|
||||||
Stack.prototype.toalt = function toalt() {
|
Stack.prototype.toalt = function toalt() {
|
||||||
if (this.length === 0)
|
if (this.length === 0)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'toaltstack');
|
||||||
|
|
||||||
this.alt.push(this.pop());
|
this.alt.push(this.pop());
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.fromalt = function fromalt() {
|
Stack.prototype.fromalt = function fromalt() {
|
||||||
if (this.alt.length === 0)
|
if (this.alt.length === 0)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'fromaltstack');
|
||||||
|
|
||||||
this.push(this.alt.pop());
|
this.push(this.alt.pop());
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.ifdup = function ifdup() {
|
Stack.prototype.ifdup = function ifdup() {
|
||||||
if (this.length === 0)
|
if (this.length === 0)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'ifdup');
|
||||||
|
|
||||||
if (Script.bool(this.top(-1)))
|
if (Script.bool(this.top(-1)))
|
||||||
this.push(Script.array(this.top(-1)));
|
this.push(Script.array(this.top(-1)));
|
||||||
@ -247,28 +247,28 @@ Stack.prototype.depth = function depth() {
|
|||||||
|
|
||||||
Stack.prototype.drop = function drop() {
|
Stack.prototype.drop = function drop() {
|
||||||
if (this.length === 0)
|
if (this.length === 0)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'drop');
|
||||||
|
|
||||||
this.pop();
|
this.pop();
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.dup = function dup() {
|
Stack.prototype.dup = function dup() {
|
||||||
if (this.length === 0)
|
if (this.length === 0)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'dup');
|
||||||
|
|
||||||
this.push(this.top(-1));
|
this.push(this.top(-1));
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.nip = function nip() {
|
Stack.prototype.nip = function nip() {
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'nip');
|
||||||
|
|
||||||
this.splice(this.length - 2, 1);
|
this.splice(this.length - 2, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.over = function over() {
|
Stack.prototype.over = function over() {
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'over');
|
||||||
|
|
||||||
this.push(this.top(-2));
|
this.push(this.top(-2));
|
||||||
};
|
};
|
||||||
@ -285,13 +285,13 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
|
|||||||
var val, n;
|
var val, n;
|
||||||
|
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', op);
|
||||||
|
|
||||||
val = this.pop();
|
val = this.pop();
|
||||||
n = Script.num(val, flags).toNumber();
|
n = Script.num(val, flags).toNumber();
|
||||||
|
|
||||||
if (n <= 0 || n > this.length)
|
if (n <= 0 || n > this.length)
|
||||||
throw new Error('Bad value.');
|
throw new ScriptError('Bad value.', op);
|
||||||
|
|
||||||
val = this.get(-n - 1);
|
val = this.get(-n - 1);
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
|
|||||||
|
|
||||||
Stack.prototype.rot = function rot() {
|
Stack.prototype.rot = function rot() {
|
||||||
if (this.length < 3)
|
if (this.length < 3)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'rot');
|
||||||
|
|
||||||
this._swap(-3, -2);
|
this._swap(-3, -2);
|
||||||
this._swap(-2, -1);
|
this._swap(-2, -1);
|
||||||
@ -311,21 +311,21 @@ Stack.prototype.rot = function rot() {
|
|||||||
|
|
||||||
Stack.prototype.swap = function swap() {
|
Stack.prototype.swap = function swap() {
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'swap');
|
||||||
|
|
||||||
this._swap(-2, -1);
|
this._swap(-2, -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.tuck = function tuck() {
|
Stack.prototype.tuck = function tuck() {
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'tuck');
|
||||||
|
|
||||||
this.splice(this.length - 2, 0, this.top(-1));
|
this.splice(this.length - 2, 0, this.top(-1));
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack.prototype.drop2 = function drop2() {
|
Stack.prototype.drop2 = function drop2() {
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', '2drop');
|
||||||
|
|
||||||
this.pop();
|
this.pop();
|
||||||
this.pop();
|
this.pop();
|
||||||
@ -335,7 +335,7 @@ Stack.prototype.dup2 = function dup2() {
|
|||||||
var v1, v2;
|
var v1, v2;
|
||||||
|
|
||||||
if (this.length < 2)
|
if (this.length < 2)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', '2dup');
|
||||||
|
|
||||||
v1 = this.top(-2);
|
v1 = this.top(-2);
|
||||||
v2 = this.top(-1);
|
v2 = this.top(-1);
|
||||||
@ -348,7 +348,7 @@ Stack.prototype.dup3 = function dup3() {
|
|||||||
var v1, v2, v3;
|
var v1, v2, v3;
|
||||||
|
|
||||||
if (this.length < 3)
|
if (this.length < 3)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', '3dup');
|
||||||
|
|
||||||
v1 = this.top(-3);
|
v1 = this.top(-3);
|
||||||
v2 = this.top(-2);
|
v2 = this.top(-2);
|
||||||
@ -363,7 +363,7 @@ Stack.prototype.over2 = function over2() {
|
|||||||
var v1, v2;
|
var v1, v2;
|
||||||
|
|
||||||
if (this.length < 4)
|
if (this.length < 4)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', '2over');
|
||||||
|
|
||||||
v1 = this.top(-4);
|
v1 = this.top(-4);
|
||||||
v2 = this.top(-3);
|
v2 = this.top(-3);
|
||||||
@ -376,7 +376,7 @@ Stack.prototype.rot2 = function rot2() {
|
|||||||
var v1, v2;
|
var v1, v2;
|
||||||
|
|
||||||
if (this.length < 6)
|
if (this.length < 6)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', '2rot');
|
||||||
|
|
||||||
v1 = this.top(-6);
|
v1 = this.top(-6);
|
||||||
v2 = this.top(-5);
|
v2 = this.top(-5);
|
||||||
@ -393,7 +393,7 @@ Stack.prototype.swap2 = function swap2() {
|
|||||||
|
|
||||||
Stack.prototype.size = function size() {
|
Stack.prototype.size = function size() {
|
||||||
if (this.length < 1)
|
if (this.length < 1)
|
||||||
throw new Error('Bad stack length.');
|
throw new ScriptError('Stack too small.', 'size');
|
||||||
|
|
||||||
this.push(Script.array(this.top(-1).length));
|
this.push(Script.array(this.top(-1).length));
|
||||||
};
|
};
|
||||||
@ -492,16 +492,21 @@ Script.prototype._next = function _next(to, code, ip) {
|
|||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.execute = function execute(stack, tx, index, flags, version) {
|
Script.prototype.execute = function execute(stack, flags, tx, index, version) {
|
||||||
try {
|
try {
|
||||||
return this._execute(stack, tx, index, flags, version);
|
return this.interpret(stack, flags, tx, index, version);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
utils.debug('Script error: %s.', e.message);
|
if (e.type === 'ScriptError') {
|
||||||
|
utils.debug('Script error: %s.', e.message);
|
||||||
|
} else {
|
||||||
|
utils.debug('Script interpreter threw:');
|
||||||
|
utils.debug(e.stack + '');
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype._execute = function _execute(stack, tx, index, flags, version) {
|
Script.prototype.interpret = function interpret(stack, flags, tx, index, version) {
|
||||||
var code = this.code.slice();
|
var code = this.code.slice();
|
||||||
var ip = 0;
|
var ip = 0;
|
||||||
var lastSep = -1;
|
var lastSep = -1;
|
||||||
@ -518,16 +523,16 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (code.length > constants.script.maxOps)
|
if (code.length > constants.script.maxOps)
|
||||||
return false;
|
throw new ScriptError('Script too large.');
|
||||||
|
|
||||||
for (ip = 0; ip < code.length; ip++) {
|
for (ip = 0; ip < code.length; ip++) {
|
||||||
op = code[ip];
|
op = code[ip];
|
||||||
|
|
||||||
if (Buffer.isBuffer(op)) {
|
if (Buffer.isBuffer(op)) {
|
||||||
if (op.length > constants.script.maxPush)
|
if (op.length > constants.script.maxPush)
|
||||||
return false;
|
throw new ScriptError('Push data too large.', op, ip);
|
||||||
if (!Script.checkPush(op, flags))
|
if (!Script.checkPush(op, flags))
|
||||||
return false;
|
throw new ScriptError('Push verification failed.', op, ip);
|
||||||
stack.push(op);
|
stack.push(op);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -553,7 +558,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
case 'nop9':
|
case 'nop9':
|
||||||
case 'nop10': {
|
case 'nop10': {
|
||||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '1negate': {
|
case '1negate': {
|
||||||
@ -563,7 +568,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
case 'if':
|
case 'if':
|
||||||
case 'notif': {
|
case 'notif': {
|
||||||
if (stack.length < 1)
|
if (stack.length < 1)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
val = Script.bool(stack.pop());
|
val = Script.bool(stack.pop());
|
||||||
if (op === 'notif')
|
if (op === 'notif')
|
||||||
val = !val;
|
val = !val;
|
||||||
@ -573,7 +578,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
// Splice out the statement blocks we don't need
|
// Splice out the statement blocks we don't need
|
||||||
if (val) {
|
if (val) {
|
||||||
if (endif === -1)
|
if (endif === -1)
|
||||||
return false;
|
throw new ScriptError('Missing endif.', op, ip);
|
||||||
if (else_ === -1) {
|
if (else_ === -1) {
|
||||||
code.splice(endif, 1);
|
code.splice(endif, 1);
|
||||||
code.splice(if_, 1);
|
code.splice(if_, 1);
|
||||||
@ -583,7 +588,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (endif === -1)
|
if (endif === -1)
|
||||||
return false;
|
throw new ScriptError('Missing endif.', op, ip);
|
||||||
if (else_ === -1) {
|
if (else_ === -1) {
|
||||||
code.splice(if_, (endif - if_) + 1);
|
code.splice(if_, (endif - if_) + 1);
|
||||||
} else {
|
} else {
|
||||||
@ -596,20 +601,20 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'else': {
|
case 'else': {
|
||||||
return false;
|
throw new ScriptError('Unexpected else.', op, ip);
|
||||||
}
|
}
|
||||||
case 'endif': {
|
case 'endif': {
|
||||||
return false;
|
throw new ScriptError('Unexpected endif.', op, ip);
|
||||||
}
|
}
|
||||||
case 'verify': {
|
case 'verify': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
if (!Script.bool(stack.pop()))
|
if (!Script.bool(stack.pop()))
|
||||||
return false;
|
throw new ScriptError('Verification failed.', op, ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'return': {
|
case 'return': {
|
||||||
return false;
|
throw new ScriptError('Script returned.', op, ip);
|
||||||
}
|
}
|
||||||
case 'toaltstack': {
|
case 'toaltstack': {
|
||||||
stack.toalt();
|
stack.toalt();
|
||||||
@ -698,7 +703,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
case 'not':
|
case 'not':
|
||||||
case '0notequal': {
|
case '0notequal': {
|
||||||
if (stack.length < 1)
|
if (stack.length < 1)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
n = Script.num(stack.pop(), flags);
|
n = Script.num(stack.pop(), flags);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case '1add':
|
case '1add':
|
||||||
@ -756,7 +761,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
case 'min':
|
case 'min':
|
||||||
case 'max':
|
case 'max':
|
||||||
if (stack.length < 2)
|
if (stack.length < 2)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
n2 = Script.num(stack.pop(), flags);
|
n2 = Script.num(stack.pop(), flags);
|
||||||
n1 = Script.num(stack.pop(), flags);
|
n1 = Script.num(stack.pop(), flags);
|
||||||
n = new bn(0, 'le');
|
n = new bn(0, 'le');
|
||||||
@ -815,7 +820,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
break;
|
break;
|
||||||
case 'within':
|
case 'within':
|
||||||
if (stack.length < 3)
|
if (stack.length < 3)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
n3 = Script.num(stack.pop(), flags);
|
n3 = Script.num(stack.pop(), flags);
|
||||||
n2 = Script.num(stack.pop(), flags);
|
n2 = Script.num(stack.pop(), flags);
|
||||||
n1 = Script.num(stack.pop(), flags);
|
n1 = Script.num(stack.pop(), flags);
|
||||||
@ -832,42 +837,42 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
}
|
}
|
||||||
case 'ripemd160': {
|
case 'ripemd160': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
stack.push(utils.ripemd160(stack.pop()));
|
stack.push(utils.ripemd160(stack.pop()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sha1': {
|
case 'sha1': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
stack.push(utils.sha1(stack.pop()));
|
stack.push(utils.sha1(stack.pop()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sha256': {
|
case 'sha256': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
stack.push(utils.sha256(stack.pop()));
|
stack.push(utils.sha256(stack.pop()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'hash256': {
|
case 'hash256': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
stack.push(utils.dsha256(stack.pop()));
|
stack.push(utils.dsha256(stack.pop()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'hash160': {
|
case 'hash160': {
|
||||||
if (stack.length === 0)
|
if (stack.length === 0)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
stack.push(utils.ripesha(stack.pop()));
|
stack.push(utils.ripesha(stack.pop()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'equalverify':
|
case 'equalverify':
|
||||||
case 'equal': {
|
case 'equal': {
|
||||||
if (stack.length < 2)
|
if (stack.length < 2)
|
||||||
return false;
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
res = utils.isEqual(stack.pop(), stack.pop());
|
res = utils.isEqual(stack.pop(), stack.pop());
|
||||||
if (op === 'equalverify') {
|
if (op === 'equalverify') {
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
throw new ScriptError('Equal verification failed.', op, ip);
|
||||||
} else {
|
} else {
|
||||||
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
||||||
}
|
}
|
||||||
@ -875,17 +880,20 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
}
|
}
|
||||||
case 'checksigverify':
|
case 'checksigverify':
|
||||||
case 'checksig': {
|
case 'checksig': {
|
||||||
if (!tx || stack.length < 2)
|
if (!tx)
|
||||||
return false;
|
throw new ScriptError('No TX passed in.', op, ip);
|
||||||
|
|
||||||
|
if (stack.length < 2)
|
||||||
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
|
|
||||||
key = stack.pop();
|
key = stack.pop();
|
||||||
sig = stack.pop();
|
sig = stack.pop();
|
||||||
|
|
||||||
if (!Script.isValidKey(key, flags))
|
if (!Script.isValidKey(key, flags))
|
||||||
return false;
|
throw new ScriptError('Key is not valid.', op, ip);
|
||||||
|
|
||||||
if (!Script.isValidSignature(sig, flags))
|
if (!Script.isValidSignature(sig, flags))
|
||||||
return false;
|
throw new ScriptError('Signature is not valid.', op, ip);
|
||||||
|
|
||||||
type = sig[sig.length - 1];
|
type = sig[sig.length - 1];
|
||||||
|
|
||||||
@ -897,7 +905,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
res = Script.checksig(hash, sig, key, flags);
|
res = Script.checksig(hash, sig, key, flags);
|
||||||
if (op === 'checksigverify') {
|
if (op === 'checksigverify') {
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
throw new ScriptError('Signature verification failed.', op, ip);
|
||||||
} else {
|
} else {
|
||||||
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
||||||
}
|
}
|
||||||
@ -906,23 +914,26 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
}
|
}
|
||||||
case 'checkmultisigverify':
|
case 'checkmultisigverify':
|
||||||
case 'checkmultisig': {
|
case 'checkmultisig': {
|
||||||
if (!tx || stack.length < 4)
|
if (!tx)
|
||||||
return false;
|
throw new ScriptError('No TX passed in.', op, ip);
|
||||||
|
|
||||||
|
if (stack.length < 4)
|
||||||
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
|
|
||||||
n = Script.num(stack.pop(), flags).toNumber();
|
n = Script.num(stack.pop(), flags).toNumber();
|
||||||
|
|
||||||
if (!(n >= 1 && n <= 15))
|
if (!(n >= 1 && n <= 15))
|
||||||
return false;
|
throw new ScriptError('`n` is out of bounds.', op, ip);
|
||||||
|
|
||||||
if (stack.length < n + 1)
|
if (stack.length < n + 1)
|
||||||
return false;
|
throw new ScriptError('`n` exceeds stack size.', op, ip);
|
||||||
|
|
||||||
keys = [];
|
keys = [];
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
key = stack.pop();
|
key = stack.pop();
|
||||||
|
|
||||||
if (!Script.isValidKey(key, flags))
|
if (!Script.isValidKey(key, flags))
|
||||||
return false;
|
throw new ScriptError('Key is not valid.', op, ip);
|
||||||
|
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
}
|
}
|
||||||
@ -930,10 +941,10 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
m = Script.num(stack.pop(), flags).toNumber();
|
m = Script.num(stack.pop(), flags).toNumber();
|
||||||
|
|
||||||
if (!(m >= 1 && m <= n))
|
if (!(m >= 1 && m <= n))
|
||||||
return false;
|
throw new ScriptError('`m` is out of bounds.', op, ip);
|
||||||
|
|
||||||
if (stack.length < m)
|
if (stack.length < m)
|
||||||
return false;
|
throw new ScriptError('`m` exceeds stack size.', op, ip);
|
||||||
|
|
||||||
subscript = this.getSubscript(lastSep);
|
subscript = this.getSubscript(lastSep);
|
||||||
|
|
||||||
@ -947,7 +958,7 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
sig = stack.pop();
|
sig = stack.pop();
|
||||||
|
|
||||||
if (!Script.isValidSignature(sig, flags))
|
if (!Script.isValidSignature(sig, flags))
|
||||||
return false;
|
throw new ScriptError('Signature is not valid.', op, ip);
|
||||||
|
|
||||||
type = sig[sig.length - 1];
|
type = sig[sig.length - 1];
|
||||||
|
|
||||||
@ -962,23 +973,20 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stack.length < 1)
|
if (stack.length < 1)
|
||||||
return false;
|
throw new ScriptError('No dummy present.', op, ip);
|
||||||
|
|
||||||
val = stack.pop();
|
val = stack.pop();
|
||||||
|
|
||||||
if (flags & constants.flags.VERIFY_NULLDUMMY) {
|
if (flags & constants.flags.VERIFY_NULLDUMMY) {
|
||||||
if (!Script.isDummy(val))
|
if (!Script.isDummy(val))
|
||||||
return false;
|
throw new ScriptError('Dummy did not verify.', op, ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = succ >= m;
|
res = succ >= m;
|
||||||
|
|
||||||
if (!res)
|
|
||||||
utils.debug('checkmultisig failed: succ: %d, m: %d', succ, m);
|
|
||||||
|
|
||||||
if (op === 'checkmultisigverify') {
|
if (op === 'checkmultisigverify') {
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
throw new ScriptError('Signature verification failed.', op, ip);
|
||||||
} else {
|
} else {
|
||||||
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
stack.push(res ? new Buffer([1]) : new Buffer([]));
|
||||||
}
|
}
|
||||||
@ -989,28 +997,25 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
||||||
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
||||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx || stack.length === 0)
|
if (!tx)
|
||||||
return false;
|
throw new ScriptError('No TX passed in.', op, ip);
|
||||||
|
|
||||||
locktime = stack.top(-1);
|
if (stack.length === 0)
|
||||||
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
if (!Buffer.isBuffer(locktime))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// NOTE: Bitcoind accepts 5 byte locktimes.
|
// NOTE: Bitcoind accepts 5 byte locktimes.
|
||||||
// 4 byte locktimes become useless in 2106
|
// 4 byte locktimes become useless in 2106.
|
||||||
// (will people still be using bcoin then?).
|
locktime = Script.num(stack.top(-1), flags, 5).toNumber();
|
||||||
locktime = Script.num(locktime, flags, 4).toNumber();
|
|
||||||
|
|
||||||
if (locktime < 0)
|
if (locktime < 0)
|
||||||
return false;
|
throw new ScriptError('Negative locktime.', op, ip);
|
||||||
|
|
||||||
if (!Script.checkLocktime(locktime, tx, index))
|
if (!Script.checkLocktime(locktime, tx, index))
|
||||||
return false;
|
throw new ScriptError('Locktime verification failed.', op, ip);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1018,44 +1023,40 @@ Script.prototype._execute = function _execute(stack, tx, index, flags, version)
|
|||||||
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
|
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
|
||||||
if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
|
if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
|
||||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
throw new ScriptError('Upgradable NOP used.', op, ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx || stack.length === 0)
|
if (!tx)
|
||||||
return false;
|
throw new ScriptError('No TX passed in.', op, ip);
|
||||||
|
|
||||||
locktime = stack.top(-1);
|
if (stack.length === 0)
|
||||||
|
throw new ScriptError('Stack too small.', op, ip);
|
||||||
if (!Buffer.isBuffer(locktime))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// NOTE: Bitcoind accepts 5 byte locktimes.
|
// NOTE: Bitcoind accepts 5 byte locktimes.
|
||||||
// 4 byte locktimes become useless in 2106
|
// 4 byte locktimes become useless in 2106
|
||||||
// (will people still be using bcoin then?).
|
// (will people still be using bcoin then?).
|
||||||
locktime = Script.num(locktime, flags, 4).toNumber();
|
locktime = Script.num(stack.top(-1), flags, 4).toNumber();
|
||||||
|
|
||||||
if (locktime < 0)
|
if (locktime < 0)
|
||||||
return false;
|
throw new ScriptError('Negative sequence.', op, ip);
|
||||||
|
|
||||||
if ((locktime & constants.sequenceLocktimeDisableFlag) !== 0)
|
if ((locktime & constants.sequenceLocktimeDisableFlag) !== 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!Script.checkSequence(locktime, tx, index))
|
if (!Script.checkSequence(locktime, tx, index))
|
||||||
return false;
|
throw new ScriptError('Sequence verification failed.', op, ip);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// Unknown operation
|
throw new ScriptError('Unknown opcode.', op, ip);
|
||||||
utils.debug('Unknown opcode "%s" at offset %d', op, ip);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack.getSize() > constants.script.maxStack)
|
if (stack.getSize() > constants.script.maxStack)
|
||||||
return false;
|
throw new ScriptError('Stack size too large.', op, ip);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -1147,7 +1148,7 @@ Script.num = function num(value, flags, size) {
|
|||||||
size = 4;
|
size = 4;
|
||||||
|
|
||||||
if (value.length > size)
|
if (value.length > size)
|
||||||
throw new Error('Script number overflow.');
|
throw new ScriptError('Script number overflow.');
|
||||||
|
|
||||||
if ((flags & constants.flags.VERIFY_MINIMALDATA) && value.length > 0) {
|
if ((flags & constants.flags.VERIFY_MINIMALDATA) && value.length > 0) {
|
||||||
// If the low bits on the last byte are unset,
|
// If the low bits on the last byte are unset,
|
||||||
@ -1160,7 +1161,7 @@ Script.num = function num(value, flags, size) {
|
|||||||
// zero).
|
// zero).
|
||||||
if (!(value[value.length - 1] & 0x7f)) {
|
if (!(value[value.length - 1] & 0x7f)) {
|
||||||
if (value.length === 1 || !(value[value.length - 2] & 0x80))
|
if (value.length === 1 || !(value[value.length - 2] & 0x80))
|
||||||
throw new Error('Non-minimally encoded Script number.');
|
throw new ScriptError('Non-minimally encoded Script number.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2387,14 +2388,14 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute the input script
|
// Execute the input script
|
||||||
input.execute(stack, tx, i, flags, 0);
|
input.execute(stack, flags, tx, i, 0);
|
||||||
|
|
||||||
// Copy the stack for P2SH
|
// Copy the stack for P2SH
|
||||||
if (flags & constants.flags.VERIFY_P2SH)
|
if (flags & constants.flags.VERIFY_P2SH)
|
||||||
copy = stack.clone();
|
copy = stack.clone();
|
||||||
|
|
||||||
// Execute the previous output script
|
// Execute the previous output script
|
||||||
res = output.execute(stack, tx, i, flags, 0);
|
res = output.execute(stack, flags, tx, i, 0);
|
||||||
|
|
||||||
// Verify the script did not fail as well as the stack values
|
// Verify the script did not fail as well as the stack values
|
||||||
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
||||||
@ -2408,7 +2409,7 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Verify the program in the output script
|
// Verify the program in the output script
|
||||||
if (!Script.verifyProgram(witness, output, tx, i, flags))
|
if (!Script.verifyProgram(witness, output, flags, tx, i))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Force a cleanstack
|
// Force a cleanstack
|
||||||
@ -2437,7 +2438,7 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
redeem = new Script(raw);
|
redeem = new Script(raw);
|
||||||
|
|
||||||
// Execute the redeem script
|
// Execute the redeem script
|
||||||
res = redeem.execute(stack, tx, i, flags, 0);
|
res = redeem.execute(stack, flags, tx, i, 0);
|
||||||
|
|
||||||
// Verify the script did not fail as well as the stack values
|
// Verify the script did not fail as well as the stack values
|
||||||
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
||||||
@ -2451,7 +2452,7 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Verify the program in the redeem script
|
// Verify the program in the redeem script
|
||||||
if (!Script.verifyProgram(witness, redeem, tx, i, flags))
|
if (!Script.verifyProgram(witness, redeem, flags, tx, i))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Force a cleanstack
|
// Force a cleanstack
|
||||||
@ -2477,7 +2478,7 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.verifyProgram = function verifyProgram(witness, output, tx, i, flags) {
|
Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i) {
|
||||||
var program, witnessScript, redeem, stack, j, res;
|
var program, witnessScript, redeem, stack, j, res;
|
||||||
|
|
||||||
assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
|
assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
|
||||||
@ -2531,7 +2532,7 @@ Script.verifyProgram = function verifyProgram(witness, output, tx, i, flags) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = redeem.execute(stack, tx, i, flags, 1);
|
res = redeem.execute(stack, flags, tx, i, 1);
|
||||||
|
|
||||||
// Verify the script did not fail as well as the stack values
|
// Verify the script did not fail as well as the stack values
|
||||||
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
if (!res || stack.length === 0 || !Script.bool(stack.pop()))
|
||||||
@ -2753,6 +2754,35 @@ Script.isScript = function isScript(obj) {
|
|||||||
&& typeof obj.getSubscript === 'function';
|
&& typeof obj.getSubscript === 'function';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ScriptError
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ScriptError(msg, op, ip) {
|
||||||
|
Error.call(this);
|
||||||
|
if (Error.captureStackTrace)
|
||||||
|
Error.captureStackTrace(this, ScriptError);
|
||||||
|
this.type = 'ScriptError';
|
||||||
|
if (Buffer.isBuffer(op))
|
||||||
|
op = 'pushdata[' + op.length + ']';
|
||||||
|
if (op || ip != null) {
|
||||||
|
msg += '(';
|
||||||
|
if (op) {
|
||||||
|
msg += 'op=' + op;
|
||||||
|
if (ip != null)
|
||||||
|
msg += ', ';
|
||||||
|
}
|
||||||
|
if (ip != null)
|
||||||
|
msg += 'ip=' + ip;
|
||||||
|
}
|
||||||
|
this.message = msg;
|
||||||
|
this.op = op;
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.inherits(ScriptError, Error);
|
||||||
|
|
||||||
Script.witness = Witness;
|
Script.witness = Witness;
|
||||||
Script.stack = Stack;
|
Script.stack = Stack;
|
||||||
|
Script.error = ScriptError;
|
||||||
module.exports = Script;
|
module.exports = Script;
|
||||||
|
|||||||
@ -807,7 +807,7 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
|||||||
if (!input.script.isPushOnly())
|
if (!input.script.isPushOnly())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = input.script.execute(stack, this, i, flags, 0);
|
res = input.script.execute(stack, flags, this, i, 0);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user