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)
|
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}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user