mtx: refactor templating.

This commit is contained in:
Christopher Jeffrey 2016-08-18 06:18:34 -07:00
parent e8f2c3321c
commit 0db8677139
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 109 additions and 78 deletions

View File

@ -601,6 +601,17 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
return addressMap[hash] === true;
};
KeyRing.prototype.getRedeem = function(hash) {
if (this.program && utils.equal(hash, this.programHash))
return this.program;
if (this.script && utils.equal(hash, this.scriptHash160))
return this.script;
if (this.script && utils.equal(hash, this.scriptHash256))
return this.script;
};
/**
* Build input scripts templates for a transaction (does not
* sign, only creates signature slots). Only builds scripts

View File

@ -218,7 +218,7 @@ MTX.prototype.addOutput = function addOutput(options, value) {
*/
MTX.prototype.scriptInput = function scriptInput(index, ring) {
var input, prev, n, i, vector, redeemScript, witnessScript;
var input, prev, redeem;
// Get the input
input = this.inputs[index];
@ -248,57 +248,82 @@ MTX.prototype.scriptInput = function scriptInput(index, ring) {
// with segwit: figuring out where the redeem script and witness
// redeem scripts go.
if (prev.isScripthash()) {
if (ring.program && utils.equal(prev.get(1), ring.programHash)) {
// Witness program nested in regular P2SH.
redeemScript = ring.program.toRaw();
vector = input.witness;
if (ring.program.isWitnessScripthash()) {
// P2WSH nested within pay-to-scripthash
// (it had to be this complicated, didn't it?)
witnessScript = ring.script.toRaw();
prev = ring.script;
} else if (ring.program.isWitnessPubkeyhash()) {
// P2WPKH nested within pay-to-scripthash.
prev = Script.fromPubkeyhash(ring.keyHash);
} else {
assert(false, 'Unknown program.');
redeem = ring.getRedeem(prev.get(1));
if (!redeem)
return false;
// Witness program nested in regular P2SH.
if (redeem.isProgram()) {
// P2WSH nested within pay-to-scripthash.
if (redeem.isWitnessScripthash()) {
prev = ring.getRedeem(redeem.get(1));
if (!prev)
return false;
this.scriptVector(prev, input.witness, ring);
input.witness.push(prev.toRaw());
input.script.push(redeem.toRaw());
input.script.compile();
return true;
}
} else if (ring.script && utils.equal(prev.get(1), ring.scriptHash160)) {
// Regular P2SH.
redeemScript = ring.script.toRaw();
vector = input.script;
prev = ring.script;
} else {
// P2WPKH nested within pay-to-scripthash.
if (redeem.isWitnessPubkeyhash()) {
prev = Script.fromPubkeyhash(ring.keyHash);
this.scriptVector(prev, input.witness, ring);
input.script.push(redeem.toRaw());
input.script.compile();
return true;
}
// Unknown witness program.
return false;
}
} else if (prev.isProgram()) {
// Witness program.
vector = input.witness;
if (prev.isWitnessScripthash()) {
// Bare P2WSH.
if (!ring.script || !utils.equal(prev.get(1), ring.scriptHash256))
return false;
witnessScript = ring.script.toRaw();
prev = ring.script;
} else if (prev.isWitnessPubkeyhash()) {
// Bare P2WPKH.
if (!utils.equal(prev.get(1), ring.keyHash))
return false;
prev = Script.fromPubkeyhash(prev.get(1));
} else {
// Bare... who knows?
return false;
}
} else {
// Wow, a normal output! Praise be to Jengus and Gord.
vector = input.script;
// Regular P2SH.
this.scriptVector(redeem, input.script, ring);
input.script.push(redeem.toRaw());
input.script.compile();
return true;
}
// Witness program.
if (prev.isProgram()) {
// Bare P2WSH.
if (prev.isWitnessScripthash()) {
redeem = ring.getRedeem(prev.get(1));
if (!redeem)
return false;
this.scriptVector(redeem, input.witness, ring);
input.witness.push(redeem.toRaw());
input.script.compile();
return true;
}
// Bare P2WPKH.
if (prev.isWitnessPubkeyhash()) {
prev = Script.fromPubkeyhash(prev.get(1));
this.scriptVector(prev, input.witness, ring);
input.script.compile();
return true;
}
// Bare... who knows?
return false;
}
// Wow, a normal output! Praise be to Jengus and Gord.
this.scriptVector(prev, input.script, ring);
return true;
};
MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
var i, n;
// P2PK
if (prev.isPubkey()) {
// P2PK
if (!utils.equal(prev.get(1), ring.publicKey))
return false;
@ -307,8 +332,12 @@ MTX.prototype.scriptInput = function scriptInput(index, ring) {
return true;
vector.set(0, opcodes.OP_0);
} else if (prev.isPubkeyhash()) {
// P2PKH
return;
}
// P2PKH
if (prev.isPubkeyhash()) {
if (!utils.equal(prev.get(2), ring.keyHash))
return false;
@ -318,8 +347,12 @@ MTX.prototype.scriptInput = function scriptInput(index, ring) {
vector.set(0, opcodes.OP_0);
vector.set(1, ring.publicKey);
} else if (prev.isMultisig()) {
// Multisig
return;
}
// Multisig
if (prev.isMultisig()) {
if (prev.indexOf(ring.publicKey) === -1)
return false;
@ -338,41 +371,28 @@ MTX.prototype.scriptInput = function scriptInput(index, ring) {
// Fill script with `n` signature slots.
for (i = 0; i < n; i++)
vector.set(i + 1, opcodes.OP_0);
} else {
if (prev.indexOf(ring.publicKey) === -1)
return false;
// Already has a script template (at least)
if (vector.length !== 0)
return true;
// Likely a non-standard scripthash multisig
// input. Determine n value by counting keys.
// Also, only allow nonstandard types for
// scripthash.
vector.set(0, opcodes.OP_0);
// Fill script with `n` signature slots.
for (i = 0; i < prev.length; i++) {
if (Script.isKey(prev.get(i)))
vector.set(i + 1, opcodes.OP_0);
}
return;
}
// P2SH requires the redeem
// script after signatures.
if (redeemScript)
input.script.push(redeemScript);
if (prev.indexOf(ring.publicKey) === -1)
return false;
// P2WSH requires the witness
// script after signatures.
if (witnessScript)
input.witness.push(witnessScript);
// Already has a script template (at least)
if (vector.length !== 0)
return true;
input.script.compile();
input.witness.compile();
// Likely a non-standard scripthash multisig
// input. Determine n value by counting keys.
// Also, only allow nonstandard types for
// scripthash.
vector.set(0, opcodes.OP_0);
return true;
// Fill script with `n` signature slots.
for (i = 0; i < prev.length; i++) {
if (Script.isKey(prev.get(i)))
vector.set(i + 1, opcodes.OP_0);
}
};
/**