simultaneous tx creation

This commit is contained in:
Ivan Socolsky 2015-02-08 18:29:58 -03:00
parent e665db210b
commit 53fa9fcace
2 changed files with 78 additions and 43 deletions

View File

@ -408,41 +408,50 @@ CopayServer.prototype.createTx = function(opts, cb) {
// Check some parameters like:
// amount > dust
self.getWallet({}, function(err, wallet) {
if (err) return cb(err);
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
self._getUtxos(function(err, utxos) {
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'));
var changeAddress = wallet.createAddress(true).address;
utxos = _.reject(utxos, {
locked: true
});
var txp = new TxProposal({
creatorId: self.copayerId,
toAddress: opts.toAddress,
amount: opts.amount,
changeAddress: changeAddress,
requiredSignatures: wallet.m,
maxRejections: wallet.n - wallet.m,
});
txp.inputs = self._selectUtxos(txp, utxos);
if (!txp.inputs) {
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds'));
}
txp.inputPaths = _.pluck(txp.inputs, 'path');
// no need to do this now: // TODO remove this comment
//self._createRawTx(txp);
self.storage.storeTx(wallet.id, txp, function(err) {
self._getUtxos(function(err, utxos) {
if (err) return cb(err);
return cb(null, txp);
var changeAddress = wallet.createAddress(true);
utxos = _.reject(utxos, {
locked: true
});
var txp = new TxProposal({
creatorId: self.copayerId,
toAddress: opts.toAddress,
amount: opts.amount,
message: opts.message,
changeAddress: changeAddress.address,
requiredSignatures: wallet.m,
maxRejections: wallet.n - wallet.m,
});
txp.inputs = self._selectUtxos(txp, utxos);
if (!txp.inputs) {
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds'));
}
txp.inputPaths = _.pluck(txp.inputs, 'path');
self.storage.storeWallet(wallet, function(err) {
if (err) return cb(err);
self.storage.storeAddress(wallet.id, changeAddress, function(err) {
if (err) return cb(err);
self.storage.storeTx(wallet.id, txp, function(err) {
if (err) return cb(err);
return cb(null, txp);
});
})
});
});
});
});

View File

@ -652,14 +652,12 @@ describe('Copay server', function() {
});
it('should create a tx', function(done) {
helpers.createUtxos(server, wallet, helpers.toSatoshi([100, 200]), function(utxos) {
helpers.stubBlockExplorer(server, utxos);
var txOpts = {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(80),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
@ -705,7 +703,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(80),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, tx) {
@ -728,7 +725,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(120),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
@ -760,7 +756,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(12),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, tx) {
@ -771,7 +766,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: 8,
message: 'some message 2',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts2, function(err, tx) {
@ -799,7 +793,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(12),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, tx) {
@ -810,7 +803,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(24),
message: 'some message 2',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts2, function(err, tx) {
@ -831,6 +823,43 @@ describe('Copay server', function() {
});
});
});
it('should create tx using different UTXOs for simultaneous requests', function(done) {
var ntxs = 3;
helpers.createUtxos(server, wallet, helpers.toSatoshi(_.times(3, function() {
return 100;
})), function(utxos) {
helpers.stubBlockExplorer(server, utxos);
server.getBalance({}, function(err, balance) {
should.not.exist(err);
balance.totalAmount.should.equal(helpers.toSatoshi(ntxs * 100));
balance.lockedAmount.should.equal(helpers.toSatoshi(0));
var txOpts = {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(80),
requestSignature: 'dummy',
};
async.map(_.range(ntxs), function(i, cb) {
server.createTx(txOpts, function(err, tx) {
cb(err, tx);
});
}, function(err) {
server.getPendingTxs({}, function(err, txs) {
should.not.exist(err);
txs.length.should.equal(ntxs);
_.uniq(_.pluck(txs, 'changeAddress')).length.should.equal(ntxs);
server.getBalance({}, function(err, balance) {
should.not.exist(err);
balance.totalAmount.should.equal(helpers.toSatoshi(ntxs * 100));
balance.lockedAmount.should.equal(balance.totalAmount);
done();
});
});
});
});
});
});
});
describe('#signTx', function() {
@ -849,7 +878,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(10),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, tx) {
@ -937,7 +965,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(10),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, txp) {
@ -969,7 +996,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(10),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, txp) {
@ -1024,7 +1050,6 @@ describe('Copay server', function() {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(10),
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function(err, txp) {
@ -1035,6 +1060,7 @@ describe('Copay server', function() {
should.not.exist(err);
txps.length.should.equal(1);
txps[0].id.should.equal(txp.id);
txps[0].message.should.equal('some message');
done();
});
});