mirror of https://github.com/BTCPrivate/copay.git
468 lines
14 KiB
JavaScript
468 lines
14 KiB
JavaScript
'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 BIP32 = bitcore.BIP32;
|
|
var bignum = bitcore.bignum;
|
|
var Script = bitcore.Script;
|
|
var Builder = bitcore.TransactionBuilder;
|
|
var util = bitcore.util;
|
|
var networks = bitcore.networks;
|
|
var copay = copay || require('../copay');
|
|
var fakeStorage = copay.FakeStorage;
|
|
var PrivateKey = copay.PrivateKey || require('../js/models/PrivateKey');
|
|
var TxProposals = copay.TxProposals || require('../js/models/TxProposal');
|
|
var PublicKeyRing = is_browser ? copay.PublicKeyRing :
|
|
require('soop').load('../js/models/core/PublicKeyRing', {Storage: fakeStorage});
|
|
var is_browser = (typeof process.versions === 'undefined')
|
|
|
|
var config = {
|
|
networkName:'livenet',
|
|
};
|
|
|
|
var unspentTest = [
|
|
{
|
|
"address": "dummy",
|
|
"scriptPubKey": "dummy",
|
|
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
|
"vout": 1,
|
|
"amount": 10,
|
|
"confirmations":7
|
|
}
|
|
];
|
|
|
|
var createPKR = function (bip32s) {
|
|
var w = new PublicKeyRing(config);
|
|
should.exist(w);
|
|
|
|
for(var i=0; i<5; i++) {
|
|
if (bip32s) {
|
|
var b=bip32s[i];
|
|
w.addCopayer(b?b.extendedPublicKeyString():null);
|
|
}
|
|
else
|
|
w.addCopayer();
|
|
}
|
|
w.generateAddress(true);
|
|
w.generateAddress(true);
|
|
w.generateAddress(true);
|
|
w.generateAddress(false);
|
|
w.generateAddress(false);
|
|
w.generateAddress(false);
|
|
//3x3 indexes
|
|
|
|
return w;
|
|
};
|
|
|
|
|
|
describe('TxProposals model', function() {
|
|
|
|
it('should create an instance', function () {
|
|
var w = new TxProposals({
|
|
networkName: config.networkName
|
|
});
|
|
should.exist(w);
|
|
w.network.name.should.equal('livenet');
|
|
});
|
|
|
|
function createTx(toAddress, amountSatStr, utxos, opts, priv, pkr) {
|
|
opts = opts || {};
|
|
|
|
var amountSat = bitcore.bignum(amountSatStr);
|
|
|
|
if(! pkr.isComplete() ) {
|
|
throw new Error('publicKeyRing is not complete');
|
|
}
|
|
|
|
if (!opts.remainderOut) {
|
|
opts.remainderOut ={ address: pkr.generateAddress(true).toString() };
|
|
};
|
|
|
|
var b = new Builder(opts)
|
|
.setUnspent(utxos)
|
|
.setHashToScriptMap(pkr.getRedeemScriptMap())
|
|
.setOutputs([{address: toAddress, amountSat: amountSat}])
|
|
;
|
|
|
|
var signRet;
|
|
if (priv) {
|
|
b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) );
|
|
}
|
|
var me = {};
|
|
if (priv) me[priv.id] = Date.now();
|
|
|
|
return {
|
|
signedBy: priv && b.signaturesAdded ? me : {},
|
|
seenBy: priv ? me : {},
|
|
builder: b,
|
|
};
|
|
};
|
|
|
|
|
|
it('#merge with self', function () {
|
|
var priv = new PrivateKey(config);
|
|
var w = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
var pkr=createPKR([priv.getBIP32()]);
|
|
var ts = Date.now();
|
|
var isChange=0;
|
|
var index=0;
|
|
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
{},
|
|
priv,
|
|
pkr
|
|
));
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
w.merge(w);
|
|
w.txps.length.should.equal(1);
|
|
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].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 ts = Date.now();
|
|
var isChange=0;
|
|
var index=0;
|
|
var pkr = createPKR([priv.getBIP32()]);
|
|
var opts = {remainderOut: { address: pkr.generateAddress(true).toString() }};
|
|
|
|
|
|
var w = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv2,
|
|
pkr
|
|
));
|
|
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(1);
|
|
|
|
Object.keys(w.txps[0].signedBy).length.should.equal(0);
|
|
Object.keys(w.txps[0].seenBy).length.should.equal(1);
|
|
|
|
|
|
var w2 = new TxProposals({
|
|
networkName: config.networkName,
|
|
publicKeyRing: w.publicKeyRing,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w2.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv,
|
|
pkr
|
|
));
|
|
|
|
var tx = w2.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
w.merge(w2);
|
|
w.txps.length.should.equal(1);
|
|
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].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]);
|
|
}
|
|
};
|
|
|
|
|
|
it('#merge, merge signatures case 2', function () {
|
|
|
|
var priv = new PrivateKey(config);
|
|
var priv2 = new PrivateKey(config);
|
|
var priv3 = new PrivateKey(config);
|
|
var ts = Date.now();
|
|
var isChange=0;
|
|
var index=0;
|
|
var pkr = createPKR([priv.getBIP32(), priv2.getBIP32()]);
|
|
var opts = {remainderOut: { address: pkr.generateAddress(true).toString() }};
|
|
|
|
var w = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
|
|
w.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv3,
|
|
pkr
|
|
));
|
|
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(1);
|
|
|
|
Object.keys(w.txps[0].signedBy).length.should.equal(0);
|
|
Object.keys(w.txps[0].seenBy).length.should.equal(1);
|
|
|
|
|
|
var w2 = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w2.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv,
|
|
pkr
|
|
));
|
|
tx = w2.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
w.merge(w2);
|
|
w.txps.length.should.equal(1);
|
|
|
|
tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
|
|
var w3 = new TxProposals({
|
|
networkName: config.networkName,
|
|
publicKeyRing: pkr,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w3.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv2,
|
|
pkr
|
|
));
|
|
tx = w3.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
(w3.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w3.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
|
|
w.merge(w3);
|
|
w.txps.length.should.equal(1);
|
|
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
|
|
tx = w.txps[0].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 ts = Date.now();
|
|
var isChange=0;
|
|
var index=0;
|
|
var pkr = createPKR([priv.getBIP32(), priv2.getBIP32(), priv3.getBIP32() ]);
|
|
var opts = {remainderOut: { address: pkr.generateAddress(true).toString() }};
|
|
|
|
var w = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv,
|
|
pkr
|
|
));
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
|
|
var w2 = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w2.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv2,
|
|
pkr
|
|
));
|
|
var tx = w2.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w2.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w2.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
|
|
|
|
var w3 = new TxProposals({
|
|
networkName: config.networkName,
|
|
});
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w3.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
opts,
|
|
priv3,
|
|
pkr
|
|
));
|
|
var tx = w3.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w3.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true);
|
|
(w3.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true);
|
|
|
|
w.merge(w2);
|
|
w.txps.length.should.equal(1);
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(1);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
|
|
|
|
w.merge(w3);
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(true);
|
|
tx.countInputMissingSignatures(0).should.equal(0);
|
|
w.txps.length.should.equal(1);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true);
|
|
});
|
|
|
|
|
|
|
|
it('#toObj #fromObj roundtrip', function () {
|
|
|
|
var priv = new PrivateKey(config);
|
|
var pkr = createPKR([priv.getBIP32()]);
|
|
var w = new TxProposals({
|
|
walletId: 'qwerty',
|
|
networkName: config.networkName,
|
|
});
|
|
var ts = Date.now();
|
|
var isChange=0;
|
|
var index=0;
|
|
|
|
unspentTest[0].address = pkr.getAddress(index, isChange).toString();
|
|
unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange);
|
|
w.add(createTx(
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
'123456789',
|
|
unspentTest,
|
|
{},
|
|
priv,
|
|
pkr
|
|
));
|
|
var tx = w.txps[0].builder.build();
|
|
tx.isComplete().should.equal(false);
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
|
|
var o = w.toObj();
|
|
should.exist(o);
|
|
o.txps.length.should.equal(1);
|
|
should.exist(o.txps[0]);
|
|
should.exist(o.txps[0].signedBy);
|
|
should.exist(o.txps[0].seenBy);
|
|
should.exist(o.txps[0].builderObj);
|
|
should.exist(o.txps[0].builderObj.valueInSat);
|
|
should.exist(o.txps[0].signedBy[priv.id]);
|
|
|
|
var w2 = TxProposals.fromObj(o);
|
|
w2.walletId.should.equal(w.walletId);
|
|
var tx2 = w2.txps[0].builder.build();
|
|
tx2.isComplete().should.equal(false);
|
|
tx2.countInputMissingSignatures(0).should.equal(2);
|
|
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
|
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
|
should.exist(w2.txps[0].builder);
|
|
should.exist(w2.txps[0].builder.valueInSat);
|
|
|
|
w2.merge(w);
|
|
});
|
|
|
|
});
|
|
|