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