Browse Source

.

activeAddress
Ivan Socolsky 10 years ago
parent
commit
d03a16d659
  1. 11
      lib/model/txproposal.js
  2. 61
      lib/server.js
  3. 13
      lib/storage.js
  4. 6
      test/integration.js

11
lib/model/txproposal.js

@ -4,23 +4,34 @@ function TxProposal(opts) {
opts = opts || {};
this.createdOn = Math.floor(Date.now() / 1000);
this.id = opts.id;
this.creatorId = opts.creatorId;
this.toAddress = opts.toAddress;
this.amount = opts.amount;
this.changeAddress = opts.changeAddress;
this.inputs = opts.inputs;
this.actions = [];
};
TxProposal.fromObj = function (obj) {
var x = new TxProposal();
x.createdOn = obj.createdOn;
x.id = obj.id;
x.creatorId = obj.creatorId;
x.toAddress = obj.toAddress;
x.amount = obj.amount;
x.changeAddress = obj.changeAddress;
x.inputs = obj.inputs;
x.raw = obj.raw;
x.actions = _.map(obj.actions, function(a) {
return {
createdOn: a.createdOn,
copayerId: a.copayerId,
type: a.type,
signature: a.signature,
};
});
return x;
};

61
lib/server.js

@ -41,7 +41,7 @@ function CopayServer(opts) {
CopayServer.prototype.createWallet = function (opts, cb) {
var self = this;
self.getWallet({ id: opts.id }, function (err, wallet) {
self.storage.fetchWallet(opts.id, function (err, wallet) {
if (err) return cb(err);
if (wallet) return cb('Wallet already exists');
@ -69,7 +69,9 @@ CopayServer.prototype.createWallet = function (opts, cb) {
var self = this;
self.storage.fetchWallet(opts.id, function (err, wallet) {
if (err || !wallet) return cb(err);
if (err) return cb(err);
if (!wallet) return cb('Wallet not found');
if (opts.includeCopayers) {
self.storage.fetchCopayers(wallet.id, function (err, copayers) {
if (err) return cb(err);
@ -109,8 +111,7 @@ CopayServer.prototype._runLocked = function (walletId, cb, task) {
self._runLocked(opts.walletId, cb, function (cb) {
self.getWallet({ id: opts.walletId, includeCopayers: true }, function (err, wallet) {
if (err) return cb(err);
if (!wallet) return cb('Wallet not found');
if (err || !wallet) return cb(err);
if (_.find(wallet.copayers, { xPubKey: opts.xPubKey })) return cb('Copayer already in wallet');
if (wallet.copayers.length == wallet.n) return cb('Wallet full');
// TODO: validate copayer's extended public key using the public key from this wallet
@ -152,8 +153,7 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
self._runLocked(opts.walletId, cb, function (cb) {
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
if (!wallet) return cb('Wallet not found');
if (err || !wallet) return cb(err);
var index = wallet.addressIndex++;
self.storage.storeWallet(wallet, function (err) {
@ -219,7 +219,7 @@ CopayServer.prototype._getUtxos = function (opts, cb) {
var self = this;
// Get addresses for this wallet
self.storage.getAddresses(opts.walletId, function (err, addresses) {
self.storage.fetchAddresses(opts.walletId, function (err, addresses) {
if (err) return cb(err);
if (addresses.length == 0) return cb('The wallet has no addresses');
@ -268,14 +268,12 @@ CopayServer.prototype.createTx = function (opts, cb) {
var self = this;
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
if (!wallet) return cb('Wallet not found');
if (err || !wallet) return cb(err);
self._getUtxos({ walletId: wallet.id }, function (err, utxos) {
if (err) return cb('Could not retrieve UTXOs');
if (err) return cb(err);
self._doCreateTx(opts.copayerId, opts.toAddress, opts.amount, opts.changeAddress, utxos, function (err, tx) {
if (err) return cb('Could not create transaction');
var tx = self._doCreateTx(opts.copayerId, opts.toAddress, opts.amount, opts.changeAddress, utxos);
self.storage.storeTx(tx, function (err) {
if (err) return cb(err);
@ -284,7 +282,12 @@ CopayServer.prototype.createTx = function (opts, cb) {
});
});
});
});
};
CopayServer.prototype._broadcastTx = function (tx, cb) {
cb = cb || function () {};
throw 'not implemented';
};
/**
@ -292,27 +295,35 @@ CopayServer.prototype.createTx = function (opts, cb) {
* @param {Object} opts
* @param {string} opts.walletId - The wallet id.
* @param {string} opts.copayerId - The wallet id.
* @param {string} opts.ntxid - The identifier of the transaction.
* @param {string} opts.txProposalId - The identifier of the transaction.
* @param {string} opts.signature - The signature of the tx for this copayer.
*/
CopayServer.prototype.signTx = function (opts, cb) {
var self = this;
self.getWallet({ id: opts.walletId }, function (err, wallet) {
if (err) return cb(err);
if (!wallet) return cb('Wallet not found');
self._getUtxos({ walletId: wallet.id }, function (err, utxos) {
if (err) return cb('Could not retrieve UTXOs');
self._doCreateTx(opts.copayerId, opts.toAddress, opts.amount, opts.changeAddress, utxos, function (err, tx) {
if (err) return cb('Could not create transaction');
if (err || !wallet) return cb(err);
self.storage.storeTx(tx, function (err) {
self.fetchTx(wallet.id, opts.txProposalId, function (err, tx) {
if (err) return cb(err);
if (!tx) return cb('Transaction proposal not found');
var action = _.find(tx.actions, { copayerId: opts.copayerId });
if (action) return cb('Copayer already acted upon this transaction proposal');
if (tx.status != 'pending') return cb('The transaction proposal is not pending');
tx.sign(opts.copayerId, opts.signature);
if (tx.isRejected()) {
tx.status = 'rejected';
} else if (tx.isAccepted()) {
tx.status = 'accepted';
}
self.storage.storeTx(wallet.id, tx, function (err) {
if (err) return cb(err);
return cb(null, tx);
});
if (tx.status == 'accepted');
self._broadcastTx(tx);
return cb();
});
});
});

13
lib/storage.js

@ -53,6 +53,15 @@ Storage.prototype.fetchCopayers = function (walletId, cb) {
});
};
Storage.prototype.fetchTx = function (walletId, txProposalId, cb) {
this.db.get('wallet-' + walletId + '-tx-' + txProposalId, function (err, data) {
if (err) {
if (err.notFound) return cb();
return cb(err);
}
return cb(null, TxProposal.fromObj(data));
});
};
Storage.prototype.storeWallet = function (wallet, cb) {
this.db.put('wallet-' + wallet.id, wallet, cb);
@ -67,10 +76,10 @@ Storage.prototype.storeAddress = function (walletId, address, cb) {
};
Storage.prototype.storeTx = function (walletId, tx, cb) {
this.db.put('wallet-' + walletId + '-tx-' + tx.ntxid, tx, cb);
this.db.put('wallet-' + walletId + '-tx-' + tx.txProposalId, tx, cb);
};
Storage.prototype.getAddresses = function (walletId, cb) {
Storage.prototype.fetchAddresses = function (walletId, cb) {
var addresses = [];
var key = 'wallet-' + walletId + '-address-';
this.db.createReadStream({ gte: key, lt: key + '~' })

6
test/integration.js

@ -68,7 +68,7 @@ describe('Copay server', function() {
});
});
it('should return undefined when requesting non-existent wallet', function (done) {
it('should fail when requesting non-existent wallet', function (done) {
var w1 = new Wallet({
id: '123',
name: 'my wallet',
@ -95,8 +95,8 @@ describe('Copay server', function() {
}]);
server.getWallet({ id: '345' }, function (err, wallet) {
should.not.exist(err);
should.not.exist(wallet);
should.exist(err);
err.should.equal('Wallet not found');
done();
});
});

Loading…
Cancel
Save