Skip to content

bitcoind: fix timing issue with tryAll #453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions lib/services/bitcoind.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,15 @@ Bitcoin.prototype._resetCaches = function() {
this.blockOverviewCache.reset();
};

Bitcoin.prototype._tryAll = function(func, callback) {
async.retry({times: this.nodes.length, interval: this.tryAllInterval || 1000}, func, callback);
Bitcoin.prototype._tryAllClients = function(func, callback) {
var self = this;
var nodesIndex = this.nodesIndex;
var retry = function(done) {
var client = self.nodes[nodesIndex].client;
nodesIndex = (nodesIndex + 1) % self.nodes.length;
func(client, done);
};
async.retry({times: this.nodes.length, interval: this.tryAllInterval || 1000}, retry, callback);
};

Bitcoin.prototype._wrapRPCError = function(errObj) {
Expand Down Expand Up @@ -1537,8 +1544,8 @@ Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) {
Bitcoin.prototype._maybeGetBlockHash = function(blockArg, callback) {
var self = this;
if (_.isNumber(blockArg) || (blockArg.length < 40 && /^[0-9]+$/.test(blockArg))) {
self._tryAll(function(done) {
self.client.getBlockHash(blockArg, function(err, response) {
self._tryAllClients(function(client, done) {
client.getBlockHash(blockArg, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand All @@ -1563,7 +1570,7 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) {
if (err) {
return callback(err);
}
self._tryAll(function(done) {
self._tryAllClients(function(client, done) {
self.client.getBlock(blockhash, false, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
Expand Down Expand Up @@ -1603,8 +1610,8 @@ Bitcoin.prototype.getBlockOverview = function(blockArg, callback) {
callback(null, cachedBlock);
});
} else {
self._tryAll(function(done) {
self.client.getBlock(blockhash, true, function(err, response) {
self._tryAllClients(function(client, done) {
client.getBlock(blockhash, true, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand Down Expand Up @@ -1654,8 +1661,8 @@ Bitcoin.prototype.getBlock = function(blockArg, callback) {
callback(null, cachedBlock);
});
} else {
self._tryAll(function(done) {
self.client.getBlock(blockhash, false, function(err, response) {
self._tryAllClients(function(client, done) {
client.getBlock(blockhash, false, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand Down Expand Up @@ -1713,8 +1720,8 @@ Bitcoin.prototype.getBlockHeader = function(blockArg, callback) {
if (err) {
return callback(err);
}
self._tryAll(function(done) {
self.client.getBlockHeader(blockhash, function(err, response) {
self._tryAllClients(function(client, done) {
client.getBlockHeader(blockhash, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand Down Expand Up @@ -1795,8 +1802,8 @@ Bitcoin.prototype.getRawTransaction = function(txid, callback) {
callback(null, tx);
});
} else {
self._tryAll(function(done) {
self.client.getRawTransaction(txid, function(err, response) {
self._tryAllClients(function(client, done) {
client.getRawTransaction(txid, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand All @@ -1822,8 +1829,8 @@ Bitcoin.prototype.getTransaction = function(txid, callback) {
callback(null, tx);
});
} else {
self._tryAll(function(done) {
self.client.getRawTransaction(txid, function(err, response) {
self._tryAllClients(function(client, done) {
client.getRawTransaction(txid, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand Down Expand Up @@ -1937,8 +1944,8 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) {
callback(null, tx);
});
} else {
self._tryAll(function(done) {
self.client.getRawTransaction(txid, 1, function(err, response) {
self._tryAllClients(function(client, done) {
client.getRawTransaction(txid, 1, function(err, response) {
if (err) {
return done(self._wrapRPCError(err));
}
Expand Down
104 changes: 75 additions & 29 deletions test/services/bitcoind.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,46 +525,92 @@ describe('Bitcoin Service', function() {
});
});

describe('#_tryAll', function() {
it('will retry the number of bitcoind nodes', function(done) {
describe('#_tryAllClients', function() {
it('will retry for each node client', function(done) {
var bitcoind = new BitcoinService(baseConfig);
bitcoind.tryAllInterval = 1;
bitcoind.nodes.push({});
bitcoind.nodes.push({});
bitcoind.nodes.push({});
var count = 0;
var func = function(callback) {
count++;
if (count <= 2) {
callback(new Error('test'));
} else {
callback();
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('test'))
}
};
bitcoind._tryAll(function(next) {
func(next);
}, function() {
count.should.equal(3);
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('test'))
}
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArg(0)
}
});
bitcoind._tryAllClients(function(client, next) {
client.getInfo(next);
}, function(err) {
if (err) {
return done(err);
}
bitcoind.nodes[0].client.getInfo.callCount.should.equal(1);
bitcoind.nodes[1].client.getInfo.callCount.should.equal(1);
bitcoind.nodes[2].client.getInfo.callCount.should.equal(1);
done();
});
});
it('will get error if all fail', function(done) {
it('will start using the current node index (round-robin)', function(done) {
var bitcoind = new BitcoinService(baseConfig);
bitcoind.tryAllInterval = 1;
bitcoind.nodes.push({});
bitcoind.nodes.push({});
bitcoind.nodes.push({});
var count = 0;
var func = function(callback) {
count++;
callback(new Error('test'));
};
bitcoind._tryAll(function(next) {
func(next);
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('2'))
}
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('3'))
}
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('1'))
}
});
bitcoind.nodesIndex = 2;
bitcoind._tryAllClients(function(client, next) {
client.getInfo(next);
}, function(err) {
err.should.be.instanceOf(Error);
err.message.should.equal('3');
bitcoind.nodes[0].client.getInfo.callCount.should.equal(1);
bitcoind.nodes[1].client.getInfo.callCount.should.equal(1);
bitcoind.nodes[2].client.getInfo.callCount.should.equal(1);
bitcoind.nodesIndex.should.equal(2);
done();
});
});
it('will get error if all clients fail', function(done) {
var bitcoind = new BitcoinService(baseConfig);
bitcoind.tryAllInterval = 1;
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('test'))
}
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('test'))
}
});
bitcoind.nodes.push({
client: {
getInfo: sinon.stub().callsArgWith(0, new Error('test'))
}
});
bitcoind._tryAllClients(function(client, next) {
client.getInfo(next);
}, function(err) {
should.exist(err);
err.should.be.instanceOf(Error);
err.message.should.equal('test');
count.should.equal(3);
done();
});
});
Expand Down