Skip to content
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

Enable gRPC server reflection and CORS on HTTP service #2698

Merged
merged 5 commits into from Sep 2, 2019

Conversation

tgrospic
Copy link
Collaborator

Overview

This PR has three parts:

  1. adds gRPC reflection for client to inspects API
  2. adds additional proto type to describe response types
  3. enables CORS on HTTP endpoints.

JIRA ticket:

https://rchain.atlassian.net/browse/RCHAIN-3804

Notes

gRPC service reflection

Setup of reflection is based on grpc-java documentation gRPC Server Reflection Tutorial

With reflection service enabled client libraries with gRPC bindings can inspect Casper API without the need for source protobuf files. We can also use generic tools like grpcui, grpc-ui, grpcox or grpcurl to inspect schema and execute requests.

Static types for service responses inside Either

With reflection enabled it's still a problem to get information about type which Either holds for success value. Dynamically type-url resolves the type but in proto files this info is only in comments so to provide TypeScript definitions I have to parse proto files directly rnode-grpc-js.
For reflection there is no workaround so I've added a new type DeployEitherMeta wich just holds dynamic value for each deploy method. The requirement is of course that names of the fields correspond exactly to name of the service methods. Unit responses are skipped like in comments.

CORS enabled on HTTP endpoints

Currently it's not possible to make HTTP requests to RNode from the browser e.g. fetch('http://node0.testnet.rchain-dev.tk:40403/status'). RNode does not specify headers to allow browsers to accept responses from different domain than self. With CORS enabled RNode can be called from page on any domain.

Examples

# Example of curl-like inspect request (reflection API)
$ grpcurl -plaintext localhost:40401 describe coop.rchain.casper.protocol.DeployService
coop.rchain.casper.protocol.DeployService is a service:
service DeployService {
  rpc DoDeploy ( .coop.rchain.casper.protocol.DeployData ) returns ( .Either );
  rpc findDeploy ( .coop.rchain.casper.protocol.FindDeployQuery ) returns ( .Either );
  ...
}

# Example of Casper API request
$ grpcurl -plaintext localhost:40401 coop.rchain.casper.protocol.DeployService/lastFinalizedBlock
{
  "success": {
    "response": {
      "typeUrl": "type.rchain.coop/coop.rchain.casper.protocol.LastFinalizedBlockResponse",
      "value": "CkBlN...TJkNWZhYjIE2MjhiMTZlYTE4NTEzMTBmODZmOWRmZTAp0KCn0="
    }
  }
}

# Exaample of request to meta object with response types
$ grpcurl -plaintext localhost:40401 describe coop.rchain.casper.protocol.DeployEitherMeta
coop.rchain.casper.protocol.DeployEitherMeta is a message:
message DeployEitherMeta {
  .coop.rchain.casper.protocol.DeployServiceResponse DoDeploy = 1;
  .coop.rchain.casper.protocol.BlockQueryResponse getBlock = 2;
  .coop.rchain.casper.protocol.VisualizeBlocksResponse visualizeDag = 3;
  .coop.rchain.casper.protocol.LightBlockInfo showMainChain = 4;
  .coop.rchain.casper.protocol.LightBlockInfo getBlocks = 5;
  .coop.rchain.casper.protocol.ListeningNameDataResponse listenForDataAtName = 6;
  .coop.rchain.casper.protocol.ListeningNameContinuationResponse listenForContinuationAtName = 7;
  .coop.rchain.casper.protocol.LightBlockQueryResponse findDeploy = 8;
  .coop.rchain.casper.protocol.PrivateNamePreviewResponse previewPrivateNames = 9;
  .coop.rchain.casper.protocol.BlockQueryResponse lastFinalizedBlock = 10;
}

UI example with gRPCox.
grpc-reflection-ui

Please make sure that this PR:

Bors cheat-sheet:

  • bors r+ runs integration tests and merges the PR (if it's approved),
  • bors try runs integration tests for the PR,
  • bors delegate+ enables non-maintainer PR authors to run the above.

Copy link
Collaborator

@KentShikama KentShikama left a comment

Choose a reason for hiding this comment

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

Looks useful; my only concern is any additional firewalls that will have to be set up by node operators.

@tgrospic
Copy link
Collaborator Author

I've added reflection to internal gRPC service also.

@KentShikama reflection only creates one additional service on the same port so for firewall it is not an issue. This new service is also visible with the reflection. :)

$ grpcurl -plaintext localhost:40401 list
coop.rchain.casper.protocol.DeployService
coop.rchain.casper.protocol.ProposeService
grpc.reflection.v1alpha.ServerReflection

$ grpcurl -plaintext localhost:40402 list
coop.rchain.casper.protocol.ProposeService
coop.rchain.node.model.Repl
grpc.reflection.v1alpha.ServerReflection

Copy link
Contributor

@sebtomba sebtomba left a comment

Choose a reason for hiding this comment

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

I don't understand how DeployServiceResponseMeta will be used by the clients. Besides that LGTM

@KentShikama
Copy link
Collaborator

@tgrospic The firewall is for the protection of the node

@KentShikama
Copy link
Collaborator

bors r+

bors bot added a commit that referenced this pull request Sep 2, 2019
2698: Enable gRPC server reflection and CORS on HTTP service r=KentShikama a=tgrospic



Co-authored-by: Tomislav Grospic <grospic@gmail.com>
@tgrospic
Copy link
Collaborator Author

tgrospic commented Sep 2, 2019

@KentShikama reflection service should only expose meta info about proto definitions and can be protected with firewall as other services on the same port.

@sebtomba I'm generating TypeScript definitions from proto files and I need type parameter for Either in responses. Field in DeployServiceResponseMeta correspond to service method with the same name and the type is the generic type of Either.
In the current implementation, I need to parse comments from proto files to get this info. Via reflection this workaround is not possible at all so this meta type will be the only solution.

@bors
Copy link
Contributor

bors bot commented Sep 2, 2019

Build succeeded

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.

None yet

4 participants