add different toObj/fromObj fn for networking

This commit is contained in:
Matias Alejo Garcia 2014-08-02 20:51:31 -03:00
commit 966818c53a
6 changed files with 233 additions and 116 deletions

View file

@ -99,14 +99,6 @@ PublicKeyRing.prototype._checkKeys = function() {
throw new Error('dont have required keys yet'); throw new Error('dont have required keys yet');
}; };
PublicKeyRing.prototype._newExtendedPublicKey = function() {
return new PrivateKey({
networkName: this.network.name
})
.deriveBIP45Branch()
.extendedPublicKeyString();
};
PublicKeyRing.prototype._updateBip = function(index) { PublicKeyRing.prototype._updateBip = function(index) {
var hk = this.copayersHK[index].derive(HDPath.IdBranch); var hk = this.copayersHK[index].derive(HDPath.IdBranch);
this.copayerIds[index] = hk.eckey.public.toString('hex'); this.copayerIds[index] = hk.eckey.public.toString('hex');
@ -125,6 +117,8 @@ PublicKeyRing.prototype.nicknameForCopayer = function(copayerId) {
}; };
PublicKeyRing.prototype.addCopayer = function(newEpk, nickname) { PublicKeyRing.prototype.addCopayer = function(newEpk, nickname) {
preconditions.checkArgument(newEpk);
if (this.isComplete()) if (this.isComplete())
throw new Error('PKR already has all required key:' + this.totalCopayers); throw new Error('PKR already has all required key:' + this.totalCopayers);
@ -133,10 +127,6 @@ PublicKeyRing.prototype.addCopayer = function(newEpk, nickname) {
throw new Error('PKR already has that key'); throw new Error('PKR already has that key');
}); });
if (!newEpk) {
newEpk = this._newExtendedPublicKey();
}
var i = this.copayersHK.length; var i = this.copayersHK.length;
var bip = new HK(newEpk); var bip = new HK(newEpk);
this.copayersHK.push(bip); this.copayersHK.push(bip);
@ -307,6 +297,30 @@ PublicKeyRing.prototype.forPaths = function(paths) {
}; };
PublicKeyRing.prototype.copayersForPubkeys = function(pubkeys, paths) {
var inKeyMap = {}, ret = [];
for(var i in pubkeys ){
inKeyMap[pubkeys[i]] = 1;
};
var keys = this.getForPaths(paths);
for(var i in keys ){
for(var copayerIndex in keys[i] ){
var kHex = keys[i][copayerIndex].toString('hex');
if (inKeyMap[kHex]) {
ret.push(this.copayerIds[copayerIndex]);
delete inKeyMap[kHex];
}
}
}
for(var i in inKeyMap)
throw new Error('Pubkey not identified')
return ret;
};
// TODO this could be cached // TODO this could be cached
PublicKeyRing.prototype._addScriptMap = function(map, path) { PublicKeyRing.prototype._addScriptMap = function(map, path) {
var p = HDPath.indexesForPath(path); var p = HDPath.indexesForPath(path);

View file

@ -10,6 +10,9 @@ var Key = bitcore.Key;
var buffertools = bitcore.buffertools; var buffertools = bitcore.buffertools;
var preconditions = require('preconditions').instance(); var preconditions = require('preconditions').instance();
var VERSION = 1;
var CORE_FIELDS = ['builderObj','inputChainPaths', 'version'];
function TxProposal(opts) { function TxProposal(opts) {
preconditions.checkArgument(opts); preconditions.checkArgument(opts);
@ -17,22 +20,26 @@ function TxProposal(opts) {
preconditions.checkArgument(opts.creator,'no creator'); preconditions.checkArgument(opts.creator,'no creator');
preconditions.checkArgument(opts.createdTs,'no createdTs'); preconditions.checkArgument(opts.createdTs,'no createdTs');
preconditions.checkArgument(opts.builder,'no builder'); preconditions.checkArgument(opts.builder,'no builder');
preconditions.checkArgument(opts.inputChainPaths,'no inputChainPaths');
this.creator = opts.creator;
this.createdTs = opts.createdTs;
this.builder = opts.builder;
this.inputChainPaths = opts.inputChainPaths; this.inputChainPaths = opts.inputChainPaths;
this.version = opts.version;
this.builder = opts.builder;
this.createdTs = opts.createdTs;
this.createdTs = opts.createdTs;
this._inputSignatures = []; this._inputSignatures = [];
this.seenBy = opts.seenBy || {};
// CopayerIds
this.creator = opts.creator;
this.signedBy = opts.signedBy || {}; this.signedBy = opts.signedBy || {};
this.seenBy = opts.seenBy || {};
this.rejectedBy = opts.rejectedBy || {}; this.rejectedBy = opts.rejectedBy || {};
this.sentTs = opts.sentTs || null; this.sentTs = opts.sentTs || null;
this.sentTxid = opts.sentTxid || null; this.sentTxid = opts.sentTxid || null;
this.comment = opts.comment || null; this.comment = opts.comment || null;
this.readonly = opts.readonly || null; this.readonly = opts.readonly || null;
// this._updateSignedBy();
this.sync();
} }
TxProposal.prototype.getId = function() { TxProposal.prototype.getId = function() {
@ -47,11 +54,24 @@ TxProposal.prototype.toObj = function() {
}; };
TxProposal.prototype.setSent = function(sentTxid) { TxProposal.prototype.toObjForNetwork = function() {
this.sentTxid = sentTxid; var o = this.toObj;
this.sentTs = Date.now();
var newOutput = {};
CORE_FIELDS.forEach(function(k){
newOutput[k] = o[k];
});
return newOutput;
}; };
TxProposal.prototype.sync = function() {
this._check();
this._updateSignedBy();
return this;
}
// fromObj => from a trusted source
TxProposal.fromObj = function(o, forceOpts) { TxProposal.fromObj = function(o, forceOpts) {
preconditions.checkArgument(o.builderObj); preconditions.checkArgument(o.builderObj);
delete o['builder']; delete o['builder'];
@ -64,17 +84,24 @@ TxProposal.fromObj = function(o, forceOpts) {
o.builder = TransactionBuilder.fromObj(o.builderObj); o.builder = TransactionBuilder.fromObj(o.builderObj);
} catch (e) { } catch (e) {
// backwards (V0) compatatibility fix.
if (!o.version) { if (!o.version) {
o.builder = new BuilderMockV0(o.builderObj); o.builder = new BuilderMockV0(o.builderObj);
o.readonly = 1; o.readonly = 1;
}; };
} }
return new TxProposal(o);
};
var t = new TxProposal(o); TxProposal.fromObjUntrusted = function(o, forceOpts, senderId) {
t._check(); var newInput = {};
t._updateSignedBy(); CORE_FIELDS.forEach(function(k){
newInput[k] = o[k];
});
if (newInput.version !== VERSION)
throw new Error('Peer using different version');
return t; return TxProposal.fromObj(newInput, forceOpts, senderId);
}; };
@ -144,7 +171,8 @@ TxProposal.prototype._updateSignedBy = function() {
if (signatureIndexes.length !== signatureCount) if (signatureIndexes.length !== signatureCount)
throw new Error('Invalid signature'); throw new Error('Invalid signature');
this._inputSignatures[i] = signatureIndexes.map(function(i) { this._inputSignatures[i] = signatureIndexes.map(function(i) {
return info.keys[i].toString('hex'); var r = info.keys[i].toString('hex');
return r;
}); });
}; };
}; };
@ -184,6 +212,21 @@ TxProposal.prototype.mergeBuilder = function(incoming) {
}; };
TxProposal.prototype.setSeen = function(copayerId) {
if (!this.seenBy[copayerId])
this.seenBy[copayerId] = Date.now();
};
TxProposal.prototype.setRejected = function(copayerId) {
if (!this.rejectedBy[copayerId] && !this.signedBy)
this.rejectedBy[copayerId] = Date.now();
};
TxProposal.prototype.setSent = function(sentTxid) {
this.sentTxid = sentTxid;
this.sentTs = Date.now();
};
/* OTDO /* OTDO
events.push({ events.push({
type: 'seen', type: 'seen',
@ -213,12 +256,11 @@ TxProposal.prototype._allSignatures = function() {
return ret; return ret;
}; };
// merge will not merge any metadata.
TxProposal.prototype.merge = function(incoming) { TxProposal.prototype.merge = function(incoming) {
var ret = {}; var ret = {};
var newSignatures = []; var newSignatures = [];
incoming.sync();
incoming._check();
incoming._updateSignedBy();
var prevInputSignatures = this._allSignatures(); var prevInputSignatures = this._allSignatures();

View file

@ -20,6 +20,7 @@ function TxProposals(opts) {
this.txps = {}; this.txps = {};
} }
// fromObj => from a trusted source
TxProposals.fromObj = function(o, forceOpts) { TxProposals.fromObj = function(o, forceOpts) {
var ret = new TxProposals({ var ret = new TxProposals({
networkName: o.networkName, networkName: o.networkName,
@ -60,8 +61,6 @@ TxProposals.prototype.merge = function(inTxp, allowedPubKeys) {
var ntxid = inTxp.getId(); var ntxid = inTxp.getId();
var ret = {}; var ret = {};
ret.events = [];
ret.events.hasChanged = false;
if (myTxps[ntxid]) { if (myTxps[ntxid]) {
var v0 = myTxps[ntxid]; var v0 = myTxps[ntxid];
@ -70,12 +69,7 @@ TxProposals.prototype.merge = function(inTxp, allowedPubKeys) {
} }
else { else {
this.txps[ntxid] = inTxp; this.txps[ntxid] = inTxp;
ret.hasChanged = true; ret.new = 1;
ret.events.push({
type: 'new',
cid: inTxp.creator,
tx: ntxid
});
} }
return ret; return ret;
}; };
@ -88,22 +82,14 @@ TxProposals.prototype.mergeFromObj = function(txProposalObj, allowedPubKeys, opt
}; };
// Add a LOCALLY CREATED (trusted) tx proposal // Add a LOCALLY CREATED (trusted) tx proposal
TxProposals.prototype.add = function(data) { TxProposals.prototype.add = function(txp) {
var txp = new TxProposal(data); txp.sync();
var ntxid = txp.getId(); var ntxid = txp.getId();
this.txps[ntxid] = txp; this.txps[ntxid] = txp;
return ntxid; 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) { TxProposals.prototype.getTxProposal = function(ntxid, copayers) {
var txp = this.txps[ntxid]; var txp = this.txps[ntxid];
var i = JSON.parse(JSON.stringify(txp)); var i = JSON.parse(JSON.stringify(txp));

View file

@ -17,6 +17,7 @@ var Address = bitcore.Address;
var HDParams = require('./HDParams'); var HDParams = require('./HDParams');
var PublicKeyRing = require('./PublicKeyRing'); var PublicKeyRing = require('./PublicKeyRing');
var TxProposal = require('./TxProposal');
var TxProposals = require('./TxProposals'); var TxProposals = require('./TxProposals');
var PrivateKey = require('./PrivateKey'); var PrivateKey = require('./PrivateKey');
var copayConfig = require('../../../config'); var copayConfig = require('../../../config');
@ -129,11 +130,39 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
}; };
Wallet.prototype._processProposalEvents = function(mergeInfo) {
var ev = [];
if (mergeInfo.new) {
ev = {
type: 'new',
cid: senderId
}
} else {
for (var i in mergeInfo.newCopayers) {
var copayerId = mergeInfo.newCopayers[i];
ev.push({
type: 'signed',
cid: copayerId
});
}
}
if (ev)
this.emit('txProposalEvent',ev);
};
Wallet.prototype._handleTxProposal = function(senderId, data) { Wallet.prototype._handleTxProposal = function(senderId, data) {
this.log('RECV TXPROPOSAL: ', data); this.log('RECV TXPROPOSAL: ', data);
var mergeInfo; var mergeInfo, ntxid;
try { try {
mergeInfo = this.txProposals.mergeFromObj(data.txProposal, senderId, Wallet.builderOpts); mergeInfo = this.txProposals.mergeFromObj(data.txProposal, senderId, Wallet.builderOpts);
mergeInfo.newCopayers=[];
for (var i in mergeInfo.newSignatures) {
var k = mergeInfo.newSignatures[i];
mergeInfo.newCopayers.push(this.getCopayerIdFromPubKey(k));
};
ntxid = mergeInfo.inTxp.getId();
} catch (e) { } catch (e) {
var corruptEvent = { var corruptEvent = {
type: 'corrupt', type: 'corrupt',
@ -143,21 +172,36 @@ Wallet.prototype._handleTxProposal = function(senderId, data) {
this.emit('txProposalEvent', corruptEvent); this.emit('txProposalEvent', corruptEvent);
return; return;
} }
this.sendSeen(ntxid);
var added = this.addSeenToTxProposals(); if (mergeInfo.hasChanged)
if (added) { this.sendTxProposal(ntxid);
this.log('### BROADCASTING txProposals with my seenBy updated.');
this.sendTxProposal(mergeInfo.inTxp.getId());
}
this.emit('txProposalsUpdated'); this.emit('txProposalsUpdated');
this.store(); this.store();
this._processProposalEvents(senderId, mergeInfo);
for (var i = 0; i < mergeInfo.events.length; i++) {
this.emit('txProposalEvent', mergeInfo.events[i]);
}
}; };
Wallet.prototype._handleReject = function(senderId, data, isInbound) {
this.log('RECV REJECT:', data);
// TODO check that has not signed.
//
this.txProposals.txps[data.ntxid].setRejected(senderId);
this.emit('txProposalsUpdated');
this.store();
};
Wallet.prototype._handleSeen = function(senderId, data, isInbound) {
this.log('RECV SEEN:', data);
this.txProposals.txps[data.ntxid].setSeen(senderId);
this.emit('txProposalsUpdated');
this.store();
};
Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) {
this.log('RECV ADDRESSBOOK:', data); this.log('RECV ADDRESSBOOK:', data);
var rcv = data.addressBook; var rcv = data.addressBook;
@ -199,6 +243,10 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) {
case 'publicKeyRing': case 'publicKeyRing':
this._handlePublicKeyRing(senderId, data, isInbound); this._handlePublicKeyRing(senderId, data, isInbound);
break; break;
case 'reject':
this._handleReject(senderId, data, isInbound);
case 'seen':
this._handleReject(senderId, data, isInbound);
case 'txProposal': case 'txProposal':
this._handleTxProposal(senderId, data, isInbound); this._handleTxProposal(senderId, data, isInbound);
break; break;
@ -381,6 +429,7 @@ Wallet.prototype.toObj = function() {
return walletObj; return walletObj;
}; };
// fromObj => from a trusted source
Wallet.fromObj = function(o, storage, network, blockchain) { Wallet.fromObj = function(o, storage, network, blockchain) {
var opts = JSON.parse(JSON.stringify(o.opts)); var opts = JSON.parse(JSON.stringify(o.opts));
opts.addressBook = o.addressBook; opts.addressBook = o.addressBook;
@ -424,6 +473,26 @@ Wallet.prototype.sendTxProposal = function(ntxid, recipients) {
}); });
}; };
Wallet.prototype.sendSeen = function(ntxid) {
preconditions.checkArgument(ntxid);
this.log('### SENDING seen: ' + ntxid + ' TO: All');
this.send(null, {
type: 'seen',
ntxid: ntxid,
walletId: this.id,
});
};
Wallet.prototype.sendReject = function(ntxid) {
preconditions.checkArgument(ntxid);
this.log('### SENDING reject: ' + ntxid + ' TO: All');
this.send(null, {
type: 'reject',
ntxid: ntxid,
walletId: this.id,
});
};
Wallet.prototype.sendWalletReady = function(recipients) { Wallet.prototype.sendWalletReady = function(recipients) {
this.log('### SENDING WalletReady TO:', recipients); this.log('### SENDING WalletReady TO:', recipients);
@ -521,7 +590,7 @@ Wallet.prototype.reject = function(ntxid) {
} }
txp.rejectedBy[myId] = Date.now(); txp.rejectedBy[myId] = Date.now();
this.sendTxProposal(ntxid); this.sendReject(ntxid);
this.store(); this.store();
this.emit('txProposalsUpdated'); this.emit('txProposalsUpdated');
}; };
@ -534,10 +603,10 @@ Wallet.prototype.sign = function(ntxid, cb) {
setTimeout(function() { setTimeout(function() {
var myId = self.getMyCopayerId(); var myId = self.getMyCopayerId();
var txp = self.txProposals.txps[ntxid]; var txp = self.txProposals.txps[ntxid];
if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) { // if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) {
if (cb) cb(false); // if (cb) cb(false);
} // }
//
var keys = self.privateKey.getForPaths(txp.inputChainPaths); var keys = self.privateKey.getForPaths(txp.inputChainPaths);
var b = txp.builder; var b = txp.builder;
@ -574,7 +643,7 @@ Wallet.prototype.sendTx = function(ntxid, cb) {
this.blockchain.sendRawTransaction(txHex, function(txid) { this.blockchain.sendRawTransaction(txHex, function(txid) {
self.log('BITCOIND txid:', txid); self.log('BITCOIND txid:', txid);
if (txid) { if (txid) {
self.txProposals.setSent(ntxid, txid); self.txProposals.txps[ntxid].setSent(txid);
self.sendTxProposal(ntxid); self.sendTxProposal(ntxid);
self.store(); self.store();
} }
@ -582,20 +651,20 @@ Wallet.prototype.sendTx = function(ntxid, cb) {
}); });
}; };
Wallet.prototype.addSeenToTxProposals = function() { // Wallet.prototype.addSeenToTxProposals = function() {
var ret = false; // var ret = false;
var myId = this.getMyCopayerId(); // var myId = this.getMyCopayerId();
//
for (var k in this.txProposals.txps) { // for (var k in this.txProposals.txps) {
var txp = this.txProposals.txps[k]; // var txp = this.txProposals.txps[k];
if (!txp.seenBy[myId]) { // if (!txp.seenBy[myId]) {
//
txp.seenBy[myId] = Date.now(); // txp.seenBy[myId] = Date.now();
ret = true; // ret = true;
} // }
} // }
return ret; // return ret;
}; // };
// TODO: remove this method and use getAddressesInfo everywhere // TODO: remove this method and use getAddressesInfo everywhere
Wallet.prototype.getAddresses = function(opts) { Wallet.prototype.getAddresses = function(opts) {
@ -718,6 +787,7 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
preconditions.checkArgument(new Address(toAddress).network().name === this.getNetworkName()); preconditions.checkArgument(new Address(toAddress).network().name === this.getNetworkName());
preconditions.checkState(pkr.isComplete()); preconditions.checkState(pkr.isComplete());
preconditions.checkState(priv);
if (comment) preconditions.checkArgument(comment.length <= 100); if (comment) preconditions.checkArgument(comment.length <= 100);
if (!opts.remainderOut) { if (!opts.remainderOut) {
@ -744,22 +814,23 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
b = b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths)); b = b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths));
if (priv) { var keys = priv.getForPaths(inputChainPaths);
var keys = priv.getForPaths(inputChainPaths); var signed = b.sign(keys);
var signed = b.sign(keys);
}
var myId = this.getMyCopayerId(); var myId = this.getMyCopayerId();
var now = Date.now(); var now = Date.now();
var me = {};
var tx = b.build(); var tx = b.build();
if (priv && tx.countInputSignatures(0)) me[myId] = now; if (!tx.countInputSignatures(0))
throw new Error ('Could not sign generated tx');
var me = {};
me[myId] = now;
var meSeen = {}; var meSeen = {};
if (priv) meSeen[myId] = now; if (priv) meSeen[myId] = now;
var data = { var ntxid = this.txProposals.add(new TxProposal({
inputChainPaths: inputChainPaths, inputChainPaths: inputChainPaths,
signedBy: me, signedBy: me,
seenBy: meSeen, seenBy: meSeen,
@ -767,9 +838,7 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
createdTs: now, createdTs: now,
builder: b, builder: b,
comment: comment comment: comment
}; }));
var ntxid = this.txProposals.add(data);
return ntxid; return ntxid;
}; };

View file

@ -182,8 +182,6 @@ describe('TxProposal', function() {
}); });
it('#_updateSignedBy', function() { it('#_updateSignedBy', function() {
var txp = dummyProposal; var txp = dummyProposal;
txp._inputSignatures.should.deep.equal([]);
txp._updateSignedBy();
txp._inputSignatures.should.deep.equal([[ '03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3' ]]); txp._inputSignatures.should.deep.equal([[ '03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3' ]]);
}); });
describe('#_check', function() { describe('#_check', function() {

View file

@ -10,7 +10,7 @@ try {
} }
var copayConfig = require('../config'); var copayConfig = require('../config');
var Wallet = require('../js/models/core/Wallet'); var Wallet = require('../js/models/core/Wallet');
var Structure = copay.Structure; var PrivateKey = copay.PrivateKey;
var Storage = require('./mocks/FakeStorage'); var Storage = require('./mocks/FakeStorage');
var Network = require('./mocks/FakeNetwork'); var Network = require('./mocks/FakeNetwork');
var Blockchain = require('./mocks/FakeBlockchain'); var Blockchain = require('./mocks/FakeBlockchain');
@ -19,22 +19,30 @@ var TransactionBuilder = bitcore.TransactionBuilder;
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var Address = bitcore.Address; var Address = bitcore.Address;
var config = {
requiredCopayers: 3,
totalCopayers: 5,
spendUnconfirmed: true,
reconnectDelay: 100,
networkName: 'testnet',
};
var getNewEpk = function() {
return new PrivateKey({
networkName: config.networkName,
})
.deriveBIP45Branch()
.extendedPublicKeyString();
}
var addCopayers = function(w) { var addCopayers = function(w) {
for (var i = 0; i < 4; i++) { for (var i = 0; i < 4; i++) {
w.publicKeyRing.addCopayer(); w.publicKeyRing.addCopayer(getNewEpk());
} }
}; };
describe('Wallet model', function() { describe('Wallet model', function() {
var config = {
requiredCopayers: 3,
totalCopayers: 5,
spendUnconfirmed: true,
reconnectDelay: 100,
networkName: 'testnet',
};
it('should fail to create an instance', function() { it('should fail to create an instance', function() {
(function() { (function() {
new Wallet(config) new Wallet(config)
@ -47,12 +55,11 @@ describe('Wallet model', function() {
}); });
var createW = function(netKey, N, conf) { var createW = function(N, conf) {
var c = JSON.parse(JSON.stringify(conf || config)); var c = JSON.parse(JSON.stringify(conf || config));
if (!N) N = c.totalCopayers; if (!N) N = c.totalCopayers;
if (netKey) c.netKey = netKey;
var mainPrivateKey = new copay.PrivateKey({ var mainPrivateKey = new copay.PrivateKey({
networkName: config.networkName networkName: config.networkName
}); });
@ -148,8 +155,7 @@ describe('Wallet model', function() {
var createW2 = function(privateKeys, N, conf) { var createW2 = function(privateKeys, N, conf) {
if (!N) N = 3; if (!N) N = 3;
var netKey = 'T0FbU2JLby0='; var w = createW(N, conf);
var w = createW(netKey, N, conf);
should.exist(w); should.exist(w);
var pkr = w.publicKeyRing; var pkr = w.publicKeyRing;
@ -157,9 +163,9 @@ describe('Wallet model', function() {
for (var i = 0; i < N - 1; i++) { for (var i = 0; i < N - 1; i++) {
if (privateKeys) { if (privateKeys) {
var k = privateKeys[i]; var k = privateKeys[i];
pkr.addCopayer(k ? k.deriveBIP45Branch().extendedPublicKeyString() : null); pkr.addCopayer(k ? k.deriveBIP45Branch().extendedPublicKeyString() : getNewEpk());
} else { } else {
pkr.addCopayer(); pkr.addCopayer(getNewEpk());
} }
} }
@ -212,12 +218,12 @@ describe('Wallet model', function() {
var t = w.txProposals; var t = w.txProposals;
var txp = t.txps[ntxid]; var txp = t.txps[ntxid];
Object.keys(txp._inputSignatures).length.should.equal(1);
var tx = txp.builder.build(); var tx = txp.builder.build();
should.exist(tx); should.exist(tx);
chai.expect(txp.comment).to.be.null; chai.expect(txp.comment).to.be.null;
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
Object.keys(txp.seenBy).length.should.equal(1); Object.keys(txp.seenBy).length.should.equal(1);
Object.keys(txp.signedBy).length.should.equal(1);
}); });
it('#create with comment', function() { it('#create with comment', function() {
@ -502,7 +508,8 @@ describe('Wallet model', function() {
var w = createW(); var w = createW();
var r = w.getRegisteredCopayerIds(); var r = w.getRegisteredCopayerIds();
r.length.should.equal(1); r.length.should.equal(1);
w.publicKeyRing.addCopayer(); w.publicKeyRing.addCopayer(getNewEpk());
r = w.getRegisteredCopayerIds(); r = w.getRegisteredCopayerIds();
r.length.should.equal(2); r.length.should.equal(2);
r[0].should.not.equal(r[1]); r[0].should.not.equal(r[1]);
@ -512,7 +519,7 @@ describe('Wallet model', function() {
var w = createW(); var w = createW();
var r = w.getRegisteredPeerIds(); var r = w.getRegisteredPeerIds();
r.length.should.equal(1); r.length.should.equal(1);
w.publicKeyRing.addCopayer(); w.publicKeyRing.addCopayer(getNewEpk());
r = w.getRegisteredPeerIds(); r = w.getRegisteredPeerIds();
r.length.should.equal(2); r.length.should.equal(2);
r[0].should.not.equal(r[1]); r[0].should.not.equal(r[1]);
@ -642,10 +649,11 @@ describe('Wallet model', function() {
}); });
}); });
it('should create & sign transaction from received funds', function(done) { it('should create & sign transaction from received funds', function(done) {
this.timeout(10000); var k2 = new PrivateKey({
var w = cachedCreateW2(); networkName: config.networkName
var pk = w.privateKey; });
w.privateKey = null;
var w = createW2([k2]);
var utxo = createUTXO(w); var utxo = createUTXO(w);
w.blockchain.fixUnspent(utxo); w.blockchain.fixUnspent(utxo);
w.createTx(toAddress, amountSatStr, null, function(ntxid) { w.createTx(toAddress, amountSatStr, null, function(ntxid) {
@ -654,7 +662,7 @@ describe('Wallet model', function() {
w.getTxProposals()[0].rejectedByUs.should.equal(false); w.getTxProposals()[0].rejectedByUs.should.equal(false);
done(); done();
}); });
w.privateKey = pk; w.privateKey = k2;
w.sign(ntxid, function(success) { w.sign(ntxid, function(success) {
success.should.equal(true); success.should.equal(true);
}); });
@ -1031,9 +1039,9 @@ describe('Wallet model', function() {
e.type.should.equal(result); e.type.should.equal(result);
done(); done();
}); });
var txp = { var txp = {dummy:1};
'txProposal': { dummy: 1} // txp.prototype.getId = function() {return 'aa'};
}; var txp = { 'txProposal': txp };
var merge = sinon.stub(w.txProposals, 'mergeFromObj', function() { var merge = sinon.stub(w.txProposals, 'mergeFromObj', function() {
if (shouldThrow) throw new Error(); if (shouldThrow) throw new Error();
return {events: [{type:'new'}]}; return {events: [{type:'new'}]};