separate TxProposal to a different class. new tests
This commit is contained in:
parent
96a5f0aeb8
commit
6e5f06693d
5 changed files with 810 additions and 664 deletions
226
js/models/core/TxProposal.js
Normal file
226
js/models/core/TxProposal.js
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var bitcore = require('bitcore');
|
||||||
|
var util = bitcore.util;
|
||||||
|
var Transaction = bitcore.Transaction;
|
||||||
|
var BuilderMockV0 = require('./BuilderMockV0');;
|
||||||
|
var TransactionBuilder = bitcore.TransactionBuilder;
|
||||||
|
var Script = bitcore.Script;
|
||||||
|
var Key = bitcore.Key;
|
||||||
|
var buffertools = bitcore.buffertools;
|
||||||
|
var preconditions = require('preconditions').instance();
|
||||||
|
|
||||||
|
|
||||||
|
function TxProposal(opts) {
|
||||||
|
preconditions.checkArgument(opts);
|
||||||
|
preconditions.checkArgument(opts.inputChainPaths);
|
||||||
|
preconditions.checkArgument(opts.creator);
|
||||||
|
preconditions.checkArgument(opts.createdTs);
|
||||||
|
preconditions.checkArgument(opts.builder);
|
||||||
|
|
||||||
|
|
||||||
|
this.creator = opts.creator;
|
||||||
|
this.createdTs = opts.createdTs;
|
||||||
|
this.builder = opts.builder;
|
||||||
|
this.inputChainPaths = opts.inputChainPaths;
|
||||||
|
|
||||||
|
this._inputSignedBy = [];
|
||||||
|
this.seenBy = opts.seenBy || {};
|
||||||
|
this.signedBy = opts.signedBy || {};
|
||||||
|
this.rejectedBy = opts.rejectedBy || {};
|
||||||
|
this.sentTs = opts.sentTs || null;
|
||||||
|
this.sentTxid = opts.sentTxid || null;
|
||||||
|
this.comment = opts.comment || null;
|
||||||
|
this.readonly = opts.readonly || null;
|
||||||
|
this._updateSignedBy();
|
||||||
|
}
|
||||||
|
|
||||||
|
TxProposal.prototype.getId = function() {
|
||||||
|
return this.builder.build().getNormalizedHash().toString('hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.toObj = function() {
|
||||||
|
var o = JSON.parse(JSON.stringify(this));
|
||||||
|
delete o['builder'];
|
||||||
|
o.builderObj = this.builder.toObj();
|
||||||
|
return o;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TxProposal.prototype.setSent = function(sentTxid) {
|
||||||
|
this.sentTxid = sentTxid;
|
||||||
|
this.sentTs = Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.fromObj = function(o, forceOpts) {
|
||||||
|
preconditions.checkArgument(o.builderObj);
|
||||||
|
delete o['builder'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// force opts is requested.
|
||||||
|
for (var k in forceOpts) {
|
||||||
|
o.builderObj.opts[k] = forceOpts[k];
|
||||||
|
}
|
||||||
|
o.builder = TransactionBuilder.fromObj(o.builderObj);
|
||||||
|
} catch (e) {
|
||||||
|
if (!o.version) {
|
||||||
|
o.builder = new BuilderMockV0(o.builderObj);
|
||||||
|
o.readonly = 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var t = new TxProposal(o);
|
||||||
|
t._throwIfInvalid();
|
||||||
|
t._updateSignedBy();
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TxProposal.prototype._formatKeys = function(allowedPubKeys) {
|
||||||
|
var keys = [];
|
||||||
|
for (var i in allowedPubKeys) {
|
||||||
|
if (!Buffer.isBuffer(allowedPubKeys[i]))
|
||||||
|
throw new Error('allowedPubKeys must be buffers');
|
||||||
|
|
||||||
|
var k = new Key();
|
||||||
|
k.public = allowedPubKeys[i];
|
||||||
|
keys.push[k];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype._verifySignatures = function(inKeys, scriptSig, txSigHash) {
|
||||||
|
preconditions.checkArgument(Buffer.isBuffer(txSigHash));
|
||||||
|
|
||||||
|
if (scriptSig.chunks[0] !== 0)
|
||||||
|
throw new Error('Invalid scriptSig');
|
||||||
|
|
||||||
|
var keys = this._formatKeys(inKeys);
|
||||||
|
var ret = [];
|
||||||
|
for (var i = 1; typeof ret === 'undefined' && i <= scriptSig.countSignatures(); i++) {
|
||||||
|
var chunk = scriptSig.chunks[i];
|
||||||
|
var sigRaw = new Buffer(chunk.slice(0, chunk.length - 1));
|
||||||
|
for (var j in keys) {
|
||||||
|
var k = keys[j];
|
||||||
|
if (k.verifySignatureSync(txSigHash, sigRaw)) {
|
||||||
|
ret.push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype._keysFromRedeemScript = function(s) {
|
||||||
|
var redeemScript = new Script(s.chunks[s.chunks.length-1]);
|
||||||
|
if (!redeemScript)
|
||||||
|
throw new Error('Bad scriptSig');
|
||||||
|
var pubkeys = redeemScript.capture();
|
||||||
|
if (!pubkeys || !pubkeys.length)
|
||||||
|
throw new Error('Bad scriptSig');
|
||||||
|
|
||||||
|
return pubkeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype._updateSignedBy = function() {
|
||||||
|
this._inputSignedBy = [];
|
||||||
|
|
||||||
|
var tx = this.builder.build();
|
||||||
|
for (var i in tx.ins) {
|
||||||
|
var scriptSig = new Script(tx.ins[i].s);
|
||||||
|
|
||||||
|
var keys = this._keysFromRedeemScript(scriptSig);
|
||||||
|
var txSigHash = tx.hashForSignature(this.builder.inputMap[i].scriptPubKey, i, Transaction.SIGHASH_ALL);
|
||||||
|
var copayerIndex = this._verifySignatures(keys, scriptSig, txSigHash);
|
||||||
|
if (typeof copayerIndex === 'undefined')
|
||||||
|
throw new Error('Invalid signature');
|
||||||
|
this._inputSignedBy[i] = this._inputSignedBy[i] || {};
|
||||||
|
this._inputSignedBy[i][copayerIndex] = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.isValid = function() {
|
||||||
|
|
||||||
|
if (this.builder.signhash && this.builder.signhash !== Transaction.SIGHASH_ALL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.builder.build();
|
||||||
|
if (!tx.ins.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < tx.ins.length; i++) {
|
||||||
|
var hashType = tx.getHashType(i);
|
||||||
|
if (hashType && hashType !== Transaction.SIGHASH_ALL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[TxProposal.js.145]'); //TODO
|
||||||
|
|
||||||
|
//Should be signed
|
||||||
|
var scriptSigs = this.builder.vanilla.scriptSigs;
|
||||||
|
if (!scriptSigs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
console.log('[TxProposal.js.153]'); //TODO
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TxProposal.prototype._throwIfInvalid = function(allowedPubKeys) {
|
||||||
|
if (!this.isValid(allowedPubKeys))
|
||||||
|
throw new Error('Invalid tx proposal');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TxProposal.prototype.merge = function(incoming, allowedPubKeys) {
|
||||||
|
var ret = {};
|
||||||
|
ret.events = [];
|
||||||
|
incoming._throwIfInvalid(allowedPubKeys);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
/*
|
||||||
|
events.push({
|
||||||
|
type: 'seen',
|
||||||
|
cId: k,
|
||||||
|
txId: ntxid
|
||||||
|
});
|
||||||
|
events.push({
|
||||||
|
type: 'signed',
|
||||||
|
cId: k,
|
||||||
|
txId: ntxid
|
||||||
|
});
|
||||||
|
events.push({
|
||||||
|
type: 'rejected',
|
||||||
|
cId: k,
|
||||||
|
txId: ntxid
|
||||||
|
});
|
||||||
|
ret.events = this.mergeMetadata(incoming);
|
||||||
|
*/
|
||||||
|
ret.hasChanged = this.mergeBuilder(incoming);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.mergeBuilder = function(incoming) {
|
||||||
|
var b0 = this.builder;
|
||||||
|
var b1 = incoming.builder;
|
||||||
|
|
||||||
|
var before = JSON.stringify(b0.toObj());
|
||||||
|
b0.merge(b1);
|
||||||
|
var after = JSON.stringify(b0.toObj());
|
||||||
|
return after !== before;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//This should be on bitcore / Transaction
|
||||||
|
TxProposal.prototype.countSignatures = function() {
|
||||||
|
var tx = this.builder.build();
|
||||||
|
|
||||||
|
var ret = 0;
|
||||||
|
for (var i in tx.ins) {
|
||||||
|
ret += tx.countInputSignatures(i);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
module.exports = TxProposal;
|
||||||
|
|
@ -1,297 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
|
|
||||||
var imports = require('soop').imports();
|
|
||||||
var bitcore = require('bitcore');
|
|
||||||
var util = bitcore.util;
|
|
||||||
var Transaction = bitcore.Transaction;
|
|
||||||
var BuilderMockV0 = require('./BuilderMockV0');;
|
|
||||||
var TransactionBuilder = bitcore.TransactionBuilder;
|
|
||||||
var Script = bitcore.Script;
|
|
||||||
var Key = bitcore.Key;
|
|
||||||
var buffertools = bitcore.buffertools;
|
|
||||||
var preconditions = require('preconditions').instance();
|
|
||||||
var COPAY_EPOCH = 1400000000000;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function TxProposal(opts) {
|
|
||||||
this.creator = opts.creator;
|
|
||||||
this.createdTs = opts.createdTs;
|
|
||||||
this.seenBy = opts.seenBy || {};
|
|
||||||
this.signedBy = opts.signedBy || {};
|
|
||||||
this.rejectedBy = opts.rejectedBy || {};
|
|
||||||
this.builder = opts.builder;
|
|
||||||
this.sentTs = opts.sentTs || null;
|
|
||||||
this.sentTxid = opts.sentTxid || null;
|
|
||||||
this.inputChainPaths = opts.inputChainPaths || [];
|
|
||||||
this.comment = opts.comment || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
TxProposal.prototype.getID = function() {
|
|
||||||
return this.builder.build().getNormalizedHash().toString('hex');
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposal.prototype.toObj = function() {
|
|
||||||
var o = JSON.parse(JSON.stringify(this));
|
|
||||||
delete o['builder'];
|
|
||||||
o.builderObj = this.builder.toObj();
|
|
||||||
return o;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
TxProposal.prototype.setSent = function(sentTxid) {
|
|
||||||
this.sentTxid = sentTxid;
|
|
||||||
this.sentTs = Date.now();
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposal.fromObj = function(o, forceOpts) {
|
|
||||||
var t = new TxProposal(o);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// force opts is requested.
|
|
||||||
for (var k in forceOpts) {
|
|
||||||
o.builderObj.opts[k] = forceOpts[k];
|
|
||||||
}
|
|
||||||
t.builder = TransactionBuilder.fromObj(o.builderObj);
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
if (!o.version) {
|
|
||||||
t.builder = new BuilderMockV0(o.builderObj);
|
|
||||||
t.readonly = 1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
TxProposal.prototype.isValid = function() {
|
|
||||||
if (this.builder.signhash && this.builder.signhash !== Transaction.SIGHASH_ALL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var tx = this.builder.build();
|
|
||||||
for (var i = 0; i < tx.ins.length; i++) {
|
|
||||||
var hashType = tx.getHashType(i);
|
|
||||||
if (hashType && hashType !== Transaction.SIGHASH_ALL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that has valid signatures
|
|
||||||
var tx = this.builder.build();
|
|
||||||
|
|
||||||
for (var i = 0; i < tx.ins.length; i++) {
|
|
||||||
|
|
||||||
var txSigHash = this.tx.hashForSignature(
|
|
||||||
this.builder.inputMap[i].scriptPubKey, i, Transaction.SIGHASH_ALL);
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposal.getSentTs = function() {
|
|
||||||
return this.sentTs;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposal.prototype.merge = function(incoming, author) {
|
|
||||||
var ret = {};
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
/*
|
|
||||||
events.push({
|
|
||||||
type: 'seen',
|
|
||||||
cId: k,
|
|
||||||
txId: ntxid
|
|
||||||
});
|
|
||||||
events.push({
|
|
||||||
type: 'signed',
|
|
||||||
cId: k,
|
|
||||||
txId: ntxid
|
|
||||||
});
|
|
||||||
events.push({
|
|
||||||
type: 'rejected',
|
|
||||||
cId: k,
|
|
||||||
txId: ntxid
|
|
||||||
});
|
|
||||||
ret.events = this.mergeMetadata(incoming, author);
|
|
||||||
*/
|
|
||||||
ret.hasChanged = this.mergeBuilder(other);
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposal.prototype.mergeBuilder = function(other) {
|
|
||||||
var b0 = this.builder;
|
|
||||||
var b1 = other.builder;
|
|
||||||
|
|
||||||
var before = JSON.stringify(b0.toObj());
|
|
||||||
b0.merge(b1);
|
|
||||||
var after = JSON.stringify(b0.toObj());
|
|
||||||
return after !== before;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//This should be on bitcore / Transaction
|
|
||||||
TxProposal.prototype.countSignatures = function() {
|
|
||||||
var tx = this.builder.build();
|
|
||||||
|
|
||||||
var ret = 0;
|
|
||||||
for (var i in tx.ins) {
|
|
||||||
ret += tx.countInputSignatures(i);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = require('soop')(TxProposal);
|
|
||||||
|
|
||||||
|
|
||||||
function TxProposals(opts) {
|
|
||||||
opts = opts || {};
|
|
||||||
this.walletId = opts.walletId;
|
|
||||||
this.network = opts.networkName === 'livenet' ?
|
|
||||||
bitcore.networks.livenet : bitcore.networks.testnet;
|
|
||||||
this.txps = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
TxProposals.fromObj = function(o, forceOpts) {
|
|
||||||
var ret = new TxProposals({
|
|
||||||
networkName: o.networkName,
|
|
||||||
walletId: o.walletId,
|
|
||||||
});
|
|
||||||
|
|
||||||
o.txps.forEach(function(o2) {
|
|
||||||
var t = TxProposal.fromObj(o2, forceOpts);
|
|
||||||
if (t.builder) {
|
|
||||||
var id = t.getID();
|
|
||||||
ret.txps[id] = t;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.prototype.getNtxids = function() {
|
|
||||||
return Object.keys(this.txps);
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.prototype.toObj = function(onlyThisNtxid) {
|
|
||||||
if (onlyThisNtxid) throw new Error();
|
|
||||||
var ret = [];
|
|
||||||
for (var id in this.txps) {
|
|
||||||
|
|
||||||
if (onlyThisNtxid && id != onlyThisNtxid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var t = this.txps[id];
|
|
||||||
if (!t.sent)
|
|
||||||
ret.push(t.toObj());
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
txps: ret,
|
|
||||||
walletId: this.walletId,
|
|
||||||
networkName: this.network.name,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.prototype.merge = function(inTxp, author) {
|
|
||||||
var myTxps = this.txps;
|
|
||||||
|
|
||||||
var ntxid = inTxp.getID();
|
|
||||||
var ret = {};
|
|
||||||
ret.events = [];
|
|
||||||
ret.events.hasChanged = false;
|
|
||||||
|
|
||||||
if (myTxps[ntxid]) {
|
|
||||||
var v0 = myTxps[ntxid];
|
|
||||||
var v1 = inTxp;
|
|
||||||
ret = v0.merge(v1, author);
|
|
||||||
} else {
|
|
||||||
this.txps[ntxid] = inTxp;
|
|
||||||
ret.hasChanged = true;
|
|
||||||
ret.events.push({
|
|
||||||
type: 'new',
|
|
||||||
cid: inTxp.creator,
|
|
||||||
tx: ntxid
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.prototype.add = function(data) {
|
|
||||||
preconditions.checkArgument(data.inputChainPaths);
|
|
||||||
preconditions.checkArgument(data.signedBy);
|
|
||||||
preconditions.checkArgument(data.creator);
|
|
||||||
preconditions.checkArgument(data.createdTs);
|
|
||||||
preconditions.checkArgument(data.builder);
|
|
||||||
var txp = new TxProposal(data);
|
|
||||||
var ntxid = txp.getID();
|
|
||||||
this.txps[ntxid] = txp;
|
|
||||||
return ntxid;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.prototype.setSent = function(ntxid, txid) {
|
|
||||||
//sent TxProposals are local an not broadcasted.
|
|
||||||
this.txps[ntxid].setSent(txid);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
TxProposals.prototype.getTxProposal = function(ntxid, copayers) {
|
|
||||||
var txp = this.txps[ntxid];
|
|
||||||
var i = JSON.parse(JSON.stringify(txp));
|
|
||||||
i.builder = txp.builder;
|
|
||||||
i.ntxid = ntxid;
|
|
||||||
i.peerActions = {};
|
|
||||||
|
|
||||||
if (copayers) {
|
|
||||||
for (var j = 0; j < copayers.length; j++) {
|
|
||||||
var p = copayers[j];
|
|
||||||
i.peerActions[p] = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var p in txp.seenBy) {
|
|
||||||
i.peerActions[p] = {
|
|
||||||
seen: txp.seenBy[p]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
for (var p in txp.signedBy) {
|
|
||||||
i.peerActions[p] = i.peerActions[p] || {};
|
|
||||||
i.peerActions[p].sign = txp.signedBy[p];
|
|
||||||
}
|
|
||||||
var r = 0;
|
|
||||||
for (var p in txp.rejectedBy) {
|
|
||||||
i.peerActions[p] = i.peerActions[p] || {};
|
|
||||||
i.peerActions[p].rejected = txp.rejectedBy[p];
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
i.rejectCount = r;
|
|
||||||
|
|
||||||
var c = txp.creator;
|
|
||||||
i.peerActions[c] = i.peerActions[c] || {};
|
|
||||||
i.peerActions[c].create = txp.createdTs;
|
|
||||||
return i;
|
|
||||||
};
|
|
||||||
|
|
||||||
//returns the unspent txid-vout used in PENDING Txs
|
|
||||||
TxProposals.prototype.getUsedUnspent = function(maxRejectCount) {
|
|
||||||
var ret = {};
|
|
||||||
for (var i in this.txps) {
|
|
||||||
var u = this.txps[i].builder.getSelectedUnspent();
|
|
||||||
var p = this.getTxProposal(i);
|
|
||||||
if (p.rejectCount > maxRejectCount || p.sentTxid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var j in u) {
|
|
||||||
ret[u[j].txid + ',' + u[j].vout] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
TxProposals.TxProposal = TxProposal;
|
|
||||||
module.exports = require('soop')(TxProposals);
|
|
||||||
37
test/mocks/FakeBuilder.js
Normal file
37
test/mocks/FakeBuilder.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
'use scrict';
|
||||||
|
var bitcore = bitcore || require('bitcore');
|
||||||
|
var Script = bitcore.Script;
|
||||||
|
|
||||||
|
|
||||||
|
function Tx() {
|
||||||
|
this.ins = [{s: new Buffer('0048304502200708a381dde585ef7fdfaeaeb5da9b451d3e22b01eac8a5e3d03b959e24a7478022100c90e76e423523a54a9e9c43858337ebcef1a539a7fc685c2698dd8648fcf1b9101473044022030a77c9613d6ee010717c1abc494668d877e3fa0ae4c520f65cc3b308754c98c02205219d387bcb291bd44805b9468439e4168b02a6a180cdbcc24d84d71d696c1ae014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae','hex')}];
|
||||||
|
};
|
||||||
|
|
||||||
|
Tx.prototype.getNormalizedHash = function() {
|
||||||
|
return '123456';
|
||||||
|
};
|
||||||
|
Tx.prototype.hashForSignature = function() {
|
||||||
|
return new Buffer('72403de587240b85855da2ebd29b7dab5d170a9662d4bf7c4980358b14091696','hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function FakeBuilder() {
|
||||||
|
this.test = 1;
|
||||||
|
this.tx = new Tx();
|
||||||
|
this.signhash = 1;
|
||||||
|
this.inputMap = [{ address: '2NDJbzwzsmRgD2o5HHXPhuq5g6tkKTjYkd6',
|
||||||
|
scriptPubKey: new Script(new Buffer('a914dc0623476aefb049066b09b0147a022e6eb8429187', 'hex')),
|
||||||
|
scriptType: 4,
|
||||||
|
i: 0 }];
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeBuilder.prototype.build = function() {
|
||||||
|
return this.tx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FakeBuilder.prototype.toObj = function() {
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FakeBuilder;
|
||||||
170
test/test.TxProposal.js
Normal file
170
test/test.TxProposal.js
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var chai = chai || require('chai');
|
||||||
|
var should = chai.should();
|
||||||
|
var bitcore = bitcore || require('bitcore');
|
||||||
|
var Transaction = bitcore.Transaction;
|
||||||
|
var buffertools = bitcore.buffertools;
|
||||||
|
var WalletKey = bitcore.WalletKey;
|
||||||
|
var Key = bitcore.Key;
|
||||||
|
var bignum = bitcore.Bignum;
|
||||||
|
var Script = bitcore.Script;
|
||||||
|
var TransactionBuilder = bitcore.TransactionBuilder;
|
||||||
|
var util = bitcore.util;
|
||||||
|
var networks = bitcore.networks;
|
||||||
|
var sinon = require('sinon');
|
||||||
|
try {
|
||||||
|
var copay = require('copay'); //browser
|
||||||
|
} catch (e) {
|
||||||
|
var copay = require('../copay'); //node
|
||||||
|
}
|
||||||
|
|
||||||
|
var FakeBuilder = require('./mocks/FakeBuilder');
|
||||||
|
var TxProposal = copay.TxProposal;
|
||||||
|
|
||||||
|
var dummyProposal = new TxProposal({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builder: new FakeBuilder(),
|
||||||
|
inputChainPaths: ['m/1'],
|
||||||
|
});
|
||||||
|
|
||||||
|
var someKeys = ["03b39d61dc9a504b13ae480049c140dcffa23a6cc9c09d12d6d1f332fee5e18ca5","022929f515c5cf967474322468c3bd945bb6f281225b2c884b465680ef3052c07e"];
|
||||||
|
|
||||||
|
describe('TxProposal', function() {
|
||||||
|
describe('new', function() {
|
||||||
|
it('should fail to create an instance with wrong arguments', function() {
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var txp = new TxProposal();
|
||||||
|
}).should.throw('Illegal Argument');
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var txp = new TxProposal({
|
||||||
|
creator: 1
|
||||||
|
});
|
||||||
|
}).should.throw('Illegal Argument');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should create an instance', function() {
|
||||||
|
var txp = new TxProposal({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builder: new FakeBuilder(),
|
||||||
|
inputChainPaths: 'm/1',
|
||||||
|
});
|
||||||
|
should.exist(txp);
|
||||||
|
|
||||||
|
txp.creator.should.equal(1);
|
||||||
|
should.exist(txp.builder);
|
||||||
|
txp.inputChainPaths.should.equal('m/1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getId', function() {
|
||||||
|
it('should return id',function() {
|
||||||
|
var b = new FakeBuilder();
|
||||||
|
var spy = sinon.spy(b.tx, 'getNormalizedHash');
|
||||||
|
var txp = new TxProposal({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builder: b,
|
||||||
|
inputChainPaths: 'm/1',
|
||||||
|
});
|
||||||
|
txp.getId().should.equal('123456');;
|
||||||
|
sinon.assert.callCount(spy,1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#toObj', function() {
|
||||||
|
it('should return an object and remove builder',function() {
|
||||||
|
var b = new FakeBuilder();
|
||||||
|
var txp = new TxProposal({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builder: b,
|
||||||
|
inputChainPaths: 'm/1',
|
||||||
|
});
|
||||||
|
var o = txp.toObj();
|
||||||
|
should.exist(o);
|
||||||
|
o.creator.should.equal(1);
|
||||||
|
should.not.exist(o.builder);
|
||||||
|
should.exist(o.builderObj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#fromObj', function() {
|
||||||
|
it.skip('should create from Object',function() {
|
||||||
|
var b = new FakeBuilder();
|
||||||
|
var txp = TxProposal.fromObj({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builderObj: b.toObj(),
|
||||||
|
inputChainPaths: ['m/1'] ,
|
||||||
|
});
|
||||||
|
should.exist(txp);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail to create from wrong object',function() {
|
||||||
|
var b = new FakeBuilder();
|
||||||
|
(function(){var txp = TxProposal.fromObj({
|
||||||
|
creator: 1,
|
||||||
|
createdTs: 1,
|
||||||
|
builderObj: b.toObj(),
|
||||||
|
inputChainPaths: ['m/1'] ,
|
||||||
|
});}).should.throw('Invalid');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setSent', function() {
|
||||||
|
it('should set txid and timestamp',function() {
|
||||||
|
var now = Date.now();
|
||||||
|
var txp = dummyProposal;
|
||||||
|
txp.setSent('3a42');
|
||||||
|
txp.sentTs.should.gte(now);
|
||||||
|
txp.sentTxid.should.equal('3a42');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('Signature verification', function() {
|
||||||
|
var validScriptSig = '00483045022100a35a5cbe37e39caa62bf1c347eae9c72be827c190b31494b184943b3012757a8022008a1ff72a34a5bf2fc955aa5b6f8a4c32cb0fab7e54c212a5f6f645bb95b8ef10149304602210092347916c3c3e6f1692bf9447b973779c28ce9985baaa3940b483af573f464b4022100ab91062796ab8acb32a0fa90e00627db5be77d9722400b3ecfd9c5f34a8092b1014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae';
|
||||||
|
|
||||||
|
var keyBuf = someKeys.map(function(hex){
|
||||||
|
return new Buffer(hex,'hex');
|
||||||
|
});
|
||||||
|
it('#_formatKeys',function() {
|
||||||
|
var txp = dummyProposal;
|
||||||
|
(function(){txp._formatKeys(someKeys);}).should.throw('buffers');
|
||||||
|
var res = txp._formatKeys(keyBuf);
|
||||||
|
});
|
||||||
|
it('#_verifyScriptSig arg checks',function() {
|
||||||
|
var txp = dummyProposal;
|
||||||
|
( function() { txp._verifySignatures(
|
||||||
|
keyBuf,
|
||||||
|
new bitcore.Script(new Buffer('112233','hex')),
|
||||||
|
new Buffer('1a','hex')); } ).should.throw('script');
|
||||||
|
});
|
||||||
|
it('#_verifyScriptSig, no signatures',function() {
|
||||||
|
var txp = dummyProposal;
|
||||||
|
var ret = txp._verifySignatures(
|
||||||
|
keyBuf,
|
||||||
|
new bitcore.Script(new Buffer(validScriptSig,'hex')),
|
||||||
|
new Buffer('1a','hex')
|
||||||
|
);
|
||||||
|
ret.length.should.equal(0);
|
||||||
|
});
|
||||||
|
it('#_verifyScriptSig, one signature',function() {
|
||||||
|
var txp = dummyProposal;
|
||||||
|
var ret = txp._verifySignatures(
|
||||||
|
[new Buffer('0380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127','hex')],
|
||||||
|
new bitcore.Script(new Buffer(validScriptSig,'hex')),
|
||||||
|
new Buffer('1a','hex')
|
||||||
|
);
|
||||||
|
ret.length.should.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -26,6 +26,8 @@ var PublicKeyRing = is_browser ? copay.PublicKeyRing :
|
||||||
Storage: fakeStorage
|
Storage: fakeStorage
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var isChange = false;
|
||||||
|
var addressIndex = 0;
|
||||||
var config = {
|
var config = {
|
||||||
networkName: 'testnet',
|
networkName: 'testnet',
|
||||||
};
|
};
|
||||||
|
|
@ -69,12 +71,88 @@ var vopts = {
|
||||||
dontVerifyStrictEnc: true
|
dontVerifyStrictEnc: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var createTx = function(toAddress, amountSatStr, utxos, opts, priv, pkr) {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var pub = priv.publicHex;
|
||||||
|
|
||||||
|
if (!pkr.isComplete()) {
|
||||||
|
throw new Error('publicKeyRing is not complete');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.remainderOut) {
|
||||||
|
opts.remainderOut = {
|
||||||
|
address: pkr.generateAddress(true, pub).toString()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var b = new TransactionBuilder(opts)
|
||||||
|
.setUnspent(utxos)
|
||||||
|
.setOutputs([{
|
||||||
|
address: toAddress,
|
||||||
|
amountSatStr: amountSatStr,
|
||||||
|
}]);
|
||||||
|
var selectedUtxos = b.getSelectedUnspent();
|
||||||
|
var inputChainPaths = selectedUtxos.map(function(utxo) {
|
||||||
|
return pkr.pathForAddress(utxo.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
var selectedUtxos = b.getSelectedUnspent();
|
||||||
|
|
||||||
|
var inputChainPaths = selectedUtxos.map(function(utxo) {
|
||||||
|
return pkr.pathForAddress(utxo.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths));
|
||||||
|
var signRet;
|
||||||
|
if (priv) {
|
||||||
|
var pkeys = priv.getForPaths(inputChainPaths);
|
||||||
|
b.sign(pkeys);
|
||||||
|
}
|
||||||
|
var me = {};
|
||||||
|
if (priv) me[priv.getId()] = Date.now();
|
||||||
|
var tx = b.build();
|
||||||
|
|
||||||
|
return {
|
||||||
|
inputChainPaths: inputChainPaths,
|
||||||
|
creator: priv.getId(),
|
||||||
|
createdTs: new Date(),
|
||||||
|
signedBy: priv && tx.countInputSignatures(0) ? {priv.getId(): true} : {},
|
||||||
|
seenBy: priv ? me : {},
|
||||||
|
builder: b,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var cachedTxProposals;
|
||||||
|
var getCachedTxProposals = function() {
|
||||||
|
if (!cachedTxProposals){
|
||||||
|
var priv = new PrivateKey(config);
|
||||||
|
var pub = priv.publicHex;
|
||||||
|
var w = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
var start = new Date().getTime();
|
||||||
|
var pkr = createPKR([priv]);
|
||||||
|
var ts = Date.now();
|
||||||
|
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest, {},
|
||||||
|
priv,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
cachedTxProposals = { tObj:w.toObj(), priv: priv};
|
||||||
|
}
|
||||||
|
cachedTxProposals.txp = TxProposals.fromObj(cachedTxProposals.tObj);
|
||||||
|
return cachedTxProposals;
|
||||||
|
};
|
||||||
|
|
||||||
describe('TxProposals model', function() {
|
describe('TxProposals model', function() {
|
||||||
|
|
||||||
var isChange = false;
|
|
||||||
var addressIndex = 0;
|
|
||||||
|
|
||||||
it('verify TXs', function(done) {
|
it('verify TXs', function(done) {
|
||||||
|
|
||||||
var priv = new PrivateKey(config);
|
var priv = new PrivateKey(config);
|
||||||
|
|
@ -136,59 +214,6 @@ describe('TxProposals model', function() {
|
||||||
w.network.name.should.equal(config.networkName);
|
w.network.name.should.equal(config.networkName);
|
||||||
});
|
});
|
||||||
|
|
||||||
var createTx = function(toAddress, amountSatStr, utxos, opts, priv, pkr) {
|
|
||||||
opts = opts || {};
|
|
||||||
|
|
||||||
var pub = priv.publicHex;
|
|
||||||
|
|
||||||
if (!pkr.isComplete()) {
|
|
||||||
throw new Error('publicKeyRing is not complete');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!opts.remainderOut) {
|
|
||||||
opts.remainderOut = {
|
|
||||||
address: pkr.generateAddress(true, pub).toString()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var b = new TransactionBuilder(opts)
|
|
||||||
.setUnspent(utxos)
|
|
||||||
.setOutputs([{
|
|
||||||
address: toAddress,
|
|
||||||
amountSatStr: amountSatStr,
|
|
||||||
}]);
|
|
||||||
var selectedUtxos = b.getSelectedUnspent();
|
|
||||||
var inputChainPaths = selectedUtxos.map(function(utxo) {
|
|
||||||
return pkr.pathForAddress(utxo.address);
|
|
||||||
});
|
|
||||||
|
|
||||||
var selectedUtxos = b.getSelectedUnspent();
|
|
||||||
|
|
||||||
var inputChainPaths = selectedUtxos.map(function(utxo) {
|
|
||||||
return pkr.pathForAddress(utxo.address);
|
|
||||||
});
|
|
||||||
|
|
||||||
b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths));
|
|
||||||
var signRet;
|
|
||||||
if (priv) {
|
|
||||||
var pkeys = priv.getForPaths(inputChainPaths);
|
|
||||||
b.sign(pkeys);
|
|
||||||
}
|
|
||||||
var me = {};
|
|
||||||
if (priv) me[priv.getId()] = Date.now();
|
|
||||||
|
|
||||||
var tx = b.build();
|
|
||||||
|
|
||||||
return {
|
|
||||||
inputChainPaths: inputChainPaths,
|
|
||||||
creator: priv.getId(),
|
|
||||||
createdTs: new Date(),
|
|
||||||
signedBy: priv && tx.countInputSignatures(0) ? me : {},
|
|
||||||
seenBy: priv ? me : {},
|
|
||||||
builder: b,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
it('#getUsedUnspend', function() {
|
it('#getUsedUnspend', function() {
|
||||||
var priv = new PrivateKey(config);
|
var priv = new PrivateKey(config);
|
||||||
|
|
@ -215,362 +240,347 @@ describe('TxProposals model', function() {
|
||||||
uuk[0].split(',')[0].should.equal(unspentTest[0].txid);
|
uuk[0].split(',')[0].should.equal(unspentTest[0].txid);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#merge with self', function() {
|
it.only('should create a correct uncomplete txp', function() {
|
||||||
var priv = new PrivateKey(config);
|
var c = getCachedTxProposals();
|
||||||
var pub = priv.publicHex;
|
var x = c.priv.getId();
|
||||||
|
var ntxid = Object.keys(c.txp.txps)[0];
|
||||||
var w = new TxProposals({
|
c.txp.txps[ntxid].signedBy[c.priv.getId()].should.equal(true);
|
||||||
networkName: config.networkName,
|
(c.txp.txps[ntxid].seenBy[c.priv.id] - ts > 0).should.equal(true);
|
||||||
});
|
|
||||||
var start = new Date().getTime();
|
|
||||||
var pkr = createPKR([priv]);
|
|
||||||
var ts = Date.now();
|
|
||||||
|
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest, {},
|
|
||||||
priv,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
var ntxid = Object.keys(w.txps)[0];
|
|
||||||
var tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
|
|
||||||
var x = priv.getId();
|
|
||||||
(w.txps[ntxid].signedBy[priv.getId()] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var info = w.merge(w.txps[ntxid], pkr.getCopayerId(0));
|
|
||||||
info.events.length.should.equal(0);
|
|
||||||
|
|
||||||
Object.keys(w.txps).length.should.equal(1);
|
|
||||||
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#merge', function() {
|
||||||
|
|
||||||
|
it('with self', function() {
|
||||||
|
var t = txps.fromObj(txpsObj);
|
||||||
|
var info = w.merge(w.txps[ntxid], pkr.getCopayerId(0));
|
||||||
|
info.events.length.should.equal(0);
|
||||||
|
|
||||||
|
Object.keys(w.txps).length.should.equal(1);
|
||||||
|
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
|
||||||
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it('#merge, merge signatures case 1', function() {
|
|
||||||
var priv2 = new PrivateKey(config);
|
|
||||||
var priv = new PrivateKey(config);
|
|
||||||
var pub = priv.publicHex;
|
|
||||||
|
|
||||||
var ts = Date.now();
|
it('#merge, merge signatures case 1', function() {
|
||||||
var pkr = createPKR([priv]);
|
var priv2 = new PrivateKey(config);
|
||||||
var opts = {
|
var priv = new PrivateKey(config);
|
||||||
remainderOut: {
|
var pub = priv.publicHex;
|
||||||
address: pkr.generateAddress(true, pub).toString()
|
|
||||||
|
var ts = Date.now();
|
||||||
|
var pkr = createPKR([priv]);
|
||||||
|
var opts = {
|
||||||
|
remainderOut: {
|
||||||
|
address: pkr.generateAddress(true, pub).toString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var w = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv2,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
|
||||||
|
var ntxid = Object.keys(w.txps)[0];
|
||||||
|
var tx = w.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputSignatures(0).should.equal(0);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
|
||||||
|
Object.keys(w.txps[ntxid].signedBy).length.should.equal(0);
|
||||||
|
Object.keys(w.txps[ntxid].seenBy).length.should.equal(1);
|
||||||
|
|
||||||
|
|
||||||
|
var w2 = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
publicKeyRing: w.publicKeyRing,
|
||||||
|
});
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w2.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
|
||||||
|
var ntxid = Object.keys(w.txps)[0];
|
||||||
|
var tx = w2.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
|
||||||
|
|
||||||
|
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true, 'asdsd');
|
||||||
|
(w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(0));
|
||||||
|
console.log('[test.TxProposals.js.323:info:]',info); //TODO
|
||||||
|
info.events.length.should.equal(2);
|
||||||
|
info.events[0].type.should.equal('seen');
|
||||||
|
info.events[1].type.should.equal('signed');
|
||||||
|
|
||||||
|
Object.keys(w.txps).length.should.equal(1);
|
||||||
|
|
||||||
|
var tx = w.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var _dumpChunks = function(scriptSig, label) {
|
||||||
|
console.log('## DUMP: ' + label + ' ##');
|
||||||
|
for (var i = 0; i < scriptSig.chunks.length; i++) {
|
||||||
|
console.log('\tCHUNK ', i, scriptSig.chunks[i]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var w = new TxProposals({
|
it('#merge, merge signatures case 2', function() {
|
||||||
networkName: config.networkName,
|
|
||||||
});
|
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv2,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
|
|
||||||
var ntxid = Object.keys(w.txps)[0];
|
var o1 = {
|
||||||
var tx = w.txps[ntxid].builder.build();
|
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPdSF1avR6mXyDj5Uv1XY2UyUHSDpAXQ5TvPN7prGeDppjy4562rBB9gMMAhRfFdJrNDpQ4t69kkqHNEEen3PX1zBJqSehJDH',
|
||||||
tx.isComplete().should.equal(false);
|
networkName: 'testnet',
|
||||||
tx.countInputSignatures(0).should.equal(0);
|
privateKeyCache: {}
|
||||||
tx.countInputMissingSignatures(0).should.equal(1);
|
};
|
||||||
|
var o2 = {
|
||||||
Object.keys(w.txps[ntxid].signedBy).length.should.equal(0);
|
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPdVeB5RzuxS9JQcACueZYgUaM5eWzaEBkHjW5Pg6Mqez1APSqoUP1jUdbT8WVG7ZJYTXvUL7XtPzFYBXjmdKuwSor1dcNQ8j',
|
||||||
Object.keys(w.txps[ntxid].seenBy).length.should.equal(1);
|
networkName: 'testnet',
|
||||||
|
privateKeyCache: {}
|
||||||
|
};
|
||||||
|
var o3 = {
|
||||||
|
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPeHWNrPVZtQVgcCtXBr5TACNbDQ56rwqNJce9MEc64US6DJKxpWsrebEomxxWZFDtkvkZGkzA43uLvdF4XHiWqoNaL6Dq2Gd',
|
||||||
|
networkName: 'testnet',
|
||||||
|
privateKeyCache: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var w2 = new TxProposals({
|
var priv = PrivateKey.fromObj(o1);
|
||||||
networkName: config.networkName,
|
var priv2 = PrivateKey.fromObj(o2);
|
||||||
publicKeyRing: w.publicKeyRing,
|
var priv3 = PrivateKey.fromObj(o3);
|
||||||
});
|
var pub = priv.publicHex;
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w2.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
|
|
||||||
var ntxid = Object.keys(w.txps)[0];
|
var ts = Date.now();
|
||||||
var tx = w2.txps[ntxid].builder.build();
|
var pkr = createPKR([priv, priv2]);
|
||||||
tx.isComplete().should.equal(false);
|
var opts = {
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
remainderOut: {
|
||||||
|
address: '2MxK2m7cPtEwjZBB8Ksq7ppjkgJyFPJGemr'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var addressToSign = pkr.generateAddress(false, pub);
|
||||||
|
unspentTest[0].address = addressToSign.toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
var tx, txb;
|
||||||
|
|
||||||
|
var w = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
|
||||||
|
w.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv3,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
|
||||||
|
var ntxid = Object.keys(w.txps)[0];
|
||||||
|
txb = w.txps[ntxid].builder;
|
||||||
|
tx = txb.build();
|
||||||
|
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
|
||||||
|
Object.keys(w.txps[ntxid].signedBy).length.should.equal(0);
|
||||||
|
Object.keys(w.txps[ntxid].seenBy).length.should.equal(1);
|
||||||
|
|
||||||
|
var w2 = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true, 'asdsd');
|
|
||||||
(w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(0));
|
w2.add(createTx(
|
||||||
info.events.length.should.equal(2);
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
info.events[0].type.should.equal('seen');
|
'123456789',
|
||||||
info.events[1].type.should.equal('signed');
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
var ntxid = Object.keys(w2.txps)[0];
|
||||||
|
txb = w2.txps[ntxid].builder;
|
||||||
|
tx = txb.build();
|
||||||
|
|
||||||
Object.keys(w.txps).length.should.equal(1);
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
|
||||||
var tx = w.txps[ntxid].builder.build();
|
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
tx.isComplete().should.equal(false);
|
(w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
});
|
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(0));
|
||||||
|
info.events.length.should.equal(2);
|
||||||
|
info.events[0].type.should.equal('seen');
|
||||||
|
info.events[1].type.should.equal('signed');
|
||||||
|
|
||||||
var _dumpChunks = function(scriptSig, label) {
|
tx = w.txps[ntxid].builder.build();
|
||||||
console.log('## DUMP: ' + label + ' ##');
|
tx.isComplete().should.equal(false);
|
||||||
for (var i = 0; i < scriptSig.chunks.length; i++) {
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
console.log('\tCHUNK ', i, scriptSig.chunks[i]);
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
}
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
it('#merge, merge signatures case 2', function() {
|
var w3 = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
publicKeyRing: pkr,
|
||||||
|
});
|
||||||
|
w3.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv2,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
tx = w3.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
|
||||||
var o1 = {
|
(w3.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPdSF1avR6mXyDj5Uv1XY2UyUHSDpAXQ5TvPN7prGeDppjy4562rBB9gMMAhRfFdJrNDpQ4t69kkqHNEEen3PX1zBJqSehJDH',
|
(w3.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
networkName: 'testnet',
|
|
||||||
privateKeyCache: {}
|
|
||||||
};
|
|
||||||
var o2 = {
|
|
||||||
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPdVeB5RzuxS9JQcACueZYgUaM5eWzaEBkHjW5Pg6Mqez1APSqoUP1jUdbT8WVG7ZJYTXvUL7XtPzFYBXjmdKuwSor1dcNQ8j',
|
|
||||||
networkName: 'testnet',
|
|
||||||
privateKeyCache: {}
|
|
||||||
};
|
|
||||||
var o3 = {
|
|
||||||
extendedPrivateKeyString: 'tprv8ZgxMBicQKsPeHWNrPVZtQVgcCtXBr5TACNbDQ56rwqNJce9MEc64US6DJKxpWsrebEomxxWZFDtkvkZGkzA43uLvdF4XHiWqoNaL6Dq2Gd',
|
|
||||||
networkName: 'testnet',
|
|
||||||
privateKeyCache: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
var info = w.merge(w3.txps[ntxid], pkr.getCopayerId(1));
|
||||||
|
|
||||||
var priv = PrivateKey.fromObj(o1);
|
Object.keys(w.txps).length.should.equal(1);
|
||||||
var priv2 = PrivateKey.fromObj(o2);
|
|
||||||
var priv3 = PrivateKey.fromObj(o3);
|
|
||||||
var pub = priv.publicHex;
|
|
||||||
|
|
||||||
var ts = Date.now();
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
var pkr = createPKR([priv, priv2]);
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
var opts = {
|
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
remainderOut: {
|
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
address: '2MxK2m7cPtEwjZBB8Ksq7ppjkgJyFPJGemr'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var addressToSign = pkr.generateAddress(false, pub);
|
|
||||||
unspentTest[0].address = addressToSign.toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
var tx, txb;
|
|
||||||
|
|
||||||
var w = new TxProposals({
|
tx = w.txps[ntxid].builder.build();
|
||||||
networkName: config.networkName,
|
tx.isComplete().should.equal(false);
|
||||||
});
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
|
||||||
w.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv3,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
|
|
||||||
var ntxid = Object.keys(w.txps)[0];
|
|
||||||
txb = w.txps[ntxid].builder;
|
|
||||||
tx = txb.build();
|
|
||||||
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(1);
|
|
||||||
|
|
||||||
Object.keys(w.txps[ntxid].signedBy).length.should.equal(0);
|
|
||||||
Object.keys(w.txps[ntxid].seenBy).length.should.equal(1);
|
|
||||||
|
|
||||||
var w2 = new TxProposals({
|
|
||||||
networkName: config.networkName,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('#merge, merge signatures case 3', function() {
|
||||||
|
|
||||||
w2.add(createTx(
|
var priv = new PrivateKey(config);
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
var priv2 = new PrivateKey(config);
|
||||||
'123456789',
|
var priv3 = new PrivateKey(config);
|
||||||
unspentTest,
|
var pub = priv.publicHex;
|
||||||
opts,
|
|
||||||
priv,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
var ntxid = Object.keys(w2.txps)[0];
|
|
||||||
txb = w2.txps[ntxid].builder;
|
|
||||||
tx = txb.build();
|
|
||||||
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
|
|
||||||
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(0));
|
|
||||||
info.events.length.should.equal(2);
|
|
||||||
info.events[0].type.should.equal('seen');
|
|
||||||
info.events[1].type.should.equal('signed');
|
|
||||||
|
|
||||||
tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
|
|
||||||
var w3 = new TxProposals({
|
var ts = Date.now();
|
||||||
networkName: config.networkName,
|
var pkr = createPKR([priv, priv2, priv3]);
|
||||||
publicKeyRing: pkr,
|
var opts = {
|
||||||
|
remainderOut: {
|
||||||
|
address: pkr.generateAddress(true, pub).toString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var w = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
var ntxid = Object.keys(w.txps)[0];
|
||||||
|
var tx = w.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
|
||||||
|
var w2 = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w2.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv2,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
var tx = w2.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w2.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
(w2.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
var w3 = new TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
});
|
||||||
|
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
||||||
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
||||||
|
w3.add(createTx(
|
||||||
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
|
'123456789',
|
||||||
|
unspentTest,
|
||||||
|
opts,
|
||||||
|
priv3,
|
||||||
|
pkr
|
||||||
|
));
|
||||||
|
var tx = w3.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w3.txps[ntxid].signedBy[priv3.id] - ts > 0).should.equal(true);
|
||||||
|
(w3.txps[ntxid].seenBy[priv3.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(1));
|
||||||
|
|
||||||
|
Object.keys(w.txps).length.should.equal(1);
|
||||||
|
var tx = w.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
|
||||||
|
|
||||||
|
var info = w.merge(w3.txps[ntxid], pkr.getCopayerId(2));
|
||||||
|
|
||||||
|
var tx = w.txps[ntxid].builder.build();
|
||||||
|
tx.isComplete().should.equal(true);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(0);
|
||||||
|
Object.keys(w.txps).length.should.equal(1);
|
||||||
|
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].seenBy[priv3.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txps[ntxid].signedBy[priv3.id] - ts > 0).should.equal(true);
|
||||||
});
|
});
|
||||||
w3.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv2,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
tx = w3.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
|
|
||||||
(w3.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w3.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var info = w.merge(w3.txps[ntxid], pkr.getCopayerId(1));
|
|
||||||
|
|
||||||
Object.keys(w.txps).length.should.equal(1);
|
|
||||||
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('#merge, merge signatures case 3', function() {
|
|
||||||
|
|
||||||
var priv = new PrivateKey(config);
|
|
||||||
var priv2 = new PrivateKey(config);
|
|
||||||
var priv3 = new PrivateKey(config);
|
|
||||||
var pub = priv.publicHex;
|
|
||||||
|
|
||||||
|
|
||||||
var ts = Date.now();
|
|
||||||
var pkr = createPKR([priv, priv2, priv3]);
|
|
||||||
var opts = {
|
|
||||||
remainderOut: {
|
|
||||||
address: pkr.generateAddress(true, pub).toString()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var w = new TxProposals({
|
|
||||||
networkName: config.networkName,
|
|
||||||
});
|
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
var ntxid = Object.keys(w.txps)[0];
|
|
||||||
var tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
|
|
||||||
var w2 = new TxProposals({
|
|
||||||
networkName: config.networkName,
|
|
||||||
});
|
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w2.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv2,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
var tx = w2.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
(w2.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w2.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var w3 = new TxProposals({
|
|
||||||
networkName: config.networkName,
|
|
||||||
});
|
|
||||||
unspentTest[0].address = pkr.getAddress(addressIndex, isChange, pub).toString();
|
|
||||||
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(addressIndex, isChange, pub);
|
|
||||||
w3.add(createTx(
|
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
||||||
'123456789',
|
|
||||||
unspentTest,
|
|
||||||
opts,
|
|
||||||
priv3,
|
|
||||||
pkr
|
|
||||||
));
|
|
||||||
var tx = w3.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
(w3.txps[ntxid].signedBy[priv3.id] - ts > 0).should.equal(true);
|
|
||||||
(w3.txps[ntxid].seenBy[priv3.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(1));
|
|
||||||
|
|
||||||
Object.keys(w.txps).length.should.equal(1);
|
|
||||||
var tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(false);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(1);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
|
|
||||||
|
|
||||||
var info = w.merge(w3.txps[ntxid], pkr.getCopayerId(2));
|
|
||||||
|
|
||||||
var tx = w.txps[ntxid].builder.build();
|
|
||||||
tx.isComplete().should.equal(true);
|
|
||||||
tx.countInputMissingSignatures(0).should.equal(0);
|
|
||||||
Object.keys(w.txps).length.should.equal(1);
|
|
||||||
(w.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].seenBy[priv3.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
||||||
(w.txps[ntxid].signedBy[priv3.id] - ts > 0).should.equal(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue