From 2bc76b157034ce34148792564ef9c70115f8bcfe Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 4 Oct 2016 12:13:45 -0400 Subject: [PATCH] Unit test coverage for script interpreter verifyWitnessProgram --- lib/script/interpreter.js | 25 +++++---- test/script/interpreter.js | 106 +++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/lib/script/interpreter.js b/lib/script/interpreter.js index ffcec43..42b1c26 100644 --- a/lib/script/interpreter.js +++ b/lib/script/interpreter.js @@ -38,7 +38,7 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, if (version === 0) { if (program.length === 32) { if (witness.length === 0) { - this.errstr = 'v0 scripthash program empty'; + this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY'; return false; } @@ -46,14 +46,14 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, scriptPubKey = new Script(scriptPubKeyBuffer); var hash = Hash.sha256(scriptPubKeyBuffer); if (hash.toString('hex') !== program.toString('hex')) { - this.errstr = 'witness program mismatch'; + this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'; return false; } stack = witness.slice(0, -1); } else if (program.length === 20) { if (witness.length !== 2) { - this.errstr = 'witness program mismatch'; + this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'; return false; } @@ -66,11 +66,11 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, stack = witness; } else { - this.errstr = 'Witness program wrong length'; + this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH'; return false; } - } else if ((flags & this.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)) { - this.errstr = 'Upgradeable witness program discouraged'; + } else if ((flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)) { + this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'; return false; } else { return true; @@ -248,17 +248,17 @@ Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, return false; } if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { - var witnessValues = {}; - if (redeemScript.isWitnessProgram(witnessValues)) { + var p2shWitnessValues = {}; + if (redeemScript.isWitnessProgram(p2shWitnessValues)) { hadWitness = true; var redeemScriptPush = new Script(); redeemScriptPush.add(redeemScript.toBuffer()); if (scriptSig.toHex() !== redeemScriptPush.toHex()) { - this.errstr = 'Malleated scriptSig'; + this.errstr = 'SCRIPT_ERR_WITNESS_MALLEATED_P2SH'; return false; } - if (!this.verifyWitnessProgram(witnessValues.version, witnessValues.program, witness, satoshis, flags)) { + if (!this.verifyWitnessProgram(p2shWitnessValues.version, p2shWitnessValues.program, witness, satoshis, flags)) { return false; } @@ -268,7 +268,7 @@ Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { if (!hadWitness && witness.length > 0) { - this.errstr = 'Witness unexpected'; + this.errstr = 'SCRIPT_ERR_WITNESS_UNEXPECTED'; return false; } } @@ -320,6 +320,9 @@ Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD); // bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 Interpreter.SCRIPT_VERIFY_NONE = 0; +// Making v1-v16 witness program non-standard +Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1 << 12); + // Evaluate P2SH subscripts (softfork safe, BIP16). Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0); diff --git a/test/script/interpreter.js b/test/script/interpreter.js index ea7a328..70b9519 100644 --- a/test/script/interpreter.js +++ b/test/script/interpreter.js @@ -1,6 +1,7 @@ 'use strict'; var should = require('chai').should(); +var sinon = require('sinon'); var bitcore = require('../..'); var Interpreter = bitcore.Script.Interpreter; var Transaction = bitcore.Transaction; @@ -97,6 +98,111 @@ describe('Interpreter', function() { }); + describe('#verifyWitnessProgram', function() { + it('will return true if witness program greater than 0', function() { + var si = Interpreter(); + var version = 1; + var program = new Buffer('bcbd1db07ce89d1f4050645c26c90ce78b67eff78460002a4d5c10410958e064', 'hex'); + var witness = [new Buffer('bda0eeeb166c8bfeaee88dedc8efa82d3bea35aac5be253902f59d52908bfe25', 'hex')]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(true); + }); + it('will return false with error if witness length is 0', function() { + var si = Interpreter(); + var version = 0; + var program = new Buffer('bcbd1db07ce89d1f4050645c26c90ce78b67eff78460002a4d5c10410958e064', 'hex'); + var witness = []; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY'); + }); + it('will return false if program hash mismatch (version 0, 32 byte program)', function() { + var si = Interpreter(); + var version = 0; + var program = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'); + }); + it('will return false if witness stack doesn\'t have two items (version 0, 20 byte program)', function() { + var si = Interpreter(); + var version = 0; + var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'); + }); + it('will return false if program wrong length for version 0', function() { + var si = Interpreter(); + var version = 0; + var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH'); + }); + it('will return false with discourage upgradable witness program', function() { + var si = Interpreter(); + var version = 1; + var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'); + }); + it('will return false with error if stack doesn\'t have exactly one item', function() { + var si = Interpreter(); + si.evaluate = sinon.stub().returns(true); + var version = 0; + var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_EVAL_FALSE'); + }); + it('will return false if last item in stack casts to false', function() { + var si = Interpreter(); + si.evaluate = function() { + si.stack = [new Buffer('00', 'hex')]; + return true; + }; + var version = 0; + var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); + var witness = [ + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') + ]; + var satoshis = 1; + var flags = 0; + si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); + si.errstr.should.equal('SCRIPT_ERR_EVAL_FALSE_IN_STACK'); + }); + }); + describe('#verify', function() { it('should verify these trivial scripts', function() {