mtx: more refactoring.

This commit is contained in:
Christopher Jeffrey 2016-08-18 15:06:02 -07:00
parent 0db8677139
commit b6c8362c63
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -228,16 +228,12 @@ MTX.prototype.scriptInput = function scriptInput(index, ring) {
if (!input.coin) if (!input.coin)
return false; return false;
// Optimization: Don't bother with any below // Don't bother with any below calculation
// calculation if the output is already templated. // if the output is already templated.
// Just say this is "our" output.
if (input.script.length !== 0 || input.witness.length !== 0) if (input.script.length !== 0 || input.witness.length !== 0)
return true; return true;
// Optimization: test output against the // Make sure this coin is ours.
// address map to avoid unnecessary calculation.
// A hash table lookup may be faster than all
// the nonsense below.
if (!ring.ownOutput(input.coin)) if (!ring.ownOutput(input.coin))
return false; return false;
@ -333,7 +329,7 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
vector.set(0, opcodes.OP_0); vector.set(0, opcodes.OP_0);
return; return true;
} }
// P2PKH // P2PKH
@ -348,7 +344,7 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
vector.set(0, opcodes.OP_0); vector.set(0, opcodes.OP_0);
vector.set(1, ring.publicKey); vector.set(1, ring.publicKey);
return; return true;
} }
// Multisig // Multisig
@ -372,7 +368,7 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
vector.set(i + 1, opcodes.OP_0); vector.set(i + 1, opcodes.OP_0);
return; return true;
} }
if (prev.indexOf(ring.publicKey) === -1) if (prev.indexOf(ring.publicKey) === -1)
@ -435,38 +431,31 @@ MTX.prototype.createSignature = function createSignature(index, prev, key, type,
*/ */
MTX.prototype.signInput = function signInput(index, ring, key, type) { MTX.prototype.signInput = function signInput(index, ring, key, type) {
var input, prev, signature, keyIndex, signatures, i; var input = this.inputs[index];
var len, m, n, keys, vector, version; var version = 0;
var redeem = false;
var prev, vector, signature, result;
// Get the input
input = this.inputs[index];
assert(input); assert(input);
// We should have previous outputs by now. // We should have previous outputs by now.
if (!input.coin) if (!input.coin)
return false; return false;
// Optimization: test output against the // Make sure this output is ours.
// address map to avoid unnecessary calculation.
// A hash table lookup may be faster than all
// the nonsense below.
if (!ring.ownOutput(input.coin)) if (!ring.ownOutput(input.coin))
return false; return false;
// Get the previous output's script // Get the previous output's script
prev = input.coin.script; prev = input.coin.script;
vector = input.script; vector = input.script;
len = vector.length;
version = 0;
// We need to grab the redeem script when // Grab regular p2sh redeem script.
// signing p2sh transactions.
if (prev.isScripthash()) { if (prev.isScripthash()) {
prev = input.script.getRedeem(); prev = input.script.getRedeem();
if (!prev) if (!prev)
throw new Error('Input has not been templated.'); throw new Error('Input has not been templated.');
len = vector.length - 1; redeem = true;
} }
// If the output script is a witness program, // If the output script is a witness program,
@ -480,18 +469,32 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
if (!prev) if (!prev)
throw new Error('Input has not been templated.'); throw new Error('Input has not been templated.');
vector = input.witness; vector = input.witness;
len = vector.length - 1; redeem = true;
version = 1; version = 1;
} else if (prev.isWitnessPubkeyhash()) { } else if (prev.isWitnessPubkeyhash()) {
prev = Script.fromPubkeyhash(prev.get(1)); prev = Script.fromPubkeyhash(prev.get(1));
vector = input.witness; vector = input.witness;
len = vector.length; redeem = false;
version = 1; version = 1;
} }
// Create our signature. // Create our signature.
signature = this.createSignature(index, prev, key, type, version); signature = this.createSignature(index, prev, key, type, version);
if (redeem) {
redeem = vector.pop();
result = this.signVector(prev, vector, signature, ring);
vector.push(redeem);
vector.compile();
return result;
}
return this.signVector(prev, vector, signature, ring);
};
MTX.prototype.signVector = function signVector(prev, vector, signature, ring) {
var keys, i, m, n, signatures, keyIndex;
// P2PK // P2PK
if (prev.isPubkey()) { if (prev.isPubkey()) {
// Already signed. // Already signed.
@ -545,11 +548,6 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
// Grab `n` value (number of keys). // Grab `n` value (number of keys).
n = prev.getSmall(prev.length - 2); n = prev.getSmall(prev.length - 2);
} else { } else {
// Only allow non-standard signing for
// scripthash.
if (len !== vector.length - 1)
return false;
keys = []; keys = [];
for (i = 0; i < prev.length; i++) { for (i = 0; i < prev.length; i++) {
@ -566,29 +564,25 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
if (vector.getSmall(0) !== 0) if (vector.getSmall(0) !== 0)
throw new Error('Input has not been templated.'); throw new Error('Input has not been templated.');
// Something is very wrong here. Abort. // Too many signature slots. Abort.
if (len - 1 > n) if (vector.length - 1 > n)
return false; return false;
// Count the number of current signatures. // Count the number of current signatures.
signatures = 0; signatures = 0;
for (i = 1; i < len; i++) { for (i = 1; i < vector.length; i++) {
if (Script.isSignature(vector.get(i))) if (Script.isSignature(vector.get(i)))
signatures++; signatures++;
} }
// Signatures are already finalized. // Signatures are already finalized.
if (signatures === m && len - 1 === m) if (signatures === m && vector.length - 1 === m)
return true; return true;
// This can happen in a case where another // Add some signature slots for us to use if
// implementation adds signatures willy-nilly // there was for some reason not enough.
// or by `m`. Add some signature slots for while (vector.length - 1 < n)
// us to use. vector.push(opcodes.OP_0);
while (len - 1 < n) {
vector.insert(len, opcodes.OP_0);
len++;
}
// Find the key index so we can place // Find the key index so we can place
// the signature in the same index. // the signature in the same index.
@ -608,7 +602,7 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
// Add our signature to the correct slot // Add our signature to the correct slot
// and increment the total number of // and increment the total number of
// signatures. // signatures.
if (keyIndex < len && signatures < m) { if (keyIndex < vector.length && signatures < m) {
if (vector.getSmall(keyIndex) === 0) { if (vector.getSmall(keyIndex) === 0) {
vector.set(keyIndex, signature); vector.set(keyIndex, signature);
signatures++; signatures++;
@ -618,26 +612,21 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
// All signatures added. Finalize. // All signatures added. Finalize.
if (signatures >= m) { if (signatures >= m) {
// Remove empty slots left over. // Remove empty slots left over.
for (i = len - 1; i >= 1; i--) { for (i = vector.length - 1; i >= 1; i--) {
if (vector.getSmall(i) === 0) { if (vector.getSmall(i) === 0)
vector.remove(i); vector.remove(i);
len--;
}
} }
// Remove signatures which are not required. // Remove signatures which are not required.
// This should never happen except when dealing // This should never happen.
// with implementations that potentially handle
// signature slots differently.
while (signatures > m) { while (signatures > m) {
vector.remove(len - 1); vector.pop();
signatures--; signatures--;
len--;
} }
// Sanity checks. // Sanity checks.
assert(signatures === m); assert(signatures === m);
assert(len - 1 === m); assert(vector.length - 1 === m);
} }
vector.compile(); vector.compile();
@ -645,6 +634,60 @@ MTX.prototype.signInput = function signInput(index, ring, key, type) {
return signatures === m; return signatures === m;
}; };
MTX.prototype.combineMultisig = function combineMultisig(index, prev, version, script, signature) {
var m = prev.getSmall(0);
var sigs = [signature];
var map = {};
var result;
var i, j, sig, type, msg, key, pub, res;
for (i = 1; i < script.length; i++) {
sig = script.get(i);
if (Script.isSignature(sig))
sigs.push(sig);
}
for (i = 0; i < sigs.length; i++) {
sig = sigs[i];
type = sig[sig.length - 1];
msg = this.signatureHash(index, prev, type, version);
for (j = 1; j < prev.length - 2; j++) {
key = prev.get(j);
pub = key.toString('hex');
if (map[pub])
continue;
res = Script.checksig(msg, sig, key);
if (res) {
map[pub] = sig;
if (utils.equal(sig, signature))
result = true;
break;
}
}
}
script.clear();
script.push(opcodes.OP_0);
for (i = 1; i < prev.length - 2; i++) {
key = prev.get(i);
pub = key.toString('hex');
sig = map[pub];
if (sig)
script.push(sig);
}
while (script.length - 1 < m)
script.push(opcodes.OP_0);
script.compile();
return result;
};
/** /**
* Test whether the transaction is fully-signed. * Test whether the transaction is fully-signed.
* @returns {Boolean} * @returns {Boolean}