Skip to content

Handling integer IDs in JSON-RPC requests -- fixes #2366#2811

Merged
ebuchman merged 6 commits intotendermint:developfrom
tomtau:fix/rpc-integer-id
Nov 26, 2018
Merged

Handling integer IDs in JSON-RPC requests -- fixes #2366#2811
ebuchman merged 6 commits intotendermint:developfrom
tomtau:fix/rpc-integer-id

Conversation

@tomtau
Copy link
Contributor

@tomtau tomtau commented Nov 12, 2018

Addresses #2366

  • [n/a] Updated all relevant documentation in docs
  • Updated all code comments where relevant
  • Wrote tests
  • Updated CHANGELOG_PENDING.md

Hi everyone, we're using one JSON-RPC client library that only does integer IDs (incrementally), so rather than having a workaround for that, I guess it'd be better to fix this issue in Tendermint.
This is the first Go code I ever wrote, so apologies if it's too bad.
I decided to use this "interface wrapper with a single method" workaround for the lack of sum types in Go, as it seems to be an OK tradeoff between type safety (e.g. "empty interface" wrapper would work as well here, but passing in booleans / objects / arrays as IDs wouldn't result in an error) and boilerplate.

@codecov-io
Copy link

codecov-io commented Nov 12, 2018

Codecov Report

Merging #2811 into develop will decrease coverage by 0.23%.
The diff coverage is 45.31%.

@@             Coverage Diff             @@
##           develop    #2811      +/-   ##
===========================================
- Coverage     62.4%   62.16%   -0.24%     
===========================================
  Files          212      212              
  Lines        17254    17352      +98     
===========================================
+ Hits         10767    10787      +20     
- Misses        5583     5657      +74     
- Partials       904      908       +4
Impacted Files Coverage Δ
rpc/core/events.go 0% <0%> (ø) ⬆️
tools/tm-bench/transacter.go 8.49% <0%> (ø) ⬆️
rpc/lib/types/types.go 37.39% <46.77%> (+8.23%) ⬆️
privval/ipc_server.go 64.81% <0%> (-5.56%) ⬇️
lite/base_verifier.go 76% <0%> (-2.95%) ⬇️
privval/tcp_server.go 78.57% <0%> (-2.86%) ⬇️
p2p/pex/pex_reactor.go 71.51% <0%> (-0.95%) ⬇️
p2p/pex/addrbook.go 68.91% <0%> (-0.49%) ⬇️
consensus/reactor.go 66.62% <0%> (-0.12%) ⬇️
libs/db/remotedb/grpcdb/server.go 0% <0%> (ø) ⬆️
... and 1 more

Copy link
Contributor

@ebuchman ebuchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this on, and welcome to Tendermint dev!

A few minor points to address, but otherwise looks good :)

func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest {
// UnmarshalJSON custom JSON unmarshalling due to jsonrpcid being string or int
func (request *RPCRequest) UnmarshalJSON(data []byte) error {
type AliasStr RPCRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Unmarshal interface{} and then use switch for different possible types

switch ID.(type) {
  case string:
           XXX
  case int:
           YYY
  default:
    return fmt.Errorf("Unknown ID type. Got %T, expected string or int", ID)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! also you can do without intermediate struct

unsafeResp := &struct {
            JSONRPC string          `json:"jsonrpc"`
            ID      interface{}     `json:"id"`
            Method  string          `json:"method"`
            Params  json.RawMessage `json:"params"` // must be map[string]interface{} or []interface{}
        }{}

you just use the original one

Copy link
Contributor Author

@tomtau tomtau Nov 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@melekes @ebuchman I've changed it here: f2a71d7#diff-f595cd0be03b00ec17ec43d65afb7780

I'm not that experienced with Go, so not sure how to do it without the intermediate struct -- or by using the original, did you mean that jsonrpcid should be an empty interface and it should get rid of the extra ID type wrappers (JSONRPCStringID/JSONRPCIntID)?

Tomas Tauber added 3 commits November 19, 2018 11:45
…ndermint#2366)

* added a wrapper interface `jsonrpcid` that represents both string and int IDs in JSON-RPC requests/responses + custom JSON unmarshallers

* changed client-side code in RPC that uses it

* added extra tests for integer IDs
* added table driven tests for request type marshalling/unmarshalling
* expanded handler test to check IDs
* changed pending changelog note
@tomtau tomtau force-pushed the fix/rpc-integer-id branch from 71fe74d to 73bd3c6 Compare November 19, 2018 04:00
@ebuchman
Copy link
Contributor

Pushed a commit to do some minor cleanup, hope you don't mind. PTAL! Otherwise LGTM

@ebuchman ebuchman merged commit b12488b into tendermint:develop Nov 26, 2018
danil-lashin pushed a commit to danil-lashin/tendermint that referenced this pull request Nov 27, 2018
* develop:
  types: Emit tags from BeginBlock/EndBlock (tendermint#2747)
  Fix fast sync stack with wrong block tendermint#2457 (tendermint#2731)
  It's better read from genDoc than from state.validators when appHeight==0 in replay (tendermint#2893)
  update encoding spec (tendermint#2903)
  return back initially allowed level if we encounter allowed key (tendermint#2889)
  Handling integer IDs in JSON-RPC requests -- fixes tendermint#2366 (tendermint#2811)

# Conflicts:
#	blockchain/reactor_test.go
#	blockchain/store_test.go
#	node/node_test.go
#	types/events.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants