-
Notifications
You must be signed in to change notification settings - Fork 315
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
Adding queue to prevent 'Bitcoin JSON-RPC: Work queue depth exceeded' errors #23
Conversation
I have also fixed the tests (for some reason, they didn't go through; maybe other node version). I am not sure what will Travis do with it. ....and he will fail. I will edit the tests so they go through both on my PC and on Travis then. |
New node in travis fixed the tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall a correct implementation of the feature. I personally would love the difff to be smaller / the changes to be more lightweight.
There are also some bigger issues as changing the node version which is a no go from my perspective. Needs to be addresses or at least discussed.
.travis.yml
Outdated
@@ -1,6 +1,6 @@ | |||
language: node_js | |||
node_js: | |||
- '0.10' | |||
- '7' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be avoided. Changing the node versionin travis is a pretty major change. Why should this be necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I run the tests on my PC, they failed (because node changed the error message on JSON parsing slightly), so I corrected the tests, but then they failed on travis. So I corrected Travis.
I don't think it's a major change, but I don't really care, it's just about different error in the tests. If this is a blocker, I can remove the two commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will remove the test changes (this and the JSON line), I agree that it doesn't belong in this PR
lib/index.js
Outdated
@@ -3,6 +3,8 @@ | |||
var http = require('http'); | |||
var https = require('https'); | |||
|
|||
var async = require('async'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 5 is empty. Should not be the case. I would remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah good idea
lib/index.js
Outdated
@@ -22,6 +24,10 @@ function RpcClient(opts) { | |||
this.log = RpcClient.loggers[RpcClient.config.logger || 'normal']; | |||
} | |||
|
|||
var queueSize = opts.queue || 16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constant values (like 16
) should be set at the top or in a config file like
var DEFAULT_CONCURRENCY=16
and then
var queueSize = opts.queue || DEFAULT_CONCURRENCY
Would be really annoying to go looking for that value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true. But it's not there for the other values also (user/pass), I didn't want to refactor too much... but yeah I can change that
lib/index.js
Outdated
@@ -38,90 +44,100 @@ RpcClient.config = { | |||
logger: 'normal' // none, normal, debug | |||
}; | |||
|
|||
function rpc(request, callback) { | |||
function rpc(request, originalCallback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no reason to change this parameter name. Should not be done in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I can either change callback
to originalCallback
and then callback
stays in the rest of the code (since I need to call both the original callback and the "task" callback).
Or I can leave callback
, like you suggest, and then I will need to make newCallback
and call newCallback
everywhere instead of callback
.
lib/index.js
Outdated
for (var k in self.httpOptions) { | ||
options[k] = self.httpOptions[k]; | ||
var task = function(taskCallback) { | ||
var callback = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about error handling? Can this still be done properly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's done exactly as in the original code
lib/index.js
Outdated
|
||
var called = false; | ||
var called = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all whitespace changes from the PR. This just bloats the diff and is very annoying when reviewing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not unnecessary whitespace change. The code is in a new function that wasn't there before.
I can make two commits, one without the whitespace change and one that just shifts the lines, but is that really necessary.
"chai": "^1.10.0", | ||
"coveralls": "^2.11.2", | ||
"istanbul": "^0.3.5", | ||
"mocha": "^2.1.0", | ||
"sinon": "^1.12.2" | ||
}, | ||
"dependencies": { | ||
"async": "^1.3.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest use fixed deps or yarn. This right here will lead to undeterministic builds and heavy pain in the future. Async is a well maintained library, that is for sure but still they can f**k up a release. Better be safe than sorry.
So for the time being I would make the line so:
"async":"1.3.0"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bitcore-node uses exactly this dependency, "async": "^1.3.0"
. Given that this is used only in bitcore-node, it doesn't matter really
Thanks for the feedback. I agree with some, I will do some little changes I can remove the changes in tests/travis if that's a stopper for merging, I don't really care (it was really only in order for my PC to run the tests, since I have a new node version; but I can change it back). Anyway bitpay doesn't seem to reply on pull requests or merge them, so I don't know if it matters :) |
OK, I made the patch significantly smaller by making it a new function instead of wrapping it in a function-inside-function. I kept the async version in package.json, since the |
@Runn1ng I was just reviewing as a bistander. I actually am not a maintainer of this codebase and cannot block or merge anything. |
Yeah I know. Collabolators got a little badge on github :) |
Why no one is merging it? |
... years later |
Oh sorry, I probably pushed the smart fee commit to my branch to my repo by mistake. Thanks for noticing, I will force-push again |
I'm not sure this is the right approach to dealing with this issue ... since bitcoind-rpc is used client side, and there can be many concurrent users of a given bitcoind node, the work queue could still be exceeded even with this logic in place. Isn't it better to handle such errors gracefully than to burden this library with logic that would only prevent the issue if a single process was exceeding the bitcoind work queue? Also, a wrapper of some sort that exists outside this repo could accomplish the same thing if it's really desired. |
@gasteve I haven't looked into the specifics of the implementation in this PR, but it's common for a client library to provide a mechanism for limiting the number of concurrent requests. For example, https://github.com/brianc/node-postgres uses connection "pooling". It's true that for this to be effective there needs to be some level of coordination between clients and server (at least in terms of configuration) so that each client sets its concurrency appropriately. For example, if the server allows 16 concurrent tasks and there are four clients, then perhaps to be safe each client would self-limit to four concurrent tasks. |
@gasteve Valid point. But this is about fixing a dos vulnerabilty asap. As long as you have no PR that implements your suggested improvements, I would say: Done is better than perfect. |
But anyhow, this will not get merged because no maintainer gives a damn... |
Thinking a bit more about it, I see another issue: This is actually not fixing the dos vulnerability at all. An attacker can still flood the api with carefully designed requests so that the queue will fill up and no other user will be able successfully submit a single request (it will get queued at position 1 mio or so and only be resolved after 5 hours). In order to protect the insight-api against dos we need to queue "per user" on a much higher level. Also it should be fine to get a "bitcoin rcp work queue depth exceeded" if it is handled gracefully further up in the stack instead of just being sent out straight to the user. One could retry or something. So all in all I agree with the point that this here is the wrong place to try to fix the issue. Also the proposed changes are NOT fixing the issue at hand, which is: Anyone can take down an insight-api deployment with no cost. |
I'm trying to index (freshly) the data and I get this error. I didn't receive a single the API request(i.e. no chance I got DDOS-ed) Does this PR fixes freshly indexes as well? |
@levino yes this does not really solve the DDoS vulnerability. However it stops "accidental" overflow of the RPC queue. |
Can someone close this? Thanks. |
I have added a queue, fixing recurring "Bitcoin JSON-RPC: Work queue depth exceeded" errors.
The queue size can be set from calling code by options (I will add it to bitcore-node next); by default, 16 is used, since that's the default bitcoind queue size.
Fixes issues:
and maybe others
I am using the same async version as bitcore-node, so it's not installed twice with different versions :)