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: Add experimental light-client support #965

Merged
merged 88 commits into from
Jun 26, 2023

Conversation

lexnv
Copy link
Collaborator

@lexnv lexnv commented May 18, 2023

This PR exposes the LightClient that uses smoldot to connect to chains.

Smoldot exposes a single non-clonable object that exposes all responses of all methods and all subscriptions via
a next() method call. Because of this, a background task is spawned to multiplex the responses back
to the appropriate submitters.

Smoldot generates some extra events while submitting an extrinsic, this is related to the new RPC Spec V2.
As a result of that, spurious events emitted by transaction_unstable_watchEvent are ignored.

The SubstrateTxStatus needed to be changed as well to support both lower camelCase and upper CamelCase.

When using the smoldot from crates-io, the implementation panics at:

thread 'main' panicked at 'attempt to subtract with overflow', /Users/lexnv/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smoldot-0.6.0/src/chain_spec.rs:444:37
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

However, using the latest from the smoldot repo does not reproduce the issue.

The PR exposes 2 ways to construct the Light Client:

  • from a spec str
  • from a URL from which the chain spec is fetched

The former version is working as expected, while the latter seems to cause an overflow issue in smoldot

thread 'main' panicked at 'attempt to subtract with overflow', /Users/lexnv/.cargo/git/checkouts/smoldot-2dcbf637e11a77d4/43b3306/lib/src/chain_spec.rs:445:37
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Testing Done

Initially using smoldot to target a local node caused the client to hang with GrandPa warp sync warnings.
Using the latest branch, I was able to start a node as normal:

  1. ./polkadot-6dc9e84dde2 --dev --alice --validator
  2. cargo run --example tx_basic_light_client

Available functionality

The following functionality is tested both on a local node, as well as on the polkadot live chain:

  • Submit and watch a transaction
  • Subscribes to all finalized blocks using the old RPC method
  • Subscribes to the head of the chain using the new chainHead RPC method
  • Dynamically query constants
  • Dynamically decode the events of the latest block
  • Various RPC calls to ensure proper shape of the response.

Known limitations

  • Iterating over keys is not expected to work: the light client tries its best to provide some answers, although I've encountered the same 3 responses submitted over again
  • chainHead_unstable_body response contains a value: ["0xhex", "0xhex"] shape, where subxt expects from substrate chains result: "0xhex"
  • chainHead_unstable_storage response contains a value: "0xhex" shape, where subxt expects from substrate chains result: "0xhex" (this is handled internally)
  • submitting a transaction using the old API will generate spurious events from the new API (chainHead_unstable_transaction -- handled internally)

Closes: #962

@lexnv lexnv requested a review from a team as a code owner May 18, 2023 17:23
@lexnv lexnv self-assigned this May 18, 2023
@ascjones
Copy link
Contributor

Been dreaming about this for a long time 🚀

IIRC @rphmeier also expressed an interest in this.

Cargo.toml Outdated Show resolved Hide resolved
Copy link
Member

@niklasad1 niklasad1 left a comment

Choose a reason for hiding this comment

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

Looks good,

How to deal with the git dependency is a blocker from my side otherwise really cool to have support for this in subxt

lexnv and others added 7 commits May 22, 2023 17:31
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
@rphmeier
Copy link

Nice, looking forward to trying this out. Is it also intended to work in-browser with Wasm compilation as well as native executables?

