diff --git a/Script.js b/Script.js index bce3f11..fe59127 100644 --- a/Script.js +++ b/Script.js @@ -66,6 +66,15 @@ function spec(b) { } }; + Script.prototype.isPushOnly = function () + { + for (var i = 0; i < this.chunks.length; i++) + if (!Buffer.isBuffer(this.chunks[i])) + return false; + + return true; + }; + Script.prototype.isP2SH = function () { return (this.chunks.length == 3 && diff --git a/ScriptInterpreter.js b/ScriptInterpreter.js index e90796d..c54bc8b 100644 --- a/ScriptInterpreter.js +++ b/ScriptInterpreter.js @@ -1,6 +1,7 @@ require('classtool'); function spec(b) { + var assert = require('assert'); var config = b.config || require('./config'); var log = b.log || require('./util/log')(config); @@ -758,6 +759,11 @@ function spec(b) { return this.stack[this.stack.length-offset]; }; + ScriptInterpreter.prototype.stackBack = function stackBack() + { + return this.stack[-1]; + }; + /** * Pop the top element off the stack and return it. */ @@ -911,6 +917,62 @@ function spec(b) { return si; }; + ScriptInterpreter.verifyFull = + function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType, opts) + { + var si = new ScriptInterpreter(); + var siCopy = new ScriptInterpreter(); + + var ok = true; + si.eval(scriptSig, txTo, nIn, hashType, function (err) { + if (err) + ok = false; + }); + if (!ok) + return false; + + if (opts.verifyP2SH) { + si.stack.forEach(function(item) { + siCopy.stack.push(item); + }); + } + + ok = true; + si.eval(scriptPubKey, txTo, nIn, hashType, function (err) { + if (err) + ok = false; + }); + if (!ok) + return false; + if (si.stack.length == 0) + return false; + + if (castBool(si.stackBack()) == false) + return false; + + if (opts.verifyP2SH && scriptPubKey.isP2SH()) { + if (!scriptSig.isPushOnly()) + return false; + + assert.notEqual(siCopy.length, 0); + + var subscript = new Script(siCopy.stackPop()); + + ok = true; + siCopy.eval(subscript, txTo, nIn, hashType, function (err) { + if (err) + ok = false; + }); + if (!ok) + return false; + if (siCopy.stack.length == 0) + return false; + return castBool(siCopy.stackBack()); + } + + return true; + }; + var checkSig = ScriptInterpreter.checkSig = function (sig, pubkey, scriptCode, tx, n, hashType, callback) { if (!sig.length) {