diff --git a/lib/blockchainexplorer.js b/lib/blockchainexplorer.js index 70fd076..bee70b9 100644 --- a/lib/blockchainexplorer.js +++ b/lib/blockchainexplorer.js @@ -27,10 +27,10 @@ function BlockChainExplorer(opts) { url = 'https://test-insight.bitpay.com:443' break; } - var bc = new Explorers.Insight(url, network); - bc.getTransactions = _.bind(getTransactionsInsight, bc, url); - bc.initSocket = _.bind(initSocketInsight, bc, url); - return bc; + var explorer = new Explorers.Insight(url, network); + explorer.getTransactions = _.bind(getTransactionsInsight, explorer, url); + explorer.initSocket = _.bind(initSocketInsight, explorer, url); + return explorer; break; default: throw new Error('Provider ' + provider + ' not supported'); @@ -38,7 +38,6 @@ function BlockChainExplorer(opts) { }; }; - function getTransactionsInsight(url, addresses, cb) { request({ method: "POST", diff --git a/lib/blockchainmonitor.js b/lib/blockchainmonitor.js index 2b7bc1d..a66fc8c 100644 --- a/lib/blockchainmonitor.js +++ b/lib/blockchainmonitor.js @@ -13,27 +13,27 @@ var nodeutil = require('util'); var WalletUtils = require('bitcore-wallet-utils'); var Bitcore = WalletUtils.Bitcore; var WalletService = require('./server'); -var BlockExplorer = require('./blockexplorer'); +var BlockchainExplorer = require('./blockchainexplorer'); var Notification = require('./model/notification'); function BlockchainMonitor() { + var self = this; this.subscriptions = {}; this.sockets = {}; - - this._initBlockExplorerSocket('insight', 'livenet'); - this._initBlockExplorerSocket('insight', 'testnet'); + this.sockets['livenet'] = self._getBlockchainExplorerSocket('insight', 'livenet'); + this.sockets['testnet'] = self._getBlockchainExplorerSocket('insight', 'testnet'); }; nodeutil.inherits(BlockchainMonitor, events.EventEmitter); -BlockchainMonitor.prototype._initBlockExplorerSocket = function(provider, network) { - var explorer = new BlockExplorer({ +BlockchainMonitor.prototype._getBlockchainExplorerSocket = function(provider, network) { + var explorer = new BlockchainExplorer({ provider: provider, network: network, }); - this.sockets[network] = explorer.initSocket(); + return explorer.initSocket(); }; BlockchainMonitor.prototype.subscribeAddresses = function(walletId, addresses) { @@ -60,6 +60,7 @@ BlockchainMonitor.prototype.subscribeAddresses = function(walletId, addresses) { addresses: [], }; }; + var addresses = [].concat(addresses); var network = Bitcore.Address.fromString(addresses[0]).network.name; var socket = self.sockets[network]; @@ -70,7 +71,7 @@ BlockchainMonitor.prototype.subscribeAddresses = function(walletId, addresses) { }); }; -BlockchainMonitor.prototype.subscribeWallet = function(walletService) { +BlockchainMonitor.prototype.subscribeWallet = function(walletService, cb) { var self = this; var walletId = walletService.walletId; @@ -79,10 +80,10 @@ BlockchainMonitor.prototype.subscribeWallet = function(walletService) { walletService.getMainAddresses({}, function(err, addresses) { if (err) { delete self.subscriptions[walletId]; - log.warn('Could not subscribe to addresses for wallet ' + walletId); - return; + return cb(new Error('Could not subscribe to addresses for wallet ' + walletId)); } self.subscribeAddresses(walletService.walletId, _.pluck(addresses, 'address')); + return cb(); }); }; diff --git a/lib/wsapp.js b/lib/wsapp.js index 19b3a78..d307be2 100644 --- a/lib/wsapp.js +++ b/lib/wsapp.js @@ -60,7 +60,9 @@ WsApp.start = function(server) { socket.join(service.walletId); socket.emit('authorized'); - bcMonitor.subscribeWallet(service); + bcMonitor.subscribeWallet(service, function(err) { + if (err) log.warn(err.message); + }); }); }); }); diff --git a/test/integration/server.js b/test/integration/server.js index 132ce88..4486473 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -16,6 +16,7 @@ var Utils = require('../../lib/utils'); var WalletUtils = require('bitcore-wallet-utils'); var Bitcore = WalletUtils.Bitcore; var Storage = require('../../lib/storage'); +var BlockchainMonitor = require('../../lib/blockchainmonitor'); var Wallet = require('../../lib/model/wallet'); var TxProposal = require('../../lib/model/txproposal'); @@ -201,7 +202,101 @@ helpers.createAddresses = function(server, wallet, main, change, cb) { var db, storage, blockchainExplorer; -describe('Copay server', function() { +describe('Blockchain monitor', function() { + var bcSocket, monitor; + + beforeEach(function() { + db = levelup(memdown, { + valueEncoding: 'json' + }); + storage = new Storage({ + db: db + }); + blockchainExplorer = sinon.stub(); + + WalletService.initialize({ + storage: storage, + blockchainExplorer: blockchainExplorer, + }); + helpers.offset = 0; + + bcSocket = sinon.stub(); + bcSocket.emit = sinon.stub(); + bcSocket.on = sinon.stub(); + sinon.stub(BlockchainMonitor.prototype, '_getBlockchainExplorerSocket').onFirstCall().returns(bcSocket); + monitor = new BlockchainMonitor(); + }); + + afterEach(function() { + BlockchainMonitor.prototype._getBlockchainExplorerSocket.restore(); + }); + + it('should subscribe wallet', function(done) { + helpers.createAndJoinWallet(2, 2, function(server, wallet) { + server.createAddress({}, function(err, address1) { + should.not.exist(err); + server.createAddress({}, function(err, address2) { + should.not.exist(err); + monitor.subscribeWallet(server, function(err) { + should.not.exist(err); + bcSocket.emit.calledTwice.should.be.true; + bcSocket.emit.calledWith('subscribe', address1.address).should.be.true; + bcSocket.emit.calledWith('subscribe', address2.address).should.be.true; + done(); + }); + }); + }); + }); + }); + + it('should be able to subscribe new address', function(done) { + helpers.createAndJoinWallet(2, 2, function(server, wallet) { + server.createAddress({}, function(err, address1) { + should.not.exist(err); + monitor.subscribeWallet(server, function(err) { + should.not.exist(err); + bcSocket.emit.calledOnce.should.be.true; + bcSocket.emit.calledWith('subscribe', address1.address).should.be.true; + server.createAddress({}, function(err, address2) { + should.not.exist(err); + monitor.subscribeAddresses(wallet.id, address2.address); + bcSocket.emit.calledTwice.should.be.true; + bcSocket.emit.calledWith('subscribe', address2.address).should.be.true; + done(); + }); + }); + }); + }); + }); + + it('should create NewIncomingTx notification when a new tx arrives on registered address', function(done) { + helpers.createAndJoinWallet(2, 2, function(server, wallet) { + server.createAddress({}, function(err, address1) { + should.not.exist(err); + monitor.subscribeWallet(server, function(err) { + should.not.exist(err); + bcSocket.on.calledOnce.should.be.true; + bcSocket.on.getCall(0).args[0].should.equal(address1.address); + var handler = bcSocket.on.getCall(0).args[1]; + _.isFunction(handler).should.be.true; + + var emitSpy = sinon.spy(monitor, 'emit'); + handler('txid'); + emitSpy.calledOnce.should.be.true; + emitSpy.getCall(0).args[0].should.equal('notification'); + var notification = emitSpy.getCall(0).args[1]; + notification.type.should.equal('NewIncomingTx'); + notification.data.address.should.equal(address1.address); + notification.data.txid.should.equal('txid'); + done(); + }); + }); + }); + }); +}); + + +describe('Wallet service', function() { beforeEach(function() { db = levelup(memdown, { valueEncoding: 'json'