diff --git a/js/controllers/transactions.js b/js/controllers/transactions.js index e5048401e..c140160b0 100644 --- a/js/controllers/transactions.js +++ b/js/controllers/transactions.js @@ -8,6 +8,7 @@ angular.module('copay.transactions').controller('TransactionsController', $scope.oneAtATime = true; var _updateTxs = function() { +console.log('[transactions.js.10:_updateTxs:]'); //TODO var w =$rootScope.wallet; var inT = w.getTxProposals(); var txs = []; @@ -35,11 +36,14 @@ angular.module('copay.transactions').controller('TransactionsController', one.missingSignatures = tx.countInputMissingSignatures(0); one.signedByUs = i.signedByUs; one.ntxid = i.ntxid; - one.creator = i.txp.creator, + one.creator = i.txp.creator; one.createdTs = i.txp.createdTs; + one.sentTs = i.txp.sentTs; txs.push(one); }); $scope.txs = txs; +console.log('[transactions.js.55] SET HANDL+'); //TODO + w.once('txProposalsUpdated',_updateTxs); }; @@ -49,7 +53,7 @@ angular.module('copay.transactions').controller('TransactionsController', else { _updateTxs(); var w = $rootScope.wallet; - w.on('refresh',_updateTxs); + var socket = Socket($scope); socket.on('connect', controllerUtils.handleTransactionByAddress($scope)); } diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index 1fcedb37b..fb77b7d73 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -70,7 +70,10 @@ Insight.prototype.sendRawTransaction = function(rawtx, cb) { headers: { 'content-type' : 'application/x-www-form-urlencoded' } }; this._request(options, function(err,res) { +console.log('[Insight.js.73:err:]',err); //TODO if (err) return cb(); + +console.log('[Insight.js.74]', res); //TODO return cb(res.txid); }); }; @@ -95,13 +98,18 @@ Insight.prototype._request = function(options, callback) { request.open(options.method, url, true); request.onreadystatechange = function() { if (request.readyState === 4) { +console.log('[Insight.js.102]', request); //TODO if (request.status === 200) { try { return callback(null, JSON.parse(request.responseText)); } catch (e) { + +console.log('[Insight.js.106]'); //TODO return callback({message: 'Wrong response from insight'}); } } else { + +console.log('[Insight.js.111]'); //TODO return callback({message: 'Error ' + request.status}); } } diff --git a/js/models/core/TxProposals.js b/js/models/core/TxProposals.js index 309047988..e056d9e8f 100644 --- a/js/models/core/TxProposals.js +++ b/js/models/core/TxProposals.js @@ -19,6 +19,7 @@ function TxProposal(opts) { this.seenBy = opts.seenBy || {}; this.signedBy = opts.signedBy || {}; this.builder = opts.builder; + this.sentTs = null; } TxProposal.prototype.toObj = function() { @@ -35,6 +36,14 @@ TxProposal.fromObj = function(o) { return t; }; +TxProposal.setSent = function() { + this.sentTs = Date.now();; +}; + +TxProposal.getSentTs = function() { + return this.sentTs; +}; + module.exports = require('soop')(TxProposal); @@ -54,6 +63,7 @@ TxProposals.fromObj = function(o) { o.txps.forEach(function(o2) { var t = TxProposal.fromObj(o2); var id = t.builder.build().getNormalizedHash().toString('hex'); +console.log('[TxProposals.js.65:id:]',id, o2); //TODO ret.txps[id] = t; }); return ret; @@ -64,7 +74,8 @@ TxProposals.prototype.toObj = function() { var ret = []; for(var id in this.txps){ var t = this.txps[id]; - ret.push(t.toObj()); + if (!t.sent) + ret.push(t.toObj()); } return { txps: ret, @@ -110,43 +121,66 @@ TxProposals.prototype._startMerge = function(myTxps, theirTxps) { TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) { var toMerge = mergeInfo.toMerge; + var hasChanged =0; Object.keys(toMerge).forEach(function(hash) { var v0 = myTxps[hash]; var v1 = toMerge[hash]; +console.log('[TxProposals.js.127:v0:]',v0, v1); //TODO Object.keys(v1.seenBy).forEach(function(k) { - v0.seenBy[k] = v1.seenBy[k]; + if (!v0.seenBy[k] || v0.seenBy[k] !== v1.seenBy[k]) { + v0.seenBy[k] = v1.seenBy[k]; + hasChanged++; + } }); Object.keys(v1.signedBy).forEach(function(k) { - v0.signedBy[k] = v1.signedBy[k]; + if (!v0.signedBy[k]) { + v0.signedBy[k] = v1.signedBy[k]; + hasChanged++; + } }); + + if (!v0.sentTs && v1.sentTs) { + v0.sentTs = v1.sentTs; + hasChanged++; + } + }); +console.log('[TxProposals.js.131:hasChanged:]',hasChanged); //TODO + return hasChanged; }; TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) { var toMerge = mergeInfo.toMerge; + var hasChanged=0; for(var hash in toMerge){ var v0 = myTxps[hash].builder; var v1 = toMerge[hash].builder; + // TODO: enhance this + var before = JSON.stringify(v0.toObj()); v0.merge(v1); - }; + var after = JSON.stringify(v0.toObj()); + if (after !== before) hasChanged ++; + } +console.log('[TxProposals.js.149:hasChanged:]',hasChanged); //TODO }; TxProposals.prototype.add = function(data) { var id = data.builder.build().getNormalizedHash().toString('hex'); +console.log('[TxProposals.js.175:data: ADD]',data); //TODO this.txps[id] = new TxProposal(data); }; -TxProposals.prototype.remove = function(ntxid) { - -console.log('[TxProposals.js.147] DELETING:', ntxid); //TODO - delete this.txps[ntxid]; +TxProposals.prototype.setSent = function(ntxid) { + //sent TxProposals are local an not broadcasted. +console.log('[TxProposals.js.147] SET SENT:', ntxid); //TODO + this.txps[ntxid].setSent(); }; @@ -155,18 +189,21 @@ TxProposals.prototype.merge = function(t) { throw new Error('network mismatch in:', t); var res = []; + var hasChanged = 0; var myTxps = this.txps; var theirTxps = t.txps; var mergeInfo = this._startMerge(myTxps, theirTxps); - this._mergeMetadata(myTxps, theirTxps, mergeInfo); - this._mergeBuilder(myTxps, theirTxps, mergeInfo); + hasChanged += this._mergeMetadata(myTxps, theirTxps, mergeInfo); + hasChanged += this._mergeBuilder(myTxps, theirTxps, mergeInfo); Object.keys(mergeInfo.toMerge).forEach(function(hash) { mergeInfo.ready[hash] = myTxps[hash]; }); + mergeInfo.stats.hasChanged = hasChanged; + this.txps=mergeInfo.ready; return mergeInfo.stats; }; diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 7b0efd813..45e62301b 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -34,7 +34,8 @@ function Wallet(opts) { Wallet.parent=EventEmitter; Wallet.prototype.log = function(){ if (!this.verbose) return; - console.log(arguments); + if (console) + console.log.apply(console, arguments); }; Wallet.getRandomId = function() { @@ -76,10 +77,13 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { var recipients; var inTxp = copay.TxProposals.fromObj(data.txProposals); var mergeInfo = this.txProposals.merge(inTxp, true); +console.log('[Wallet.js.79:inTxp:]',inTxp); //TODO var addSeen = this.addSeenToTxProposals(); + +console.log('[Wallet.js.81]', addSeen, mergeInfo); //TODO // if ((mergeInfo.merged && !data.isBroadcast) || addSeen) { - if (mergeInfo.merged || addSeen) { + if (mergeInfo.hasChanged || addSeen) { this.log('### BROADCASTING txProposals. ' ); recipients = null; shouldSend = true; @@ -191,6 +195,8 @@ console.log('[Wallet.js.177] NET START: emit CREATED'); //TODO if (otherPeerId !== myPeerId) { net.connectTo(otherPeerId); } + self.sendWalletReady(self.firstPeerId); + self.firstPeerId = null; self.emit('refresh'); } }, startOpts); @@ -203,7 +209,8 @@ Wallet.prototype.store = function(isSync) { if (isSync) { this.log('Wallet stored.'); //TODO - } else { + } + else { this.log('Wallet stored. REFRESH Emitted'); //TODO this.emit('refresh'); } @@ -291,7 +298,7 @@ Wallet.prototype.getTxProposals = function() { var txp = this.txProposals.txps[k]; var i = {txp:txp}; i.ntxid = k; - i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false; + i.signedByUs = txp.signedBy[this.getMyPeerId()]?true:false; ret.push(i); } return ret; @@ -301,7 +308,7 @@ Wallet.prototype.getTxProposal = function(ntxid) { var txp = this.txProposals.txps[ntxid]; var i = {txp:txp}; i.ntxid = ntxid; - i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false; + i.signedByUs = txp.signedBy[this.getMyPeerId()]?true:false; return i; }; @@ -319,7 +326,7 @@ Wallet.prototype.sign = function(ntxid) { var ret = false; if (b.signaturesAdded > before) { - txp.signedBy[self.privateKey.getId()] = Date.now(); + txp.signedBy[self.getMyPeerId()] = Date.now(); this.sendTxProposals(); this.store(true); ret = true; @@ -342,8 +349,9 @@ Wallet.prototype.sendTx = function(ntxid) { this.blockchain.sendRawTransaction(txHex, function(txid) { self.log('BITCOND txid:',txid); //TODO if (txid) { - self.txProposals.remove(ntxid); - self.store(true); + self.txProposals.setSent(ntxid); + self.sendTxProposals(); + self.store(); } return (txid); }); @@ -351,12 +359,15 @@ Wallet.prototype.sendTx = function(ntxid) { Wallet.prototype.addSeenToTxProposals = function() { var ret=false; - var self=this; + var myId=this.getMyPeerId(); for(var k in this.txProposals.txps) { var txp = this.txProposals.txps[k]; - if (!txp.seenBy[self.privateKey.getId()]) { - txp.seenBy[self.privateKey.getId()] = Date.now(); +console.log('[Wallet.js.364:txp:] ADD SEEN',txp); //TODO + if (!txp.seenBy[myId]) { + +console.log('[Wallet.js.367] ADDING'); //TODO + txp.seenBy[myId] = Date.now(); ret = true; } } @@ -435,9 +446,12 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) { } self.getUnspent(function(unspentList) { // TODO check enough funds, etc. +console.log('[Wallet.js.452]', self); //TODO self.createTxSync(toAddress, amountSatStr, unspentList, opts); self.sendPublicKeyRing(); // Change Address self.sendTxProposals(); + +console.log('[Wallet.js.452]', self); //TODO self.store(); return cb(); }); @@ -469,15 +483,24 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) { b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) ); } var me = {}; - if (priv) me[priv.getId()] = Date.now(); + var myId = this.getMyPeerId(); + var now = Date.now(); - this.txProposals.add({ - signedBy: priv && b.signaturesAdded ? me : {}, - seenBy: priv ? me : {}, - creator: priv.getId(), - createdTs: Date.now(), + if (priv) me[myId] = now; + +console.log('[Wallet.js.485:me:]',myId, me); //TODO + + var data = { + signedBy: (priv && b.signaturesAdded ? me : {}), + seenBy: (priv ? me : {}), + creator: myId, + createdTs: now, builder: b, - }); + }; + +console.log('[Wallet.js.499:data:]',data); //TODO + + this.txProposals.add(data); }; Wallet.prototype.connectTo = function(peerId) { diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index b6f904128..c6719ba27 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -33,7 +33,8 @@ function WalletFactory(config) { WalletFactory.prototype.log = function(){ if (!this.verbose) return; - console.log(arguments); + if (console) + console.log.apply(console, arguments); }; @@ -152,7 +153,7 @@ WalletFactory.prototype.joinCreateSession = function(peerId, cb) { if (data.type ==='walletId') { data.opts.privateKey = privateKey; var w = self.open(data.walletId, data.opts); - w.sendWalletReady(peerId); + w.firstPeerId = peerId; return cb(w); } }); diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index 2a7017535..382f9e536 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -23,6 +23,7 @@ function Network(opts) { this.debug = opts.debug || 3; this.maxPeers = opts.maxPeers || 10; this.opts = { key: opts.key }; + this.connections = {}; // For using your own peerJs server ['port', 'host', 'path', 'debug'].forEach(function(k) { @@ -69,6 +70,9 @@ Network._arrayRemove = function(el, array) { }; Network.prototype._onClose = function(peerId) { +console.log('[WebRTC.js.72:_onClose:]'); + + delete this.connections[peerId]; this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); this._notifyNetworkChange(); }; @@ -138,11 +142,11 @@ Network.prototype._checkAnyPeer = function() { } Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { - var self=this; dataConn.on('open', function() { if (!Network._inArray(dataConn.peer, self.connectedPeers)) { + self.connections[dataConn.peer] = dataConn; console.log('### DATA CONNECTION READY TO: ADDING PEER: %s (inbound: %s)', dataConn.peer, isInbound); @@ -159,11 +163,14 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { dataConn.on('error', function(e) { console.log('### DATA ERROR',e ); //TODO + self._onClose(dataConn.peer); + self._checkAnyPeer(); self.emit('dataError'); }); dataConn.on('close', function() { if (self.closing) return; + console.log('### CLOSE RECV FROM:', dataConn.peer); self._onClose(dataConn.peer); self._checkAnyPeer(); @@ -181,8 +188,6 @@ Network.prototype._setupPeerHandlers = function(openCallback) { p.on('open', function() { self.connectedPeers = [self.peerId]; - -console.log('[WebRTC.js.187] LENGTH', self.connectedPeers.length); //TODO return openCallback(); }); @@ -239,18 +244,16 @@ console.log('[WebRTC.js.237] started TRUE'); //TODO Network.prototype._sendToOne = function(peerId, data, cb) { if (peerId !== this.peerId) { - var conns = this.peer.connections[peerId]; - - if (conns) { + var dataConn = this.connections[peerId]; + if (dataConn) { var str = JSON.stringify({ sender: this.peerId, data: data }); - - for (var i = 0; i < conns.length; i++) { - var conn = conns[i]; - conn.send(str); - } + dataConn.send(str); + } + else { +console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO } } if (typeof cb === 'function') cb();