Skip to content

Instantly share code, notes, and snippets.

@cryptocode
Created September 11, 2021 16:14
Show Gist options
  • Save cryptocode/b1ab2ef321df5e7ecf6b29cef0d387e8 to your computer and use it in GitHub Desktop.
Save cryptocode/b1ab2ef321df5e7ecf6b29cef0d387e8 to your computer and use it in GitHub Desktop.

TL;DR: RPC 2.0 is ready for action

Status

I believe the RPC 2.0 infrastructure is complete, including access control, though it could probably use some more testing on beta before going into production.

I've tried the latest develop and everything appears to work. Though there have been Xcode path changes at some point, making development a bit inconvenient. I'm going to make a PR to fix this.

This status document should still be correct: https://github.com/cryptocode/notes/wiki/IPC-Flatbuffers-API

Existing RPC 2.0 handlers

The existing handlers, like AccountWeight and confirmation callback, are what I call a tracer bullets. It was implemented to prove that IPC2/RPC2 was feature complete.

I believe dotcom opined that AccountWeight should eventually be removed.

At any rate, these should be good to look at for people wanting to implement new handlers.

The handler code is mostly found in nano::ipc::action_handler and nano::ipc::broker.

It's important that devs adding handlers understand how the Flatbuffers C++ API works; it's mostly about doing message construction in the right order

Access control structure

The framework for this is fully implemented and is quite capable.

The access_permission enum in the node contains a starting point. My main idea here was the following:

  1. Add a permission for every RPC we add, to allow for fine-grained control
  2. Add additional logical permissions for coarse-grained control, like "wallet_read"

This enables a node operator to choose granularity when defining who should be able to access what.

Each RPC handler checks that one of multiple permissions is active.

For instance, AccountWeight checks that either api_account_weight or the account_query permission is set.

The point of account_query is to group all account-querying RPCs, while api_account_weight is only for that specific RPC. Enabling either will allow the RPC to be called.

None of this is set in stone and can easily be adjusted to suit real-world needs.

Of course, a developer/node operator can decide to give everyone access to everything with a simple config entry.

More info here (I added an error response example): https://github.com/cryptocode/notes/wiki/IPC-Authorization

I think RPC2/permissions should be marked experimental until a good structure is defined, as changing these would be a breaking change.

Streaming responses

There is no tracer bullet for this, but one can probably be made with relative ease.

In RPC 1.0, very large responses take a lot of memory. The concept of correlation ID is already implemented, so for instance a "ledger" RPC could be defined to be streaming.

The response would then be multiple messages with the same correlation ID, which the client collects until a "final" message of some sort arrives with the same correlation ID. Both the node and the client thus use minimal memory even for massive responses. This is especially useful when clients only need to count or filter or calculate.

Other thoughts/future work

  • https://forum.nano.org/t/rpc-2-0-refactor/110 should probably be fleshed out, as it's a good start.

  • I think RPC 2 should grow conservatively, with lots of thought being given to each RPC. This is especially important since Flatbuffers is a binary format that requires compatibility considerations (the spec was updated with rules for this) What enables this to happen gradually is of course that RPC 1.0 is already in place and working.

  • If there aren't enough devs available to flesh out RCP 2.0, a shorter-term option is to switch RPC 1.0 to the new boost::JSON library and move over the access control implementation. It won't be as low-level/fast as Flatbuffers, but a lot faster and more compliant than the current ptree implementation.

  • One idea I had, which is not implemented, was to also hook WebSockets into the Flatbuffers infrastructure. In an ideal world, a high-quality external webserver with websocket support is used, with IPC 2.0 communication to the node. This could even be an nginx extension. This would significantly reduce the attack surface and simplify load balancing.

  • It would be great if someone made a Flatbuffers <-> OpenAPI/swagger generator, but this was more complicated than I thought.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment