mtx: more refactoring.
This commit is contained in:
parent
0db8677139
commit
b6c8362c63
151
lib/bcoin/mtx.js
151
lib/bcoin/mtx.js
@ -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}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user