Conversation
…chainspec from a URL
| >; | ||
|
|
||
| /// Type of subscription IDs we can get back. | ||
| pub type SubscriptionId = String; |
There was a problem hiding this comment.
It was previously an unsigned int, but even if Smoldot currently does that, I didn't think we should rely on it since it probably also expects us to treat the valeus as opaque.
| to_backend: mpsc::UnboundedSender<Message>, | ||
| } | ||
|
|
||
| impl BackgroundTaskHandle { |
There was a problem hiding this comment.
I added this to give a nice "API" to interact with the background task, so that nothing outside of the backend task actually needs to care about messages and such
| /// Run the background task, which: | ||
| /// - Forwards messages/subscription requests to Smoldot from the front end. | ||
| /// - Forwards responses back from Smoldot to the front end. | ||
| pub async fn run(self) { |
There was a problem hiding this comment.
A simplified version of what was called start_task before. No longer takes in any args, so the API for BackgroundTask is super simple; just .run().await it to start it running (and in the future we can return something users can poll which will just wrap this).
| let from_back_fut = channels.from_back.next().fuse(); | ||
| } | ||
|
|
||
| futures::select! { |
There was a problem hiding this comment.
I moved to this I think to avoid allocating somewhere or annoying lifetime things; can't remember exactly now. It just takes two channels as inputs though and so I think should have no cancellation concerns (this is the usual footgun with select!
There was a problem hiding this comment.
Looks good, btw you asked me exactly this question "What is the usual usual footgun with select!" when interviewing me as a job applicant about a year ago.
There was a problem hiding this comment.
I need to make a note somewhere because if I move to doing a code review style task then future::select! is def a candidate to put somewhere :D
There was a problem hiding this comment.
you are good, streams are cancel-safe.
I like tokio::select better because it doesn't require pinning the futures
There was a problem hiding this comment.
I normally prefer the function call version to avoid some footguns but iirc I had an issue that made it hard to use it nicely; I'll have to try again at some point!
| struct ActiveSubscription { | ||
| /// Channel to send the subscription notifications back to frontend. | ||
| sender: mpsc::UnboundedSender<Box<RawValue>>, | ||
| notification_sender: mpsc::UnboundedSender<Result<Box<RawValue>, JsonRpcError>>, |
There was a problem hiding this comment.
I tweaked subscriptions a bit to:
a) return any subscription notification errors that come back (previously these were being ignored I think) and
b) send back the ID and repsonse channel rather than one channel for ID and one for responses, just to simplify usage a little.
| } | ||
|
|
||
| /// Configuration to connect to a chain. | ||
| pub struct ChainConfig<'a> { |
There was a problem hiding this comment.
This can grow to have more options like about max json RPC subs etc if we want to expose them. A user can then either build this config and configure it, or pass a chain spec &str directly, which will convert into this easily.
| NotificationError { | ||
| /// RPC method that generated the notification. | ||
| method: String, | ||
| /// Subscription ID. | ||
| subscription_id: String, | ||
| /// Result. | ||
| error: Box<RawValue>, | ||
| }, |
There was a problem hiding this comment.
This file is copied from the previous impl in background.rs, but I added this NotificationError to handle the case when we get errors back in subscriptions. Worth double checking that this is right :)
subxt/src/utils/fetch_chain_spec.rs
Outdated
|
|
||
| cfg_jsonrpsee! { | ||
| /// Fetch a chain spec from an RPC node at the given URL. | ||
| pub async fn fetch_chainspec_from_rpc_node(url: impl AsRef<str>) -> Result<Box<RawValue>, FetchChainspecError> { |
There was a problem hiding this comment.
I tried putting a fn like this (from_url) on ChainConfig but it required pulling lots of deps in etc, and since it's a dev use case mostly I was sortof ok with just exposing this util function instead in Subxt, since it's easier to do it here. Not the cleanest though!
| // Connecting to a parachain is a multi step process. | ||
| // Instantiate a light client with the Polkadot relay chain, | ||
| // and connect it to Asset Hub, too. | ||
| let (lightclient, polkadot_rpc) = LightClient::relay_chain(POLKADOT_SPEC)?; |
lexnv
left a comment
There was a problem hiding this comment.
LGTM! I like the idea of having a background task per chain ID, this should isolate things quite nicely 👍
|
I added back a compile error and docsrs thing that went missing, and updated the book, swapping the examples around so now connecting to parachains is the basic example, and connecting to a local node is more advanced :) |
tadeohepperle
left a comment
There was a problem hiding this comment.
I think the interface is well designed, good job!
| let from_back_fut = channels.from_back.next().fuse(); | ||
| } | ||
|
|
||
| futures::select! { |
There was a problem hiding this comment.
Looks good, btw you asked me exactly this question "What is the usual usual footgun with select!" when interviewing me as a job applicant about a year ago.
| // Send the method response and a channel to receive notifications back. | ||
| if pending_subscription | ||
| .response_sender | ||
| .send(Ok((sub_id.clone(), sub_rx))) |
There was a problem hiding this comment.
Could we avoid allocation here by using Arc<str> for subscription ids? Probably irrelevant though, feel free to ignore.
There was a problem hiding this comment.
I'd guess it's not worth while because we (technically, but not really in reality) need to allocate a String anyway for the deserializing bit, and then the Arc is another alloc, and we onlyclone it once anyways :)
| /// https://docs.rs/wasm-bindgen-futures/latest/wasm_bindgen_futures/fn.future_to_promise.html. | ||
| pub fn parachain<'a>( | ||
| &self, | ||
| chain_config: impl Into<ChainConfig<'a>>, |
There was a problem hiding this comment.
This interface with the relay_chain and parachain functions looks really clean.
|
This pull request has been mentioned on Polkadot Forum. There might be relevant details there: https://forum.polkadot.network/t/parity-tech-update-for-march/7226/1 |
The main changes:
subxt_lightclient; only a little glue in Subxt to integrate it.LightClientstruct to create light client instance given relay chain spec, and to create parachain connections on top of this.LightClientRpcreturned from each of the above which is the means to interact with the chain.RpcClientTfor this, so that it can be used to construct anOnlineClient.BackgroundTask. This isn't exposed yet, but can eventually be in order that users can drive it and exert backpressure if need be (I'm unsure what effect that would have on Smoldot though!).Other changes along the way:
Things not done:
OnlineClient::from_chain_spec(); need a relay + parachain version etc, prob need a builder or something to make it nice. Instead I made it easier to instantiate an OnlineClient from an RPC client (impl Into) so it's actually pretty easy anyway now.from_urlto theChainSpecConfig. I staretd doing this but it involved pulling in extra deps and feature flags etc, and the code was just easier to keep insubxt. So I exposed a utility function to fetch chain spec from url instead. I'm ok with this because it's actually only really a dev use case anyway; we prob shouldn't encourage it too much!