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

Light Client RPC Service #219

Closed
brapse opened this issue Apr 16, 2020 · 11 comments · Fixed by #449
Closed

Light Client RPC Service #219

brapse opened this issue Apr 16, 2020 · 11 comments · Fixed by #449
Assignees
Labels
light-client Issues/features which involve the light client
Milestone

Comments

@brapse
Copy link
Contributor

brapse commented Apr 16, 2020

Updated to reflect the conclusion of the discussion in comments and slack

The light client fetches headers/validator sets from other nodes to perform verification. The light client should also make those headers/validator sets available to the network through an RPC service.

The goal here is to create an RPC service operating in a separate runtime with access to it's own light client handler similar to:

let mut handle = supervisor.handle();

This issue should exclusively include endpoints for:

  • /status: returns local status information, like the latest height, latest block and valset hashes, list of of connected full nodes (primary and secondaries), etc.
  • /state: returns the latest header, commit, and validator set

Follow up issues can address potential further improvements.

@romac romac added the light-client Issues/features which involve the light client label May 25, 2020
@ebuchman
Copy link
Member

ebuchman commented Jun 2, 2020

The goal here is essentially a light-node: a process that syncs the blockchain using light-client verification and exposes an http API for interacting with the blockchain (ie. queries, transactions). Such an API could be used to build local applications that read/write to the blockchain securely without needing a local full node.

In Go, we have tendermint lite, which runs a light node that exposes the same RPC API as the full node, essentially an http proxy that does light client verification. There's also the gaiacli rest-server, a similar idea but with an application specific REST API (eg. for accounts, staking, governance etc.) rather than the RPC exposed by Tendermint full nodes (which can do raw abci queries, but doesn't know anything about accounts, staking, governance, etc.).

To start, we should expose two http endpoints in the light-node process:

  • /status: returns local status information, like the latest height, latest block and valset hashes, list of of connected full nodes (primary and secondaries), etc.
  • /state: returns the latest header, commit, and validator set

Once we have the basics, we can draft a longer term plan for this API, and consider something like the complete tendermint lite proxy in Rust, which would effectively wrap our tendermint-rs RPC client with light client verification. Note for full compatibility we'd have to support queries for historical heights, which could require running the light client backwards.

@liamsi liamsi self-assigned this Jun 2, 2020
@ebuchman ebuchman added this to the Light Node milestone Jun 2, 2020
@romac romac changed the title [light-client] Light Client RPC Service Light Client RPC Service Jun 10, 2020
@liamsi
Copy link
Member

liamsi commented Jun 15, 2020

Cross posting this here for @xla:

You guys asked me last week what methods the rpc would need from the light client. As far as I can see it’s only one method:

  • given a target height h , either return the stored result, (if still valid) or, run the light client to that height ( h might potentially be in the past)

It’s needed by the endpoints: /blockchain, /block, /block_by_hash, /block_results, /commit, /tx, /validators, /consensus_params, /abci_query, (some of them take a height param and that should trigger the light client to catch up or request a past height if necessary)

These are the routes that need to be implemented:
https://github.com/tendermint/tendermint/blob/74cae49c3b1eadb1355a0a23ae6bb81545fb08ea/light/proxy/routes.go#L12-L50

@xla xla self-assigned this Jun 15, 2020
xla added a commit that referenced this issue Jun 16, 2020
Introducing a proxy which serves the Tendermint RPC API with the help of
connect rpc client. Later to be extended to add light client
functionality. This is in nature equivalent to the Go proxy[0].

Instead of reaching for hyper this change introduces warp to build an
http server. This decision should be evaluated very carefully, while
warp is a thinly wrapper around hyper, it brings a lot of very important
tooling (including websockets), it also has its own set of dependencies.

Also currently unclear if the module that implements the rpc API with
lite client functionality should live in the rpc source tree.

Part of #219

[0] https://github.com/tendermint/tendermint/tree/master/light/proxy
@ebuchman
Copy link
Member

Just a note that we probably shouldn't start with a full proxy yet as a lot is likely to change this year in the Go RPC, and we might want to wait for that.

I was thinking to start we would just expose the two endpoints I outlined above, one to get some status info and one for the latest state.

We could extend the latest state one to also return previous state or to fetch state it doesn't have. But I think we should hold off on the full proxy for now.

@xla
Copy link
Contributor

xla commented Jun 16, 2020

@brapse Two clarifications inline.

The light client should also make those headers/validator sets available to the network through an RPC service

Probably unnecessary nit-picking, but isn't that the we want the light node to make these available through an RPC API?

The goal here is to create an RPC service operating in a separate runtime with access to it's own light client handler similar to:

Which requirements dictate the constraint for RPC to run on a separate runtime.

@brapse
Copy link
Contributor Author

brapse commented Jun 17, 2020

Right, the light node naming here makes sense.

The light client runs in its own thread as to not necessarily block the RPC or Relayer when doing long verification runs.

@xla
Copy link
Contributor

xla commented Jun 29, 2020

/status: returns local status information, like the latest height, latest block and valset hashes, list of of connected full nodes (primary and secondaries), etc.

