|
|
@ -6,8 +6,6 @@ var Script = require('./script'); |
|
|
|
var Opcode = require('../opcode'); |
|
|
|
var BN = require('../crypto/bn'); |
|
|
|
var Hash = require('../crypto/hash'); |
|
|
|
var BufferReader = require('../encoding/bufferreader'); |
|
|
|
var BufferWriter = require('../encoding/bufferwriter'); |
|
|
|
var Signature = require('../crypto/signature'); |
|
|
|
var PublicKey = require('../publickey'); |
|
|
|
|
|
|
@ -323,7 +321,9 @@ Interpreter.prototype.step = function() { |
|
|
|
|
|
|
|
//bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
|
|
|
var fExec = (this.vfExec.indexOf(false) === -1); |
|
|
|
|
|
|
|
var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript; |
|
|
|
var sig, pubkey; |
|
|
|
var fValue, fSuccess; |
|
|
|
|
|
|
|
// Read instruction
|
|
|
|
var chunk = this.script.chunks[this.pc]; |
|
|
@ -399,8 +399,8 @@ Interpreter.prototype.step = function() { |
|
|
|
{ |
|
|
|
// ( -- value)
|
|
|
|
// ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1));
|
|
|
|
var n = opcodenum - (Opcode.OP_1 - 1); |
|
|
|
var buf = BN(n).toScriptNumBuffer(); |
|
|
|
n = opcodenum - (Opcode.OP_1 - 1); |
|
|
|
buf = BN(n).toScriptNumBuffer(); |
|
|
|
this.stack.push(buf); |
|
|
|
// The result of these opcodes should always be the minimal way to push the data
|
|
|
|
// they push, so no need for a CheckMinimalPush here.
|
|
|
@ -437,16 +437,17 @@ Interpreter.prototype.step = function() { |
|
|
|
{ |
|
|
|
// <expression> if [statements] [else [statements]] endif
|
|
|
|
// bool fValue = false;
|
|
|
|
var fValue = false; |
|
|
|
fValue = false; |
|
|
|
if (fExec) { |
|
|
|
if (this.stack.length < 1) { |
|
|
|
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack.pop(); |
|
|
|
buf = this.stack.pop(); |
|
|
|
fValue = Interpreter.castToBool(buf); |
|
|
|
if (opcodenum === Opcode.OP_NOTIF) |
|
|
|
if (opcodenum === Opcode.OP_NOTIF) { |
|
|
|
fValue = !fValue; |
|
|
|
} |
|
|
|
} |
|
|
|
this.vfExec.push(fValue); |
|
|
|
} |
|
|
@ -480,11 +481,11 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - 1]; |
|
|
|
var fValue = Interpreter.castToBool(buf); |
|
|
|
if (fValue) |
|
|
|
buf = this.stack[this.stack.length - 1]; |
|
|
|
fValue = Interpreter.castToBool(buf); |
|
|
|
if (fValue) { |
|
|
|
this.stack.pop(); |
|
|
|
else { |
|
|
|
} else { |
|
|
|
this.errstr = 'SCRIPT_ERR_VERIFY'; |
|
|
|
return false; |
|
|
|
} |
|
|
@ -541,8 +542,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf1 = this.stack[this.stack.length - 2]; |
|
|
|
var buf2 = this.stack[this.stack.length - 1]; |
|
|
|
buf1 = this.stack[this.stack.length - 2]; |
|
|
|
buf2 = this.stack[this.stack.length - 1]; |
|
|
|
this.stack.push(buf1); |
|
|
|
this.stack.push(buf2); |
|
|
|
} |
|
|
@ -555,8 +556,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf1 = this.stack[this.stack.length - 3]; |
|
|
|
var buf2 = this.stack[this.stack.length - 2]; |
|
|
|
buf1 = this.stack[this.stack.length - 3]; |
|
|
|
buf2 = this.stack[this.stack.length - 2]; |
|
|
|
var buf3 = this.stack[this.stack.length - 1]; |
|
|
|
this.stack.push(buf1); |
|
|
|
this.stack.push(buf2); |
|
|
@ -571,8 +572,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf1 = this.stack[this.stack.length - 4]; |
|
|
|
var buf2 = this.stack[this.stack.length - 3]; |
|
|
|
buf1 = this.stack[this.stack.length - 4]; |
|
|
|
buf2 = this.stack[this.stack.length - 3]; |
|
|
|
this.stack.push(buf1); |
|
|
|
this.stack.push(buf2); |
|
|
|
} |
|
|
@ -585,7 +586,7 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var spliced = this.stack.splice(this.stack.length - 6, 2); |
|
|
|
spliced = this.stack.splice(this.stack.length - 6, 2); |
|
|
|
this.stack.push(spliced[0]); |
|
|
|
this.stack.push(spliced[1]); |
|
|
|
} |
|
|
@ -598,7 +599,7 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var spliced = this.stack.splice(this.stack.length - 4, 2); |
|
|
|
spliced = this.stack.splice(this.stack.length - 4, 2); |
|
|
|
this.stack.push(spliced[0]); |
|
|
|
this.stack.push(spliced[1]); |
|
|
|
} |
|
|
@ -611,17 +612,18 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - 1]; |
|
|
|
var fValue = Interpreter.castToBool(buf); |
|
|
|
if (fValue) |
|
|
|
buf = this.stack[this.stack.length - 1]; |
|
|
|
fValue = Interpreter.castToBool(buf); |
|
|
|
if (fValue) { |
|
|
|
this.stack.push(buf); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case Opcode.OP_DEPTH: |
|
|
|
{ |
|
|
|
// -- stacksize
|
|
|
|
var buf = BN(this.stack.length).toScriptNumBuffer(); |
|
|
|
buf = BN(this.stack.length).toScriptNumBuffer(); |
|
|
|
this.stack.push(buf); |
|
|
|
} |
|
|
|
break; |
|
|
@ -679,17 +681,18 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - 1]; |
|
|
|
var bn = BN().fromScriptNumBuffer(buf, fRequireMinimal); |
|
|
|
var n = bn.toNumber(); |
|
|
|
buf = this.stack[this.stack.length - 1]; |
|
|
|
bn = BN().fromScriptNumBuffer(buf, fRequireMinimal); |
|
|
|
n = bn.toNumber(); |
|
|
|
this.stack.pop(); |
|
|
|
if (n < 0 || n >= this.stack.length) { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - n - 1]; |
|
|
|
if (opcodenum === Opcode.OP_ROLL) |
|
|
|
buf = this.stack[this.stack.length - n - 1]; |
|
|
|
if (opcodenum === Opcode.OP_ROLL) { |
|
|
|
this.stack.splice(this.stack.length - n - 1, 1); |
|
|
|
} |
|
|
|
this.stack.push(buf); |
|
|
|
} |
|
|
|
break; |
|
|
@ -703,8 +706,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var x1 = this.stack[this.stack.length - 3]; |
|
|
|
var x2 = this.stack[this.stack.length - 2]; |
|
|
|
x1 = this.stack[this.stack.length - 3]; |
|
|
|
x2 = this.stack[this.stack.length - 2]; |
|
|
|
var x3 = this.stack[this.stack.length - 1]; |
|
|
|
this.stack[this.stack.length - 3] = x2; |
|
|
|
this.stack[this.stack.length - 2] = x3; |
|
|
@ -719,8 +722,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var x1 = this.stack[this.stack.length - 2]; |
|
|
|
var x2 = this.stack[this.stack.length - 1]; |
|
|
|
x1 = this.stack[this.stack.length - 2]; |
|
|
|
x2 = this.stack[this.stack.length - 1]; |
|
|
|
this.stack[this.stack.length - 2] = x2; |
|
|
|
this.stack[this.stack.length - 1] = x1; |
|
|
|
} |
|
|
@ -745,7 +748,7 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var bn = BN(this.stack[this.stack.length - 1].length); |
|
|
|
bn = BN(this.stack[this.stack.length - 1].length); |
|
|
|
this.stack.push(bn.toScriptNumBuffer()); |
|
|
|
} |
|
|
|
break; |
|
|
@ -763,8 +766,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf1 = this.stack[this.stack.length - 2]; |
|
|
|
var buf2 = this.stack[this.stack.length - 1]; |
|
|
|
buf1 = this.stack[this.stack.length - 2]; |
|
|
|
buf2 = this.stack[this.stack.length - 1]; |
|
|
|
var fEqual = buf1.toString('hex') === buf2.toString('hex'); |
|
|
|
// Opcode.OP_NOTEQUAL is disabled because it would be too easy to say
|
|
|
|
// something like n != 1 and have some wiseguy pass in 1 with extra
|
|
|
@ -775,9 +778,9 @@ Interpreter.prototype.step = function() { |
|
|
|
this.stack.pop(); |
|
|
|
this.stack.push(fEqual ? Interpreter.true : Interpreter.false); |
|
|
|
if (opcodenum === Opcode.OP_EQUALVERIFY) { |
|
|
|
if (fEqual) |
|
|
|
if (fEqual) { |
|
|
|
this.stack.pop(); |
|
|
|
else { |
|
|
|
} else { |
|
|
|
this.errstr = 'SCRIPT_ERR_EQUALVERIFY'; |
|
|
|
return false; |
|
|
|
} |
|
|
@ -801,8 +804,8 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - 1]; |
|
|
|
var bn = BN().fromScriptNumBuffer(buf, fRequireMinimal); |
|
|
|
buf = this.stack[this.stack.length - 1]; |
|
|
|
bn = BN().fromScriptNumBuffer(buf, fRequireMinimal); |
|
|
|
switch (opcodenum) { |
|
|
|
case Opcode.OP_1ADD: |
|
|
|
bn = bn.add(1); |
|
|
@ -814,7 +817,9 @@ Interpreter.prototype.step = function() { |
|
|
|
bn = bn.neg(); |
|
|
|
break; |
|
|
|
case Opcode.OP_ABS: |
|
|
|
if (bn.cmp(0) < 0) bn = bn.neg(); |
|
|
|
if (bn.cmp(0) < 0) { |
|
|
|
bn = bn.neg(); |
|
|
|
} |
|
|
|
break; |
|
|
|
case Opcode.OP_NOT: |
|
|
|
bn = BN((bn.cmp(0) === 0) + 0); |
|
|
@ -848,9 +853,9 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var bn1 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); |
|
|
|
var bn2 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); |
|
|
|
var bn = BN(0); |
|
|
|
bn1 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); |
|
|
|
bn2 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); |
|
|
|
bn = BN(0); |
|
|
|
|
|
|
|
switch (opcodenum) { |
|
|
|
case Opcode.OP_ADD: |
|
|
@ -911,9 +916,9 @@ Interpreter.prototype.step = function() { |
|
|
|
|
|
|
|
if (opcodenum === Opcode.OP_NUMEQUALVERIFY) { |
|
|
|
// if (CastToBool(stacktop(-1)))
|
|
|
|
if (Interpreter.castToBool(this.stack[this.stack.length - 1])) |
|
|
|
if (Interpreter.castToBool(this.stack[this.stack.length - 1])) { |
|
|
|
this.stack.pop(); |
|
|
|
else { |
|
|
|
} else { |
|
|
|
this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'; |
|
|
|
return false; |
|
|
|
} |
|
|
@ -928,11 +933,11 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var bn1 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); |
|
|
|
var bn2 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); |
|
|
|
bn1 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); |
|
|
|
bn2 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); |
|
|
|
var bn3 = BN().fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); |
|
|
|
//bool fValue = (bn2 <= bn1 && bn1 < bn3);
|
|
|
|
var fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0); |
|
|
|
fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0); |
|
|
|
this.stack.pop(); |
|
|
|
this.stack.pop(); |
|
|
|
this.stack.pop(); |
|
|
@ -955,19 +960,21 @@ Interpreter.prototype.step = function() { |
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
return false; |
|
|
|
} |
|
|
|
var buf = this.stack[this.stack.length - 1]; |
|
|
|
//valtype vchHash((opcode == Opcode.OP_RIPEMD160 || opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32);
|
|
|
|
buf = this.stack[this.stack.length - 1]; |
|
|
|
//valtype vchHash((opcode == Opcode.OP_RIPEMD160 ||
|
|
|
|
// opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32);
|
|
|
|
var bufHash; |
|
|
|
if (opcodenum === Opcode.OP_RIPEMD160) |
|
|
|
if (opcodenum === Opcode.OP_RIPEMD160) { |
|
|
|
bufHash = Hash.ripemd160(buf); |
|
|
|
else if (opcodenum === Opcode.OP_SHA1) |
|
|
|
} else if (opcodenum === Opcode.OP_SHA1) { |
|
|
|
bufHash = Hash.sha1(buf); |
|
|
|
else if (opcodenum === Opcode.OP_SHA256) |
|
|
|
} else if (opcodenum === Opcode.OP_SHA256) { |
|
|
|
bufHash = Hash.sha256(buf); |
|
|
|
else if (opcodenum === Opcode.OP_HASH160) |
|
|
|
} else if (opcodenum === Opcode.OP_HASH160) { |
|
|
|
bufHash = Hash.sha256ripemd160(buf); |
|
|
|
else if (opcodenum === Opcode.OP_HASH256) |
|
|
|
} else if (opcodenum === Opcode.OP_HASH256) { |
|
|
|
bufHash = Hash.sha256sha256(buf); |
|
|
|
} |
|
|
|
this.stack.pop(); |
|
|
|
this.stack.push(bufHash); |
|
|
|
} |
|
|
@ -989,27 +996,26 @@ Interpreter.prototype.step = function() { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
var bufSig = this.stack[this.stack.length - 2]; |
|
|
|
var bufPubkey = this.stack[this.stack.length - 1]; |
|
|
|
bufSig = this.stack[this.stack.length - 2]; |
|
|
|
bufPubkey = this.stack[this.stack.length - 1]; |
|
|
|
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
|
|
// CScript scriptCode(pbegincodehash, pend);
|
|
|
|
var subscript = Script().set({ |
|
|
|
subscript = new Script().set({ |
|
|
|
chunks: this.script.chunks.slice(this.pbegincodehash) |
|
|
|
}); |
|
|
|
|
|
|
|
// Drop the signature, since there's no way for a signature to sign itself
|
|
|
|
var tmpScript = Script().add(bufSig); |
|
|
|
var tmpScript = new Script().add(bufSig); |
|
|
|
subscript.findAndDelete(tmpScript); |
|
|
|
|
|
|
|
if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
var fSuccess; |
|
|
|
try { |
|
|
|
var sig = Signature.fromTxFormat(bufSig); |
|
|
|
var pubkey = PublicKey.fromBuffer(bufPubkey, false); |
|
|
|
sig = Signature.fromTxFormat(bufSig); |
|
|
|
pubkey = PublicKey.fromBuffer(bufPubkey, false); |
|
|
|
fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); |
|
|
|
} catch (e) { |
|
|
|
//invalid sig or pubkey
|
|
|
@ -1074,22 +1080,22 @@ Interpreter.prototype.step = function() { |
|
|
|
} |
|
|
|
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
|
|
var subscript = Script().set({ |
|
|
|
subscript = new Script().set({ |
|
|
|
chunks: this.script.chunks.slice(this.pbegincodehash) |
|
|
|
}); |
|
|
|
|
|
|
|
// Drop the signatures, since there's no way for a signature to sign itself
|
|
|
|
for (var k = 0; k < nSigsCount; k++) { |
|
|
|
var bufSig = this.stack[this.stack.length - isig - k]; |
|
|
|
subscript.findAndDelete(Script().add(bufSig)); |
|
|
|
bufSig = this.stack[this.stack.length - isig - k]; |
|
|
|
subscript.findAndDelete(new Script().add(bufSig)); |
|
|
|
} |
|
|
|
|
|
|
|
var fSuccess = true; |
|
|
|
fSuccess = true; |
|
|
|
while (fSuccess && nSigsCount > 0) { |
|
|
|
// valtype& vchSig = stacktop(-isig);
|
|
|
|
var bufSig = this.stack[this.stack.length - isig]; |
|
|
|
bufSig = this.stack[this.stack.length - isig]; |
|
|
|
// valtype& vchPubKey = stacktop(-ikey);
|
|
|
|
var bufPubkey = this.stack[this.stack.length - ikey]; |
|
|
|
bufPubkey = this.stack[this.stack.length - ikey]; |
|
|
|
|
|
|
|
if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { |
|
|
|
return false; |
|
|
@ -1097,8 +1103,8 @@ Interpreter.prototype.step = function() { |
|
|
|
|
|
|
|
var fOk; |
|
|
|
try { |
|
|
|
var sig = Signature.fromTxFormat(bufSig); |
|
|
|
var pubkey = PublicKey.fromBuffer(bufPubkey, false); |
|
|
|
sig = Signature.fromTxFormat(bufSig); |
|
|
|
pubkey = PublicKey.fromBuffer(bufPubkey, false); |
|
|
|
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); |
|
|
|
} catch (e) { |
|
|
|
//invalid sig or pubkey
|
|
|
@ -1143,9 +1149,9 @@ Interpreter.prototype.step = function() { |
|
|
|
this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); |
|
|
|
|
|
|
|
if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) { |
|
|
|
if (fSuccess) |
|
|
|
if (fSuccess) { |
|
|
|
this.stack.pop(); |
|
|
|
else { |
|
|
|
} else { |
|
|
|
this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'; |
|
|
|
return false; |
|
|
|
} |
|
|
|