Merge pull request #13 from isocolsky/reject

reject & rm
This commit is contained in:
Matias Alejo Garcia 2015-02-15 13:18:12 -03:00
commit b63b27280e
10 changed files with 105 additions and 79 deletions

12
app.js
View File

@ -207,7 +207,17 @@ router.post('/v1/txproposals/:id/signatures/', function(req, res) {
router.post('/v1/txproposals/:id/rejections', function(req, res) { router.post('/v1/txproposals/:id/rejections', function(req, res) {
getServerWithAuth(req, res, function(server) { getServerWithAuth(req, res, function(server) {
req.body.txProposalId = req.params['id']; req.body.txProposalId = req.params['id'];
server.signTx(req.body, function(err, txp) { server.rejectTx(req.body, function(err, txp) {
if (err) return returnError(err, res, req);
res.end();
});
});
});
router.delete('/v1/txproposals/:id/', function(req, res) {
getServerWithAuth(req, res, function(server) {
req.body.txProposalId = req.params['id'];
server.removePendingTx(req.body, function(err) {
if (err) return returnError(err, res, req); if (err) return returnError(err, res, req);
res.end(); res.end();
}); });

View File

@ -11,8 +11,9 @@ program
.command('addresses', 'list addresses') .command('addresses', 'list addresses')
.command('balance', 'wallet balance') .command('balance', 'wallet balance')
.command('send <address> <amount> <note>', 'send bitcoins') .command('send <address> <amount> <note>', 'send bitcoins')
.command('sign <txpId>', 'sign a Transaction Proposal') .command('sign <txpId>', 'sign a transaction proposal')
.command('reject <txpId>', 'reject a Transaction Proposal') .command('reject <txpId> [reason]', 'reject a transaction proposal')
.command('rm <txpId>', 'remove a transaction proposal')
.parse(process.argv); .parse(process.argv);

View File

@ -9,43 +9,32 @@ program
.version('0.0.1') .version('0.0.1')
.option('-c,--config [file]', 'Wallet config filename') .option('-c,--config [file]', 'Wallet config filename')
.option('-v,--verbose', 'be verbose') .option('-v,--verbose', 'be verbose')
.usage('[options] <txpid>') .usage('[options] <txpid> [reason]')
.parse(process.argv); .parse(process.argv);
var args = program.args; var args = program.args;
if (!args[0]) if (!args[0])
program.help(); program.help();
var txpid = args[0]; var txpid = args[0];
var reason = args[1] || '';
var cli = new Client({ var cli = new Client({
filename: program.config filename: program.config
}); });
cli.getTxProposals({}, function(err, x) { cli.getTxProposals({}, function(err, txps) {
common.die(err); common.die(err);
if (program.verbose) if (program.verbose)
console.log('* Raw Server Response:\n', x); //TODO console.log('* Raw Server Response:\n', txps); //TODO
var txps = _.filter(x, function(x) { var txp = common.findOneTxProposal(txps, txpid);
return _.endsWith(common.shortID(x.id), txpid);
});
if (!txps.length) cli.rejectTxProposal(txp, reason, function(err, tx) {
common.die('Could not find TX Proposal:' + txpid);
if (txps.length > 1)
common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) {
return x.id;
}).join(' '));;
var txp = txps[0];
cli.rejectTxProposal(txp, function(err, x) {
common.die(err); common.die(err);
if (program.verbose) if (program.verbose)
console.log('* Raw Server Response:\n', x); //TODO console.log('* Raw Server Response:\n', tx); //TODO
console.log('Transaction rejected.'); console.log('Transaction rejected.');
}); });

38
bit-wallet/bit-rm Normal file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env node
var _ = require('lodash');
var program = require('commander');
var Client = require('../lib/client');
var common = require('./common');
program
.version('0.0.1')
.option('-c,--config [file]', 'Wallet config filename')
.option('-v,--verbose', 'be verbose')
.usage('[options] <txpid>')
.parse(process.argv);
var args = program.args;
if (!args[0])
program.help();
var txpid = args[0];
var cli = new Client({
filename: program.config
});
cli.getTxProposals({}, function(err, txps) {
common.die(err);
if (program.verbose)
console.log('* Raw Server Response:\n', txps); //TODO
var txp = common.findOneTxProposal(txps, txpid);
cli.removeTxProposal(txp, function(err) {
common.die(err);
console.log('Transaction removed.');
});
});

View File

@ -22,30 +22,19 @@ var cli = new ClientLib({
filename: program.config filename: program.config
}); });
cli.getTxProposals({}, function(err, x) { cli.getTxProposals({}, function(err, txps) {
common.die(err); common.die(err);
if (program.verbose) if (program.verbose)
console.log('* Raw Server Response:\n', x); //TODO console.log('* Raw Server Response:\n', txps); //TODO
var txps = _.filter(x, function(x) { var txp = common.findOneTxProposal(txps, txpid);
return _.endsWith(common.shortID(x.id), txpid);
});
if (!txps.length) cli.signTxProposal(txp, function(err, tx) {
common.die('Could not find TX Proposal:' + txpid);
if (txps.length > 1)
common.die('More than one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) {
return x.id;
}).join(' '));;
var txp = txps[0];
cli.signTxProposal(txp, function(err, x) {
common.die(err); common.die(err);
if (program.verbose) if (program.verbose)
console.log('* Raw Server Response:\n', x); //TODO console.log('* Raw Server Response:\n', tx); //TODO
console.log('Transaction signed.'); console.log('Transaction signed.');
}); });

View File

@ -1,3 +1,7 @@
'use strict';
var _ = require('lodash');
var common = function() {}; var common = function() {};
@ -9,14 +13,14 @@ var die = common.die = function(err) {
}; };
common.parseMN = function(MN) { common.parseMN = function(MN) {
if (!MN) if (!MN)
die('No m-n parameter'); die('No m-n parameter');
var mn = MN.split('-'); var mn = MN.split('-');
var m = parseInt(mn[0]); var m = parseInt(mn[0]);
var n = parseInt(mn[1]); var n = parseInt(mn[1]);
if (!m || ! n) { if (!m || !n) {
die('Bad m-n parameter'); die('Bad m-n parameter');
} }
@ -28,4 +32,20 @@ common.shortID = function(id) {
return id.substr(id.length - 4); return id.substr(id.length - 4);
}; };
common.findOneTxProposal = function(txps, id) {
var matches = _.filter(txps, function(tx) {
return _.endsWith(common.shortID(tx.id), id);
});
if (!matches.length)
common.die('Could not find TX Proposal:' + id);
if (matches.length > 1)
common.die('More than one TX Proposals match:' + id + ' : ' + _.map(matches, function(tx) {
return tx.id;
}).join(' '));;
return matches[0];
};
module.exports = common; module.exports = common;

30
cli.js
View File

@ -1,30 +0,0 @@
var _ = require('lodash');
var async = require('async');
var log = require('npmlog');
var fs = require('fs');
var CliLib = require('./lib/clilib');
try {
fs.unlinkSync('copay.dat');
} catch (e) {}
var cli = new CliLib({
filename: 'copay.dat'
});
cli.createWallet('my wallet', 'me', 1, 1, 'testnet', function(err, secret) {
if (err) {
console.log(err);
process.exit();
}
cli.status(function(err, status) {
if (err) {
console.log(err);
process.exit();
}
console.log(status);
})
});

View File

@ -84,7 +84,7 @@ API.prototype._loadAndCheck = function() {
return data; return data;
}; };
ClientLib.prototype._doRequest = function(method, url, args, data, cb) { API.prototype._doRequest = function(method, url, args, data, cb) {
var reqSignature = _signRequest(method, url, args, data.signingPrivKey); var reqSignature = _signRequest(method, url, args, data.signingPrivKey);
var absUrl = _getUrl(url); var absUrl = _getUrl(url);
request({ request({
@ -359,4 +359,13 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) {
this._doPostRequest(url, args, data, cb); this._doPostRequest(url, args, data, cb);
}; };
API.prototype.removeTxProposal = function(txp, cb) {
var self = this;
var data = this._loadAndCheck();
var url = '/v1/txproposals/' + txp.id;
this._doRequest('delete', url, {}, data, cb);
};
module.exports = API; module.exports = API;

View File

@ -547,19 +547,19 @@ CopayServer.prototype.removeWallet = function(opts, cb) {
* removePendingTx * removePendingTx
* *
* @param opts * @param opts
* @param {string} opts.id - The tx id. * @param {string} opts.txProposalId - The tx id.
* @return {undefined} * @return {undefined}
*/ */
CopayServer.prototype.removePendingTx = function(opts, cb) { CopayServer.prototype.removePendingTx = function(opts, cb) {
var self = this; var self = this;
if (!Utils.checkRequired(opts, ['id'])) if (!Utils.checkRequired(opts, ['txProposalId']))
return cb(new ClientError('Required argument missing')); return cb(new ClientError('Required argument missing'));
Utils.runLocked(self.walletId, cb, function(cb) { Utils.runLocked(self.walletId, cb, function(cb) {
self.getTx({ self.getTx({
id: opts.id id: opts.txProposalId,
}, function(err, txp) { }, function(err, txp) {
if (err) return cb(err); if (err) return cb(err);
@ -576,7 +576,7 @@ CopayServer.prototype.removePendingTx = function(opts, cb) {
return cb(new ClientError('Cannot remove a proposal signed/rejected by other copayers')); return cb(new ClientError('Cannot remove a proposal signed/rejected by other copayers'));
self._notify('transactionProposalRemoved'); self._notify('transactionProposalRemoved');
self.storage.removeTx(self.walletId, opts.id, cb); self.storage.removeTx(self.walletId, txp.id, cb);
}); });
}); });
}; };

View File

@ -1499,7 +1499,7 @@ describe('Copay server', function() {
it('should allow creator to remove an unsigned TX', function(done) { it('should allow creator to remove an unsigned TX', function(done) {
server.removePendingTx({ server.removePendingTx({
id: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
should.not.exist(err); should.not.exist(err);
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
@ -1516,7 +1516,7 @@ describe('Copay server', function() {
signatures: signatures, signatures: signatures,
}, function(err) { }, function(err) {
server.removePendingTx({ server.removePendingTx({
id: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
should.not.exist(err); should.not.exist(err);
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
@ -1530,7 +1530,7 @@ describe('Copay server', function() {
it('should not allow non-creator copayer to remove an unsigned TX ', function(done) { it('should not allow non-creator copayer to remove an unsigned TX ', function(done) {
helpers.getAuthServer(wallet.copayers[1].id, function(server2) { helpers.getAuthServer(wallet.copayers[1].id, function(server2) {
server2.removePendingTx({ server2.removePendingTx({
id: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
err.message.should.contain('creators'); err.message.should.contain('creators');
server2.getPendingTxs({}, function(err, txs) { server2.getPendingTxs({}, function(err, txs) {
@ -1550,7 +1550,7 @@ describe('Copay server', function() {
}, function(err) { }, function(err) {
should.not.exist(err); should.not.exist(err);
server.removePendingTx({ server.removePendingTx({
id: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
err.message.should.contain('other copayers'); err.message.should.contain('other copayers');
done(); done();