To proceed more information is needed for the following points:

  • latest height: which height are we referring to? ideally we can point to a specific point in the system where this height would come form
  • latest block: is this not covered with /state? Or are we interested in surfacing even non-trusted or unverified blocks here?
  • valset hashes: Again does that no overlap with /state which would expose that?
  • connected nodes: This seems straightforward and might be just surfacing the contents of the Supervisor peerlist.

Any other thoughts appreciated as well.

@ebuchman
Copy link
Member

So /state should return the latest trusted full LightBlock data structure. But /status should return only a couple of elements from that as a quick reference. Those elements are (where light_block is what you would return in /state):

  • height (ie. light_block.signed_header.header.height)
  • block hash (light_block.signed_header.header.hash())
  • valset hash (light_block.signed_header.header.next_validator_set_hash) - note it's the next_valset because that's the latest valset we trust, even though it may not have signed a block we trust yet ...

And then the connected nodes aren't in a light block but would come from the supervisor.

@xla
Copy link
Contributor

xla commented Jun 29, 2020

@ebuchman Thanks for the clarification, I'm not quite sure what the benefit is of the mostly duplicated data, except the next_val_set_hash I guess. Thought the /status endpoint is more operational and shows some of the internal state.

On the upside the /state endpoint is on its way and implemented to your understanding.

@ebuchman
Copy link
Member

what the benefit is of the mostly duplicated data

It's a snapshot of the latest state. Similar to the way the /status endpoint on tendermint nodes returns hashes from the latest block. It's so you don't have to consume and traverse a much larger data structure but can just see directly a reference/summary of the latest state from the /status endpoint

xla added a commit that referenced this issue Jun 30, 2020
As we start to depend on the surface of the `Handle` we benefit from it
being a trait that can be implemented on a per need basis. This will
result in less overhead constructing object graphs in places where we
wannt to assert behaviour of other types in remote places, i.e. the
light-node rpc server. Overall we hope for an increased ease in writing
tests on module level.

Ref #219
brapse pushed a commit that referenced this issue Jul 1, 2020
* light-client: turn Handle into a trait

As we start to depend on the surface of the `Handle` we benefit from it
being a trait that can be implemented on a per need basis. This will
result in less overhead constructing object graphs in places where we
wannt to assert behaviour of other types in remote places, i.e. the
light-node rpc server. Overall we hope for an increased ease in writing
tests on module level.

Ref #219

* Add changes entry

* Apply suggestions from code review

Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>

Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>
brapse pushed a commit that referenced this issue Jul 3, 2020
* light-client: turn Handle into a trait

As we start to depend on the surface of the `Handle` we benefit from it
being a trait that can be implemented on a per need basis. This will
result in less overhead constructing object graphs in places where we
wannt to assert behaviour of other types in remote places, i.e. the
light-node rpc server. Overall we hope for an increased ease in writing
tests on module level.

Ref #219

* Add changes entry

* Remove async trait methods

* Make supervisor more CSP

* Improve crate imports

* Relax mutability on Handle

* Provide noop default implementations

* Update adr status

* Handle crossbeam errors honestly

* Add changes entry

* Mention ADR in change entry

* Correct PR link

* Simplify example
brapse pushed a commit that referenced this issue Jul 7, 2020
* light-client: turn Handle into a trait

As we start to depend on the surface of the `Handle` we benefit from it
being a trait that can be implemented on a per need basis. This will
result in less overhead constructing object graphs in places where we
wannt to assert behaviour of other types in remote places, i.e. the
light-node rpc server. Overall we hope for an increased ease in writing
tests on module level.

Ref #219

* Add changes entry

* Remove async trait methods

* Make supervisor more CSP

* Improve crate imports

* Relax mutability on Handle

* Provide noop default implementations

* Update adr status

* Handle crossbeam errors honestly

* Add changes entry

* WIP

* Mock out actual endpoints

* Assert actual response shapes

* Use async tests

* Integrate Handle in node rpc server

* Adjust to move to trait

* Adjust to latest trait changes

* Remove unused import

* Start error infra

* Use json input for tests

* Remove unused status endpoint

* Seal and expose proper run functionality

* Correct address configuration

* Add temp example

* Update light-node/src/rpc.rs

Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>

* Remove unused errors

* Improve error propagation

* Correct wording

Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>
@brapse
Copy link
Contributor Author

brapse commented Jul 14, 2020

The /state endpoint landed with #366 and we are just waiting for an implementation of /status ☺️

@liamsi
Copy link
Member

liamsi commented Jul 15, 2020

@ebuchman for the /status endpoint:

/status: returns local status information, like the latest height, latest block and valset hashes, list of of connected full nodes (primary and secondaries), etc.

It's probably sufficient to return a list of PeerIDs for the list of connected full nodes? Is there any benefit in highlighting the primary? My currentl thinking is that the rust struct returned by a yet to be created handler will look like this:

pub struct LatestStatus {
    pub height: Height,
    pub block_hash: Hash,
    pub valset_hash: Hash,
    pub connected_nodes: Vec<PeerId>,
}

Am I missing anything?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
light-client Issues/features which involve the light client
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants