Browse Source

script: interpreter witness program fixes

patch-2
Braydon Fuller 9 years ago
parent
commit
c6079e9556
  1. 38
      lib/script/interpreter.js
  2. 19
      lib/script/script.js
  3. 7
      lib/transaction/transaction.js

38
lib/script/interpreter.js

@ -32,25 +32,26 @@ var Interpreter = function Interpreter(obj) {
}; };
Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, satoshis, flags) { Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, satoshis, flags) {
var scriptPubKey = new Script; var scriptPubKey = new Script();
var stack = []; var stack = [];
if (version == 0) { if (version === 0) {
if (program.length == 32) { if (program.length == 32) {
if (witness.length == 0) { if (witness.length == 0) {
this.errstr = 'v0 scripthash program empty'; this.errstr = 'v0 scripthash program empty';
return false; return false;
} }
scriptPubKey = witness[witness.length - 1]; var scriptPubKeyBuffer = witness[witness.length - 1];
var hash = Hash.sha256(scriptPubKey); scriptPubKey = new Script(scriptPubKeyBuffer);
if (hash !== program.script) { var hash = Hash.sha256(scriptPubKeyBuffer);
if (hash.toString('hex') !== program.toString('hex')) {
this.errstr = 'witness program mismatch'; this.errstr = 'witness program mismatch';
return false; return false;
} }
stack = witness.slice(0, -1); stack = witness.slice(0, -1);
} else if (program.script.length == 20) { } else if (program.length == 20) {
if (witness.length != 2) { if (witness.length != 2) {
this.errstr = 'witness program mismatch'; this.errstr = 'witness program mismatch';
return false; return false;
@ -69,6 +70,7 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness,
return true; return true;
} }
this.initialize();
this.set({ this.set({
script: scriptPubKey, script: scriptPubKey,
stack: stack, stack: stack,
@ -110,7 +112,7 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness,
* *
* Translated from bitcoind's VerifyScript * Translated from bitcoind's VerifyScript
*/ */
Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, witness, satoshis) { Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, witness, satoshis) {
var Transaction = require('../transaction'); var Transaction = require('../transaction');
if (_.isUndefined(tx)) { if (_.isUndefined(tx)) {
@ -183,15 +185,14 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness,
var version, program; var version, program;
if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
if (scriptPubkey.isWitnessProgram()) { var witnessValues = {};
version = scriptPubkey[0]; if (scriptPubkey.isWitnessProgram(witnessValues)) {
program = s.toProgram();
hadWitness = true; hadWitness = true;
if (scriptSig.toBuffer().length != 0) { if (scriptSig.toBuffer().length != 0) {
return false; return false;
} }
if (!this.verifyWitnessProgram(version, program, witness, satoshis, flags)) { if (!this.verifyWitnessProgram(witnessValues.version, witnessValues.program, witness, satoshis, flags)) {
return false; return false;
} }
} }
@ -239,17 +240,18 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness,
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'; this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK';
return false; return false;
} }
if ((flags & this.SCRIPT_VERIFY_WITNESS)) { if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
if (redeemScript.isWitnessOut()) { var witnessValues = {};
version = redeemScript[0]; if (redeemScript.isWitnessProgram(witnessValues)) {
program = redeemScript.toProgram();
hadWitness = true; hadWitness = true;
if (scriptSig !== redeemScript) { var redeemScriptPush = new Script();
redeemScriptPush.add(redeemScript.toBuffer());
if (scriptSig.toHex() !== redeemScriptPush.toHex()) {
this.errstr = 'Malleated scriptSig'; this.errstr = 'Malleated scriptSig';
return false; return false;
} }
if (!this.verifyWitnessProgram(version, program, witness, satoshis, flags)) { if (!this.verifyWitnessProgram(witnessValues.version, witnessValues.program, witness, satoshis, flags)) {
return false; return false;
} }
@ -257,7 +259,7 @@ Interpreter.prototype.verifyWitnessProgram = function(version, program, witness,
} }
} }
if ((flags & this.SCRIPT_VERIFY_WITNESS)) { if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
if (!hadWitness && witness.length > 0) { if (!hadWitness && witness.length > 0) {
this.errstr = 'Witness unexpected'; this.errstr = 'Witness unexpected';
return false; return false;

19
lib/script/script.js

@ -405,29 +405,32 @@ Script.prototype.isWitnessPublicKeyHashOut = function() {
}; };
/** /**
* @param {Object=} values - The return values
* @param {Number} values.version - Set with the witness version
* @param {Buffer} values.program - Set with the witness program
* @returns {boolean} if this is a p2wpkh output script * @returns {boolean} if this is a p2wpkh output script
*/ */
Script.prototype.isWitnessProgram = function() { Script.prototype.isWitnessProgram = function(values) {
if (!values) {
values = {};
}
var buf = this.toBuffer(); var buf = this.toBuffer();
if (buf.length < 4 || buf.length > 34) { if (buf.length < 4 || buf.length > 34) {
return false; return false;
} }
if (buf[0] !== Opcode.OP_0 && (buf[0] < Opcode.OP_1 && buf[1] > Opcode.OP_16)) { if (buf[0] >= Opcode.OP_0 && (buf[0] < 1 && buf[0] > 16)) {
return false; return false;
} }
if (buf.length == buf[1] + 2) { if (buf.length === buf[1] + 2) {
values.version = buf[0];
values.program = buf.slice(2, buf.length);
return true; return true;
} }
return false; return false;
}; };
Script.prototype.toProgram = function () {
var buf = this.toBuffer();
return buf.slice(2, buf.end);
};
/** /**
* @returns {boolean} if this is a p2sh input script * @returns {boolean} if this is a p2sh input script
* Note that these are frequently indistinguishable from pubkeyhashin * Note that these are frequently indistinguishable from pubkeyhashin

7
lib/transaction/transaction.js

@ -1201,7 +1201,12 @@ Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript, si
} }
if (sigversion == 1) { if (sigversion == 1) {
return SighashWitness.verify(this, sig, pubkey, nin, subscript, this.inputs[nin].getSatoshisBuffer()); var subscriptBuffer = subscript.toBuffer();
var scriptCodeWriter = new BufferWriter();
scriptCodeWriter.writeVarintNum(subscriptBuffer.length);
scriptCodeWriter.write(subscriptBuffer);
return SighashWitness.verify(this, sig, pubkey, nin, scriptCodeWriter.toBuffer(), this.inputs[nin].getSatoshisBuffer());
} }
return Sighash.verify(this, sig, pubkey, nin, subscript); return Sighash.verify(this, sig, pubkey, nin, subscript);

Loading…
Cancel
Save