Merge pull request #20 from matiu/feat/broadcast

Feat/broadcast
This commit is contained in:
Ivan Socolsky 2015-02-16 11:11:58 -03:00
commit ec491430c9
10 changed files with 136 additions and 28 deletions

14
app.js
View File

@ -199,6 +199,19 @@ router.post('/v1/txproposals/:id/signatures/', function(req, res) {
req.body.txProposalId = req.params['id'];
server.signTx(req.body, function(err, txp) {
if (err) return returnError(err, res, req);
res.json(txp);
res.end();
});
});
});
// TODO Check HTTP verb and URL name
router.post('/v1/txproposals/:id/broadcast/', function(req, res) {
getServerWithAuth(req, res, function(server) {
req.body.txProposalId = req.params['id'];
server.broadcastTx(req.body, function(err, txp) {
if (err) return returnError(err, res, req);
res.json(txp);
res.end();
});
});
@ -209,6 +222,7 @@ router.post('/v1/txproposals/:id/rejections', function(req, res) {
req.body.txProposalId = req.params['id'];
server.rejectTx(req.body, function(err, txp) {
if (err) return returnError(err, res, req);
res.json(txp);
res.end();
});
});

View File

@ -13,6 +13,7 @@ program
.command('send <address> <amount> <note>', 'send bitcoins')
.command('sign <txpId>', 'sign a transaction proposal')
.command('reject <txpId> [reason]', 'reject a transaction proposal')
.command('broadcast <txpId>', 'broadcast a transaction proposal to the Bitcoin network')
.command('rm <txpId>', 'remove a transaction proposal')
.parse(process.argv);

31
bit-wallet/bit-broadcast Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env node
var _ = require('lodash');
var program = require('commander');
var Client = require('../lib/client');
var utils = require('./cli-utils');
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 client = utils.getClient(program);
client.getTxProposals({}, function(err, txps) {
utils.die(err);
var txp = utils.findOneTxProposal(txps, txpid);
client.broadcastTxProposal(txp, function(err, txid) {
utils.die(err);
console.log('Transaction Broadcasted: TXID: ' + x.txid);
});
});

View File

@ -1,13 +1,14 @@
#!/usr/bin/env node
var _ = require('lodash');
var program = require('commander');
var ClientLib = require('../lib/client');
var utils = require('./cli-utils');
var utils = require('./cli-utils');
program
.version('0.0.1')
.option('-c, --config [file]', 'Wallet config filename')
.option('-n, --network [networkname]', 'livenet|testnet', String, 'livenet')
.option('-t, --testnet', 'Create a Testnet Wallet', String)
.usage('[options] <walletName> <m-n> [copayerName]')
.parse(process.argv);
@ -17,14 +18,14 @@ if (!args[0])
var walletName = args[0];
var copayerName = args[2] || process.env.USER;
var network = program.network;
var network = program.testnet ? 'testnet' : 'livenet';
var mn = utils.parseMN(args[1]);
var client = utils.getClient(program);
client.createWallet(walletName, copayerName, mn[0], mn[1], network, function(err, secret) {
utils.die(err);
console.log(' * Wallet Created.');
console.log(' - Secret to share:\n\t' + secret);
console.log(' * ' + _.capitalize(network) + ' Wallet Created.');
if (secret)
console.log(' - Secret to share:\n\t' + secret);
});

View File

@ -13,9 +13,7 @@ program
.parse(process.argv);
var args = program.args;
if (!args[0])
program.help();
var txpid = args[0];
var txpid = args[0] || '';
var reason = args[1] || '';
var client = utils.getClient(program);
@ -25,6 +23,9 @@ client.getTxProposals({}, function(err, txps) {
var txp = utils.findOneTxProposal(txps, txpid);
client.rejectTxProposal(txp, reason, function(err, tx) {
utils.die(err);
console.log('Transaction rejected.');
if (x.status == 'rejected')
console.log('Transaction finally rejected.');
else
console.log('Transaction rejected by you.');
});
});

View File

@ -12,10 +12,7 @@ program
.parse(process.argv);
var args = program.args;
if (!args[0])
program.help();
var txpid = args[0];
var txpid = args[0] || '';
var client = utils.getClient(program);
client.getTxProposals({}, function(err, txps) {
@ -24,6 +21,9 @@ client.getTxProposals({}, function(err, txps) {
var txp = utils.findOneTxProposal(txps, txpid);
client.signTxProposal(txp, function(err, x) {
utils.die(err);
console.log('Transaction signed.');
if (x.status == 'broadcasted')
console.log('Transaction Broadcasted: TXID: ' + x.txid);
else
console.log('Transaction signed by you.');
});
});

View File

@ -2,16 +2,16 @@
var _ = require('lodash');
var Client = require('../lib/client');
var lib = function() {};
var Utils = function() {};
var die = lib.die = function(err) {
var die = Utils.die = function(err) {
if (err) {
console.error(err);
process.exit(1);
}
};
lib.parseMN = function(MN) {
Utils.parseMN = function(MN) {
if (!MN)
die('No m-n parameter');
var mn = MN.split('-');
@ -27,11 +27,11 @@ lib.parseMN = function(MN) {
};
lib.shortID = function(id) {
Utils.shortID = function(id) {
return id.substr(id.length - 4);
};
lib.getClient = function(args) {
Utils.getClient = function(args) {
var storage = new Client.FileStorage({
filename: args.config
});
@ -41,16 +41,16 @@ lib.getClient = function(args) {
});
}
lib.findOneTxProposal = function(txps, id) {
Utils.findOneTxProposal = function(txps, id) {
var matches = _.filter(txps, function(tx) {
return _.endsWith(lib.shortID(tx.id), id);
return _.endsWith(Utils.shortID(tx.id), id);
});
if (!matches.length)
lib.die('Could not find TX Proposal:' + id);
Utils.die('Could not find TX Proposal:' + id);
if (matches.length > 1)
lib.die('More than one TX Proposals match:' + id + ' : ' + _.map(matches, function(tx) {
Utils.die('More than one TX Proposals match:' + id + ' : ' + _.map(matches, function(tx) {
return tx.id;
}).join(' '));;
@ -59,4 +59,4 @@ lib.findOneTxProposal = function(txps, id) {
module.exports = lib;
module.exports = Utils;

View File

@ -148,13 +148,16 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb
var walletId = body.walletId;
var secret = walletId + ':' + privKey.toString() + ':' + (network == 'testnet' ? 'T' : 'L');
data.secret = secret;
var ret;
if (n > 1)
ret = data.secret = secret;
self.storage.save(data);
self._joinWallet(data, secret, copayerName, function(err) {
if (err) return cb(err);
return cb(null, data.secret);
return cb(null, ret);
});
});
};
@ -357,6 +360,16 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) {
this._doPostRequest(url, args, data, cb);
};
API.prototype.broadcastTxProposal = function(txp, cb) {
var self = this;
var data = this._loadAndCheck();
var url = '/v1/txproposals/' + txp.id + '/broadcast/';
this._doPostRequest(url, {}, data, cb);
};
API.prototype.removeTxProposal = function(txp, cb) {
var self = this;
var data = this._loadAndCheck();

View File

@ -105,7 +105,7 @@ TxProposal.prototype._getBitcoreTx = function() {
};
TxProposal.prototype.getNetworkName = function() {
return Bitcore.Address(this.toAddress).toObject().networkName;
return Bitcore.Address(this.toAddress).toObject().network;
};
TxProposal.prototype.getRawTx = function() {

View File

@ -317,6 +317,7 @@ CopayServer.prototype._getBlockExplorer = function(provider, network) {
url = 'https://test-insight.bitpay.com:443'
break;
}
console.log('[server.js.320:url:]',url); //TODO
return new Explorers.Insight(url, network);
break;
}
@ -649,6 +650,7 @@ CopayServer.prototype.signTx = function(opts, cb) {
txid: txid
});
console.log('[server.js.653:txp:]',txp); //TODO
return cb(null, txp);
});
});
@ -660,6 +662,51 @@ CopayServer.prototype.signTx = function(opts, cb) {
});
};
/**
* Broadcast a transaction proposal.
* @param {Object} opts
* @param {string} opts.txProposalId - The identifier of the transaction.
*/
CopayServer.prototype.broadcastTx = function(opts, cb) {
var self = this;
if (!Utils.checkRequired(opts, ['txProposalId']))
return cb(new ClientError('Required argument missing'));
self.getWallet({}, function(err, wallet) {
if (err) return cb(err);
self.getTx({
id: opts.txProposalId
}, function(err, txp) {
if (err) return cb(err);
if (txp.status == 'broadcasted')
return cb(new ClientError('TXALREADYBROADCASTED', 'The transaction proposal is already broadcasted'));
if (txp.status != 'accepted')
return cb(new ClientError('TXNOTACCEPTED', 'The transaction proposal is not accepted'));
self._broadcastTx(txp, function(err, txid) {
if (err) return cb(err);
txp.setBroadcasted(txid);
self.storage.storeTx(self.walletId, txp, function(err) {
if (err) return cb(err);
self._notify('NewOutgoingTx', {
txProposalId: opts.txProposalId,
txid: txid
});
return cb(null, txid);
});
});
});
});
};
/**
* Reject a transaction proposal.
* @param {Object} opts