Comment on lines +114 to +120
let result = self.client.json_rpc_request(request, self.chain_id);
if let Err(err) = result {
tracing::warn!(
target: LOG_TARGET,
"Cannot send RPC request to lightclient {:?}",
err.to_string()
);
Copy link

Choose a reason for hiding this comment

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

I just want to point out that this can realistically happen. If a TooBusy error is returned, you're supposed to back-pressure the requests sender.

I understand that from your point of view it's not very convenient, so I've opened smol-dot/smoldot#804 to clarify this thing.

Copy link

Choose a reason for hiding this comment

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

To clarify: there will always be an error here. But maybe I can provide some configuration option that guarantees a minimum buffer size, so that you have a runtime guarantee that it won't happen.

Copy link

@tomaka tomaka Jun 23, 2023

Choose a reason for hiding this comment

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

Sorry I was a bit confused this morning since I was working on something else in parallel.

What you should do is pass max_pending_requests: u32::max_value() and max_subscriptions: u32::max_value() when adding the chain. There's no need to make these parameters configurable.

These parameters exist only to make sure that the memory usage of smoldot is bounded in situations where the JSON-RPC client is potentially malicious and can spam you with requests. This isn't relevant here, since you are the JSON-RPC client.

Copy link
Member

@niklasad1 niklasad1 left a comment

Choose a reason for hiding this comment

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

great PR, looks good to me

lexnv and others added 2 commits June 23, 2023 14:05
Copy link
Contributor

@tadeohepperle tadeohepperle left a comment

Choose a reason for hiding this comment

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

Very good work, I like the multiplexing over the background task a lot.

subxt/src/book/usage/light_client.rs Show resolved Hide resolved
subxt/src/client/lightclient/background.rs Show resolved Hide resolved
subxt/src/client/lightclient/background.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@jsdw jsdw left a comment

Choose a reason for hiding this comment

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

A few remaining nits and small things, but in general this is amazing stuff! Clean, well documented and tested. Good job!!

@lexnv lexnv merged commit ef89752 into master Jun 26, 2023
@lexnv lexnv deleted the lexnv/light_client_support branch June 26, 2023 09:11
tadeohepperle pushed a commit that referenced this pull request Jul 4, 2023
* rpc/types: Decode `SubstrateTxStatus` for substrate and smoldot

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Add light client Error

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Add background task to manage RPC responses

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Implement the light client RPC in subxt

Signed-off-by: Alexandru Vasile <[email protected]>

* subxt: Expose light client under experimental feature-flag

Signed-off-by: Alexandru Vasile <[email protected]>

* artifacts: Add development chain spec for local nodes

Signed-off-by: Alexandru Vasile <[email protected]>

* Update cargo lock

Signed-off-by: Alexandru Vasile <[email protected]>

* examples: Add light client example

Signed-off-by: Alexandru Vasile <[email protected]>

* Update sp-* crates and smoldot to use git with branch / rev

Signed-off-by: Alexandru Vasile <[email protected]>

* Apply cargo fmt

Signed-off-by: Alexandru Vasile <[email protected]>

* Fix clippy

Signed-off-by: Alexandru Vasile <[email protected]>

* Import hashmap entry

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Fetch spec only if jsonrpsee feature is enabled

Signed-off-by: Alexandru Vasile <[email protected]>

* Update subxt/src/rpc/lightclient/background.rs

Co-authored-by: Niklas Adolfsson <[email protected]>

* Fix typo

Signed-off-by: Alexandru Vasile <[email protected]>

* artifacts: Update dev chain spec

Signed-off-by: Alexandru Vasile <[email protected]>

* types: Handle storage replies from chainHead_storage

Signed-off-by: Alexandru Vasile <[email protected]>

* artifacts: Add polkadot spec

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Handle RPC error responses

Signed-off-by: Alexandru Vasile <[email protected]>

* examples: Tx basic with light client for local nodes

Signed-off-by: Alexandru Vasile <[email protected]>

* example: Light client coprehensive example for live chains

Signed-off-by: Alexandru Vasile <[email protected]>

* examples: Remove prior light client example

Signed-off-by: Alexandru Vasile <[email protected]>

* feature: Rename experimental to unstable

Signed-off-by: Alexandru Vasile <[email protected]>

* book: Add light client section

Signed-off-by: Alexandru Vasile <[email protected]>

* testing: Fix clippy

Signed-off-by: Alexandru Vasile <[email protected]>

* lightclient: Ignore validated events

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust tests for light-clients and normal clients

Signed-off-by: Alexandru Vasile <[email protected]>

* testing: Keep lightclient variant

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove support for chainHead_storage for light client

Signed-off-by: Alexandru Vasile <[email protected]>

* Update light client to point to crates.io

Signed-off-by: Alexandru Vasile <[email protected]>

* Update sp-crates from crates.io

Signed-off-by: Alexandru Vasile <[email protected]>

* Replace Atomic with u64

Signed-off-by: Alexandru Vasile <[email protected]>

* Add LightClientBuilder

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust chainspec with provided bootnodes

Signed-off-by: Alexandru Vasile <[email protected]>

* Add potential_relay_chains to light client builder

Signed-off-by: Alexandru Vasile <[email protected]>

* Move the light-client to the background task

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust tracing logs

Signed-off-by: Alexandru Vasile <[email protected]>

* Update book and example

Signed-off-by: Alexandru Vasile <[email protected]>

* Apply cargo fmt

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove dev_spec.json artifact

Signed-off-by: Alexandru Vasile <[email protected]>

* Examples fix duplicate Cargo.toml

Signed-off-by: Alexandru Vasile <[email protected]>

* Use tracing_subscriber crate

Signed-off-by: Alexandru Vasile <[email protected]>

* Fix clippy for different features

Signed-off-by: Alexandru Vasile <[email protected]>

* Add comment about bootNodes

Signed-off-by: Alexandru Vasile <[email protected]>

* Add comment about tracing-sub dependency

Signed-off-by: Alexandru Vasile <[email protected]>

* Run integration-tests with light-client

Signed-off-by: Alexandru Vasile <[email protected]>

* Feature guard some incompatible tests

Signed-off-by: Alexandru Vasile <[email protected]>

* ci: Enable light-client tests under feature flag

Signed-off-by: Alexandru Vasile <[email protected]>

* ci: Fix git step name

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust flags for testing

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust warnings

Signed-off-by: Alexandru Vasile <[email protected]>

* Rename feature flag jsonrpsee-ws to jsonrpsee

Signed-off-by: Alexandru Vasile <[email protected]>

* Fix cargo check

Signed-off-by: Alexandru Vasile <[email protected]>

* ci: Run tests on just 2 threads

Signed-off-by: Alexandru Vasile <[email protected]>

* Move light-client to subxt/src/client

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust LightClientBuilder

Signed-off-by: Alexandru Vasile <[email protected]>

* Use ws_url to construct light client for testing

Signed-off-by: Alexandru Vasile <[email protected]>

* Refactor background

Signed-off-by: Alexandru Vasile <[email protected]>

* Address feedback

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove polkadot.spec and trim sub_id

Signed-off-by: Alexandru Vasile <[email protected]>

* Wait for substrate to produce block before connecting light client

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust builder and tests

Signed-off-by: Alexandru Vasile <[email protected]>

* Apply fmt

Signed-off-by: Alexandru Vasile <[email protected]>

* ci: Use release for light client testing

Signed-off-by: Alexandru Vasile <[email protected]>

* Add single test for light-client

Signed-off-by: Alexandru Vasile <[email protected]>

* Wait for more blocks

Signed-off-by: Alexandru Vasile <[email protected]>

* Use polkadot endpoint for testing

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust cargo check

Signed-off-by: Alexandru Vasile <[email protected]>

* examples: Remove light client chain connection example

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust cargo.toml section for the old example

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust background task to use usize for subscription Id

Signed-off-by: Alexandru Vasile <[email protected]>

* Build bootnodes with serde_json::Value directly

Signed-off-by: Alexandru Vasile <[email protected]>

* Make channel between subxt user and subxt background unbounded

Signed-off-by: Alexandru Vasile <[email protected]>

* Update subxt/src/client/lightclient/builder.rs

Co-authored-by: Niklas Adolfsson <[email protected]>

* Switch to smoldot 0.6.0 from 0.5.0

Signed-off-by: Alexandru Vasile <[email protected]>

* Move testing to `full_client` and `light_client` higher modules

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove subscriptionID type

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove subxt/integration-testing feature flag

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust wait_for_blocks documentation

Signed-off-by: Alexandru Vasile <[email protected]>

* Adjust utils import for testing

Signed-off-by: Alexandru Vasile <[email protected]>

* Remove into_iter from builder construction

Signed-off-by: Alexandru Vasile <[email protected]>

---------

Signed-off-by: Alexandru Vasile <[email protected]>
Co-authored-by: Niklas Adolfsson <[email protected]>
@jsdw jsdw mentioned this pull request Jul 24, 2023
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.

[light-client] Experimental support with smoldot
7 participants