-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Add Batch JSON-RPC support (rpc client & server) #1503
Conversation
allow non local tls disable for compatibility with private network in…
This reverts commit c25e1e8.
I think we need some sort of bulk handler we can tack other methods on too here. |
@jakesyl Do you want review on this now, or should I hold off until it's less of a WIP? |
@torkelrogstad, let's hold off for now. I'll have this done by EoD. Feel free to check it out in the meantime. I think I know how I want to solve the bulk querying in post mode now. |
Actually @torkelrogstad, I'd love to get your input on the best way to queue these bulk requests. Here's how it's done in python: I'm playing with how to do it in btcd |
I'm thinking of adding a batch method onto client that returns a modified client. Here's the aforementioned implementation |
@torkelrogstad I'm sure we need some work here, but this is what I've got so far. Please review and let me know what you think |
I've started looking it over, great stuff! Review is still pending, I'll wait until I've finished the entire PR before publishing. Hopefully I'll find some time later today. |
6cf1fa2
to
6278ae4
Compare
Hey, any idea if any changes are required here? |
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.
Sorry for delaying this so much! But here's some review for you.
Tested this against bitcoind 0.19
on my machine, worked great. 🎉
request.ID = data["id"] | ||
methodValue, hasMethod := data["method"] | ||
if hasMethod { | ||
request.Method = methodValue.(string) |
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.
The cast here and on line 93 seems a bit dangerous to me, would blow up if the fields are accessed later and it turns out we have the wrong type.
What's your thoughts on this?
metod, ok := methodValue.(string)
if ok {
request.Method = method
}
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.
Interesting point. I don't see an alternative though
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.
@torkelrogstad I've gone ahead and addressed this on #1583
btcjson/jsonrpc.go
Outdated
paramsValue, hasParams := data["params"] | ||
if !hasParams { | ||
// set the request param to an empty array if it is ommited in the request | ||
request.Params = []json.RawMessage{} | ||
} | ||
if hasParams { | ||
// assert the request params is an array of data | ||
params, paramsOk := paramsValue.([]interface{}) | ||
if paramsOk { | ||
rawParams := make([]json.RawMessage, 0, len(params)) | ||
for _, param := range params { | ||
marshalledParam, err := json.Marshal(param) | ||
if err != nil { | ||
return err | ||
} | ||
rawMessage := json.RawMessage(marshalledParam) | ||
rawParams = append(rawParams, rawMessage) | ||
} | ||
|
||
request.Params = rawParams | ||
} | ||
} |
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.
Can avoid some nesting this way:
paramsValue, hasParams := data["params"]
if !hasParams {
// set the request param to an empty array if it is ommited in the request
request.Params = []json.RawMessage{}
// assert the request params is an array of data
} else if params, paramsOk := paramsValue.([]interface{}); paramsOk {
rawParams := make([]json.RawMessage, 0, len(params))
for _, param := range params {
marshalledParam, err := json.Marshal(param)
if err != nil {
return err
}
rawMessage := json.RawMessage(marshalledParam)
rawParams = append(rawParams, rawMessage)
}
request.Params = rawParams
} else {
// error here, saying we got the wrong type of data?
}
// request. | ||
func NewRequest(rpcVersion string, id interface{}, method string, params []interface{}) (*Request, error) { | ||
// default to JSON-RPC 1.0 if RPC type is not specified | ||
if rpcVersion != "2.0" && rpcVersion != "1.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.
This strikes me as a bit dangerous. Two potential solutions, could (should, perhaps) do both IMO:
- Introduce a type for it
type rpcVersion string
var (
rpcVersion1 rpcVersion = rpcVersion("1.0")
rpcVersion2 rpcVersion = rpcVersion("2.0")
)
- I think it's better to error out here, instead of silently changing behavior.
// Typically callers will instead want to create the fully marshalled JSON-RPC | ||
// response to send over the wire with the MarshalResponse function. | ||
func NewResponse(id interface{}, marshalledResult []byte, rpcErr *RPCError) (*Response, error) { | ||
func NewResponse(rpcVersion string, id interface{}, marshalledResult []byte, rpcErr *RPCError) (*Response, error) { | ||
if rpcVersion != "2.0" && rpcVersion != "1.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.
Same comment about RPC versions from above apply here
// a JSON-RPC response byte slice that is suitable for transmission to a | ||
// JSON-RPC client. | ||
func MarshalResponse(rpcVersion string, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) { | ||
if rpcVersion != "2.0" && rpcVersion != "1.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.
RPC version comment from above
if len(batchedRequests) == 0 { | ||
jsonErr := &btcjson.RPCError{ | ||
Code: btcjson.ErrRPCInvalidRequest.Code, | ||
Message: fmt.Sprint("Invalid request: empty batch"), |
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.
can use string literal directly, no need for fmt.Sprint
rpcwebsocket.go
Outdated
if req.Method == "" || req.Params == nil { | ||
jsonErr := &btcjson.RPCError{ | ||
Code: btcjson.ErrRPCInvalidRequest.Code, | ||
Message: fmt.Sprintf("Invalid request: malformed"), |
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.
can use string literal directly
|
||
jsonErr := &btcjson.RPCError{ | ||
Code: btcjson.ErrRPCInvalidRequest.Code, | ||
Message: fmt.Sprint("Invalid request: empty batch"), |
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.
can use string literal directly
rpcwebsocket.go
Outdated
if req.Method == "" || req.Params == nil { | ||
jsonErr := &btcjson.RPCError{ | ||
Code: btcjson.ErrRPCInvalidRequest.Code, | ||
Message: fmt.Sprintf("Invalid request: malformed"), |
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.
can use string literal directly
// the best block in the longest block chain. | ||
func (r FutureGetBulkResult) Receive() (BulkResult, error) { | ||
m := make(BulkResult) | ||
res, err := receiveFuture(r) |
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.
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
Thanks @pavel-main, looks like that fixed it! See #1537 |
$GOPATH caching has led to flaky tests as per btcsuite#1503 and btcsuite#1536. The speedup is marginal and while the false negatives are a headache, false positives are potentially dangerous.
Any update here? Looks like prereq #1537 has been fixed |
|
$GOPATH caching has led to flaky tests as per btcsuite#1503 and btcsuite#1536. The speedup is marginal and while the false negatives are a headache, false positives are potentially dangerous.
Going to need to squash |
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.
Generally looking good but along with my question (which I think leads to a lot of unnecessary changes and the questions by @torkelrogstad which need to be resolved, this badly needs to be rebased and squashed. I can do another review after that (and after we resolve those outstanding things) so the set of changes is clearer. I definitely want this to make it in though.
@@ -193,7 +193,7 @@ func TestBtcdExtCmds(t *testing.T) { | |||
for i, test := range tests { | |||
// Marshal the command as created by the new static command | |||
// creation function. | |||
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd()) | |||
marshalled, err := btcjson.MarshalCmd("1.0", testID, test.staticCmd()) |
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.
Why are you changing from a variable to a hardcoded number here (and all the places below?
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.
fair point, I'll have to refactor. I've held off on squashing till these revisions are complete, but can do this earlier fi it helps your review
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.
Appreciate the feedback
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.
Generally I agree about waiting to squash until revisions are done but this needs the rebase before reviewing it for real so you might as well squash at the same time (I hate making people do extra steps if I don't have to).
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.
No problem
@jcvernaleo I merged this by accident, went ahead and reverted instantly. |
can I force push to undo? |
@jcvernaleo merged the wrong branch here - I thought this was on my local. I undid immediately after (#1549), but can't push the history here because the branch is protected :(, please advise |
|
@jakesyl Are you still actively working on this? |
Hi @onyb yes - I've been very busy the past month but have a few PRs queued here including this one that I need to work on. I'm still active in the btcd irc |
Recreated in #1583 |
This pr aims to address #329 which has been open for a while now by adding bulk request support. This is base on from decred#841 by @davecgh