test passing with notifications
This commit is contained in:
parent
7a4d16f88e
commit
d548639334
|
@ -5,21 +5,28 @@ var Uuid = require('uuid');
|
|||
/*
|
||||
* notifications examples
|
||||
*
|
||||
* newCopayer
|
||||
* newTxProposal
|
||||
* txProposalAcceptedBy
|
||||
* txProposalRejectedBy
|
||||
* txProposalFinallyRejected
|
||||
* txProposalFinallyAccepted
|
||||
* newIncommingTransaction
|
||||
* newOutgoingTransaction
|
||||
* NewCopayer -
|
||||
* NewAddress -
|
||||
* NewTxProposal - (amount)
|
||||
* TxProposalAcceptedBy - (txProposalId, copayerId)
|
||||
* TxProposalRejectedBy - (txProposalId, copayerId)
|
||||
* txProposalFinallyRejected - txProposalId
|
||||
* txProposalFinallyAccepted - txProposalId
|
||||
*
|
||||
* newIncommingTx (amount)
|
||||
* newOutgoingTx - (txProposalId, txid)
|
||||
*
|
||||
* data Examples:
|
||||
* { amount: 'xxx', address: 'xxx'}
|
||||
* { txProposalId: 'xxx', copayerId: 'xxx' }
|
||||
*
|
||||
* Data is meant to provide only the needed information
|
||||
* to notify the user
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
function Notification(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
|
@ -39,4 +46,4 @@ Notification.prototype.fromObj = function(obj) {
|
|||
return x;
|
||||
};
|
||||
|
||||
module.export = Notification;
|
||||
module.exports = Notification;
|
||||
|
|
|
@ -6,6 +6,7 @@ var log = require('npmlog');
|
|||
log.debug = log.verbose;
|
||||
var inherits = require('inherits');
|
||||
var events = require('events');
|
||||
var nodeutil = require('util');
|
||||
|
||||
var Bitcore = require('bitcore');
|
||||
var PublicKey = Bitcore.PublicKey;
|
||||
|
@ -22,6 +23,7 @@ var Wallet = require('./model/wallet');
|
|||
var Copayer = require('./model/copayer');
|
||||
var Address = require('./model/address');
|
||||
var TxProposal = require('./model/txproposal');
|
||||
var Notification = require('./model/Notification');
|
||||
|
||||
|
||||
var initialized = false;
|
||||
|
@ -36,7 +38,7 @@ function CopayServer() {
|
|||
this.storage = storage;
|
||||
};
|
||||
|
||||
util.inherits(CopayServer, events.EventEmitter);
|
||||
nodeutil.inherits(CopayServer, events.EventEmitter);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -147,19 +149,22 @@ CopayServer.prototype._verifySignature = function(text, signature, pubKey) {
|
|||
|
||||
|
||||
/**
|
||||
* notify
|
||||
* _notify
|
||||
*
|
||||
* @param type
|
||||
* @param data
|
||||
*/
|
||||
CopayServer.prototype.notify = function(type, data) {
|
||||
CopayServer.prototype._notify = function(type, data) {
|
||||
var self = this;
|
||||
|
||||
var walletId = self.walletId || data.walletId;
|
||||
$.checkState(walletId);
|
||||
|
||||
var n = new Notification({
|
||||
type: type,
|
||||
data: data,
|
||||
});
|
||||
this.storage.storeNotification(this.walletId, n, function () {
|
||||
this.storage.storeNotification(walletId, n, function() {
|
||||
self.emit(n);
|
||||
});
|
||||
};
|
||||
|
@ -202,7 +207,9 @@ CopayServer.prototype.joinWallet = function(opts, cb) {
|
|||
|
||||
wallet.addCopayer(copayer);
|
||||
self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) {
|
||||
self.notify('newCopayer');
|
||||
self._notify('NewCopayer', {
|
||||
walletId: opts.walletId,
|
||||
});
|
||||
return cb(err, copayer.id);
|
||||
});
|
||||
});
|
||||
|
@ -227,6 +234,7 @@ CopayServer.prototype.createAddress = function(opts, cb) {
|
|||
self.storage.storeAddressAndWallet(wallet, address, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('NewAddress');
|
||||
return cb(null, address);
|
||||
});
|
||||
});
|
||||
|
@ -411,17 +419,20 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) {
|
|||
CopayServer.prototype.createTx = function(opts, cb) {
|
||||
var self = this;
|
||||
|
||||
if (!Utils.checkRequired(opts, ['toAddress', 'amount'])) return cb(new ClientError('Required argument missing'));
|
||||
if (!Utils.checkRequired(opts, ['toAddress', 'amount']))
|
||||
return cb(new ClientError('Required argument missing'));
|
||||
|
||||
Utils.runLocked(self.walletId, cb, function(cb) {
|
||||
self.getWallet({}, function(err, wallet) {
|
||||
if (err) return cb(err);
|
||||
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
|
||||
if (wallet.isShared() && !Utils.checkRequired(opts, 'proposalSignature')) return cb(new ClientError('Proposal signature is required for shared wallets'));
|
||||
if (wallet.isShared() && !Utils.checkRequired(opts, 'proposalSignature'))
|
||||
return cb(new ClientError('Proposal signature is required for shared wallets'));
|
||||
|
||||
var copayer = wallet.getCopayer(self.copayerId);
|
||||
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
||||
if (!self._verifySignature(msg, opts.proposalSignature, copayer.signingPubKey)) return cb(new ClientError('Invalid proposal signature'));
|
||||
if (!self._verifySignature(msg, opts.proposalSignature, copayer.signingPubKey))
|
||||
return cb(new ClientError('Invalid proposal signature'));
|
||||
|
||||
var toAddress;
|
||||
try {
|
||||
|
@ -429,7 +440,8 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
|||
} catch (ex) {
|
||||
return cb(new ClientError('INVALIDADDRESS', 'Invalid address'));
|
||||
}
|
||||
if (toAddress.network != wallet.getNetworkName()) return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network'));
|
||||
if (toAddress.network != wallet.getNetworkName())
|
||||
return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network'));
|
||||
|
||||
self._getUtxos(function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
|
@ -463,6 +475,9 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
|||
self.storage.storeTx(wallet.id, txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('NewTxProposal', {
|
||||
amount: opts.amount
|
||||
});
|
||||
return cb(null, txp);
|
||||
});
|
||||
});
|
||||
|
@ -538,6 +553,7 @@ CopayServer.prototype.removePendingTx = function(opts, cb) {
|
|||
if (actors.length == 1 && actors[0] !== self.copayerId)
|
||||
return cb(new ClientError('Not allowed to erase this TX'));
|
||||
|
||||
self._notify('transactionProposalRemoved');
|
||||
self.storage.removeTx(self.walletId, opts.id, cb);
|
||||
});
|
||||
});
|
||||
|
@ -590,7 +606,17 @@ CopayServer.prototype.signTx = function(opts, cb) {
|
|||
self.storage.storeTx(self.walletId, txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('TxProposalAcceptedBy', {
|
||||
txProposalId: opts.txProposalId,
|
||||
copayerId: self.copayerId,
|
||||
});
|
||||
|
||||
if (txp.status == 'accepted') {
|
||||
|
||||
self._notify('TxProposalFinallyAccepted', {
|
||||
txProposalId: opts.txProposalId,
|
||||
});
|
||||
|
||||
self._broadcastTx(txp, function(err, txid) {
|
||||
if (err) return cb(err);
|
||||
|
||||
|
@ -598,6 +624,11 @@ CopayServer.prototype.signTx = function(opts, cb) {
|
|||
self.storage.storeTx(self.walletId, txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('newOutgoingTx', {
|
||||
txProposalId: opts.txProposalId,
|
||||
txid: txid
|
||||
});
|
||||
|
||||
return cb(null, txp);
|
||||
});
|
||||
});
|
||||
|
@ -628,14 +659,29 @@ CopayServer.prototype.rejectTx = function(opts, cb) {
|
|||
var action = _.find(txp.actions, {
|
||||
copayerId: self.copayerId
|
||||
});
|
||||
if (action) return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal'));
|
||||
if (txp.status != 'pending') return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending'));
|
||||
if (action)
|
||||
return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal'));
|
||||
|
||||
if (txp.status != 'pending')
|
||||
return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending'));
|
||||
|
||||
txp.reject(self.copayerId);
|
||||
|
||||
self.storage.storeTx(self.walletId, txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._notify('TxProposalRejectedBy', {
|
||||
txProposalId: opts.txProposalId,
|
||||
copayerId: self.copayerId,
|
||||
});
|
||||
|
||||
|
||||
if (txp.status == 'rejected') {
|
||||
self._notify('TxProposalFinallyRejected', {
|
||||
txProposalId: opts.txProposalId,
|
||||
});
|
||||
};
|
||||
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -311,6 +311,9 @@ Storage.prototype._removeCopayers = function(walletId, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
Storage.prototype._removeAllNotifications = function(walletId, cb) {
|
||||
this._delByKey(KEY.NOTIFICATION(walletId), cb);
|
||||
};
|
||||
|
||||
|
||||
Storage.prototype._removeAllAddresses = function(walletId, cb) {
|
||||
|
@ -323,23 +326,11 @@ Storage.prototype.removeWallet = function(walletId, cb) {
|
|||
async.series([
|
||||
|
||||
function(next) {
|
||||
// This should be the first step. Will check the wallet exists
|
||||
self._removeCopayers(walletId, next);
|
||||
},
|
||||
function(next) {
|
||||
self._removeAllAddresses(walletId, next);
|
||||
},
|
||||
function(next) {
|
||||
self.removeAllPendingTxs(walletId, next);
|
||||
},
|
||||
function(next) {
|
||||
self.removeAllTxs(walletId, next);
|
||||
},
|
||||
function(next) {
|
||||
var ops = [{
|
||||
type: 'del',
|
||||
key: KEY.WALLET(walletId),
|
||||
}];
|
||||
self.db.batch(ops, next);
|
||||
self._delByKey(walletPrefix(walletId), cb);
|
||||
},
|
||||
], cb);
|
||||
};
|
||||
|
|
|
@ -1202,6 +1202,7 @@ describe('Copay server', function() {
|
|||
server.removeWallet({}, function(err) {
|
||||
i = 0;
|
||||
server.storage._dump(function() {
|
||||
server.storage._dump();
|
||||
i.should.equal(0);
|
||||
done();
|
||||
}, count);
|
||||
|
|
Loading…
Reference in New Issue