Browse Source

fetch address by walletId/coin

feat/estimateFee-limit
Ivan Socolsky 8 years ago
parent
commit
30494a8133
No known key found for this signature in database GPG Key ID: FAECE6A05FAA4F56
  1. 10
      lib/blockchainmonitor.js
  2. 6
      lib/server.js
  3. 54
      lib/storage.js
  4. 69
      test/integration/server.js

10
lib/blockchainmonitor.js

@ -102,7 +102,7 @@ BlockchainMonitor.prototype._initExplorer = function(coin, network, explorer) {
socket.on('connect_error', function() { socket.on('connect_error', function() {
log.error('Error connecting to ' + explorer.getConnectionInfo()); log.error('Error connecting to ' + explorer.getConnectionInfo());
}); });
socket.on('tx', _.bind(self._handleIncomingTx, self)); socket.on('tx', _.bind(self._handleIncomingTx, self, coin, network));
socket.on('block', _.bind(self._handleNewBlock, self, coin, network)); socket.on('block', _.bind(self._handleNewBlock, self, coin, network));
}; };
@ -150,7 +150,7 @@ BlockchainMonitor.prototype._handleThirdPartyBroadcasts = function(data, process
}); });
}; };
BlockchainMonitor.prototype._handleIncomingPayments = function(data) { BlockchainMonitor.prototype._handleIncomingPayments = function(coin, network, data) {
var self = this; var self = this;
if (!data || !data.vout) return; if (!data || !data.vout) return;
@ -166,7 +166,7 @@ BlockchainMonitor.prototype._handleIncomingPayments = function(data) {
if (_.isEmpty(outs)) return; if (_.isEmpty(outs)) return;
async.each(outs, function(out, next) { async.each(outs, function(out, next) {
self.storage.fetchAddress(out.address, function(err, address) { self.storage.fetchAddressByCoin(coin, out.address, function(err, address) {
if (err) { if (err) {
log.error('Could not fetch addresses from the db'); log.error('Could not fetch addresses from the db');
return next(err); return next(err);
@ -219,9 +219,9 @@ BlockchainMonitor.prototype._updateActiveAddresses = function(address, cb) {
}); });
}; };
BlockchainMonitor.prototype._handleIncomingTx = function(data) { BlockchainMonitor.prototype._handleIncomingTx = function(coin, network, data) {
this._handleThirdPartyBroadcasts(data); this._handleThirdPartyBroadcasts(data);
this._handleIncomingPayments(data); this._handleIncomingPayments(coin, network, data);
}; };
BlockchainMonitor.prototype._notifyNewBlock = function(coin, network, hash) { BlockchainMonitor.prototype._notifyNewBlock = function(coin, network, hash) {

6
lib/server.js

@ -427,7 +427,7 @@ WalletService.prototype.getWalletFromIdentifier = function(opts, cb) {
}); });
}, },
function(done) { function(done) {
self.storage.fetchAddress(opts.identifier, function(err, address) { self.storage.fetchAddressByCoin(Defaults.COIN, opts.identifier, function(err, address) {
if (address) walletId = address.walletId; if (address) walletId = address.walletId;
return done(err); return done(err);
}); });
@ -461,7 +461,7 @@ WalletService.prototype.getWalletFromIdentifier = function(opts, cb) {
var outputs = _.first(self._normalizeTxHistory(tx)).outputs; var outputs = _.first(self._normalizeTxHistory(tx)).outputs;
var toAddresses = _.pluck(outputs, 'address'); var toAddresses = _.pluck(outputs, 'address');
async.detect(toAddresses, function(addressStr, nextAddress) { async.detect(toAddresses, function(addressStr, nextAddress) {
self.storage.fetchAddress(addressStr, function(err, address) { self.storage.fetchAddressByCoin(coinNetwork.coin, addressStr, function(err, address) {
if (err || !address) return nextAddress(err, false); if (err || !address) return nextAddress(err, false);
walletId = address.walletId; walletId = address.walletId;
nextAddress(null, true); nextAddress(null, true);
@ -2047,7 +2047,7 @@ WalletService.prototype.createTx = function(opts, cb) {
}); });
} else { } else {
if (opts.changeAddress) { if (opts.changeAddress) {
self.storage.fetchAddress(opts.changeAddress, function(err, address) { self.storage.fetchAddressByWalletId(wallet.id, opts.changeAddress, function(err, address) {
if (err) return cb(Errors.INVALID_CHANGE_ADDRESS); if (err) return cb(Errors.INVALID_CHANGE_ADDRESS);
return cb(null, address); return cb(null, address);
}); });

54
lib/storage.js

@ -461,6 +461,7 @@ Storage.prototype.storeAddress = function(address, cb) {
var self = this; var self = this;
self.db.collection(collections.ADDRESSES).update({ self.db.collection(collections.ADDRESSES).update({
walletId: address.walletId,
address: address.address address: address.address
}, address, { }, address, {
w: 1, w: 1,
@ -471,48 +472,46 @@ Storage.prototype.storeAddress = function(address, cb) {
Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) { Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) {
var self = this; var self = this;
function saveAddresses(addresses, cb) { var addresses = [].concat(addresses);
if (_.isEmpty(addresses)) return cb(); if (_.isEmpty(addresses)) return cb();
self.db.collection(collections.ADDRESSES).insert(addresses, { self.db.collection(collections.ADDRESSES).insert(addresses, {
w: 1 w: 1
}, cb); }, function(err) {
if (err) return cb(err);
self.storeWallet(wallet, cb);
});
}; };
var addresses = [].concat(addresses); Storage.prototype.fetchAddressByWalletId = function(walletId, address, cb) {
if (addresses.length == 0) return cb(); var self = this;
async.filter(addresses, function(address, next) { this.db.collection(collections.ADDRESSES).findOne({
self.db.collection(collections.ADDRESSES).findOne({ walletId: walletId,
address: address.address, address: address,
}, {
walletId: true,
}, function(err, result) { }, function(err, result) {
if (err || !result) return next(true);
if (result.walletId != wallet.id) {
log.warn('Address ' + address.address + ' exists in more than one wallet.');
return next(true);
}
// Ignore if address was already in wallet
return next(false);
});
}, function(newAddresses) {
if (newAddresses.length < addresses.length) {
log.warn('Attempted to store already existing addresses on wallet ' + wallet.id);
}
saveAddresses(newAddresses, function(err) {
if (err) return cb(err); if (err) return cb(err);
self.storeWallet(wallet, cb); if (!result) return cb();
});
return cb(null, Model.Address.fromObj(result));
}); });
}; };
Storage.prototype.fetchAddress = function(address, cb) { Storage.prototype.fetchAddressByCoin = function(coin, address, cb) {
var self = this; var self = this;
this.db.collection(collections.ADDRESSES).findOne({ this.db.collection(collections.ADDRESSES).find({
address: address, address: address,
}, function(err, result) { }).toArray(function(err, result) {
if (err) return cb(err); if (err) return cb(err);
if (!result || _.isEmpty(result)) return cb();
if (result.length > 1) {
result = _.find(result, function(address) {
return coin == (address.coin || Defaults.COIN);
});
} else {
result = _.first(result);
}
if (!result) return cb(); if (!result) return cb();
return cb(null, Model.Address.fromObj(result)); return cb(null, Model.Address.fromObj(result));
@ -610,6 +609,7 @@ Storage.prototype.cleanActiveAddresses = function(walletId, cb) {
Storage.prototype.storeActiveAddresses = function(walletId, addresses, cb) { Storage.prototype.storeActiveAddresses = function(walletId, addresses, cb) {
var self = this; var self = this;
if (_.isEmpty(addresses)) return cb();
async.each(addresses, function(address, next) { async.each(addresses, function(address, next) {
var record = { var record = {
walletId: walletId, walletId: walletId,

69
test/integration/server.js

@ -1188,22 +1188,6 @@ describe('Wallet service', function() {
}); });
}); });
it('should protect against storing same address multiple times', function(done) {
server.createAddress({}, function(err, address) {
should.not.exist(err);
should.exist(address);
delete address._id;
server.storage.storeAddressAndWallet(wallet, address, function(err) {
should.not.exist(err);
server.getMainAddresses({}, function(err, addresses) {
should.not.exist(err);
addresses.length.should.equal(1);
done();
});
});
});
});
it('should create many addresses on simultaneous requests', function(done) { it('should create many addresses on simultaneous requests', function(done) {
var N = 5; var N = 5;
async.mapSeries(_.range(N), function(i, cb) { async.mapSeries(_.range(N), function(i, cb) {
@ -7615,42 +7599,57 @@ describe('Wallet service', function() {
}); });
}); });
describe.skip('BTC & BCH wallets with same seed', function() { describe('BTC & BCH wallets with same seed', function() {
var server, wBtc, wBch; var server = {},
wallet = {};
beforeEach(function(done) { beforeEach(function(done) {
helpers.createAndJoinWallet(1, 1, function(s, w) { helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s; server.btc = s;
wBtc = w; wallet.btc = w;
w.copayers[0].id.should.equal(TestData.copayers[0].id44btc);
helpers.createAndJoinWallet(1, 1, function(s, w) {
wBch = w;
w.copayers[0].id.should.equal(TestData.copayers[0].id44btc); w.copayers[0].id.should.equal(TestData.copayers[0].id44btc);
helpers.createAndJoinWallet(1, 1, {
coin: 'bch'
}, function(s, w) {
server.bch = s;
wallet.bch = w;
w.copayers[0].id.should.equal(TestData.copayers[0].id44bch);
done(); done();
}); });
}); });
}); });
it('should create address', function(done) { it('should create address', function(done) {
server.createAddress({}, function(err, address) { server.btc.createAddress({}, function(err, address) {
should.not.exist(err); should.not.exist(err);
should.exist(address); should.exist(address);
address.walletId.should.equal(wallet.id); address.walletId.should.equal(wallet.btc.id);
address.coin.should.equal('btc');
address.network.should.equal('livenet'); address.network.should.equal('livenet');
address.address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG'); address.address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG');
address.isChange.should.be.false; server.bch.createAddress({}, function(err, address) {
address.path.should.equal('m/0/0');
address.type.should.equal('P2PKH');
server.getNotifications({}, function(err, notifications) {
should.not.exist(err); should.not.exist(err);
var notif = _.find(notifications, { should.exist(address);
type: 'NewAddress' address.walletId.should.equal(wallet.bch.id);
}); address.coin.should.equal('bch');
should.exist(notif); address.network.should.equal('livenet');
notif.data.address.should.equal(address.address); address.address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG');
server.btc.getMainAddresses({}, function(err, addresses) {
should.not.exist(err);
addresses.length.should.equal(1);
addresses[0].coin.should.equal('btc');
addresses[0].walletId.should.equal(wallet.btc.id);
addresses[0].address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG');
server.bch.getMainAddresses({}, function(err, addresses) {
should.not.exist(err);
addresses.length.should.equal(1);
addresses[0].coin.should.equal('bch');
addresses[0].walletId.should.equal(wallet.bch.id);
addresses[0].address.should.equal('1L3z9LPd861FWQhf3vDn89Fnc9dkdBo2CG');
done(); done();
}); });
}); });
}); });
});
});
}); });
}); });

Loading…
Cancel
Save