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

fix: recover from smoldot crashes #2162

Merged
merged 18 commits into from May 22, 2024
Merged

fix: recover from smoldot crashes #2162

merged 18 commits into from May 22, 2024

Conversation

ryanleecode
Copy link
Collaborator

@ryanleecode ryanleecode commented May 4, 2024

Fixes: #1786 (github will probably auto-close this issue but it shouldnt closed until the extension is updated on the chrome store).

Adds smoldot recovery to light-client-extension-helpers.

This change adds a wrapper to the smoldot client to add a restart method and change the AddChainOptions to accept AddChainOptions for potentialRelayChains instead of Chain objects, because Chain objects cannot persist between smoldot restarts.

This change also creates a custom JSON RPC Provider that will automatically re-connect to the chain it was connected to post-smoldot restart with the exact same AddChainOptions.

To actually perform restarts, there is now a supervise function that gets invoked during register that repeatedly calls addChain with an empty chain spec. The moment that there is a CrashError from smoldot, smoldot gets restarted.

Testing

Follow the instructions in the repo README.md to run the extension and open the demo page. Then repeatedly disconnect and re-connect from VPN and watch the extension console for smoldot crashes.

Demo

https://www.loom.com/share/c00c5348596d447a8ff371d043a3a818?sid=f3967a38-b725-460a-8c84-10975befbc99


Old Description

This PR addresses issue 1786, which prevents Substrate Connect from recovering when Smoldot crashes. The current fix attempt in PR 2157 has issues with recovery, chain handle management, and observability.

This PR introduces a new library using Effect to manage Smoldot restarts and JSON RPC provider connections. It ensures that each chain's lifecycle is tied to a single Smoldot client. When a Smoldot client is killed, all chains automatically disconnect and reconnect to the new Smoldot client in the JSON RPC Provider implementation. This approach improves recovery and simplifies chain management.

However, this change requires additional feature work in future PRs before it can fully replace the background folder in the light client extension helpers. Future PRs will need to adapt the existing codebase to utilize the new Smoldot management and chain handling capabilities.

The key benefits are:

  • Improved recovery: Substrate Connect can now properly handle Smoldot crashes without becoming unusable.
  • Better resource management: The new library streamlines the creation and destruction of Smoldot clients and the addition and removal of chains.
  • Simplified chain handling: Each chain is now directly linked to a single Smoldot client, reducing complexity.

The most important file you'll want to be reviewing is the JSON RPC Provider implementation: https://github.com/paritytech/substrate-connect/pull/2162/files#diff-00e4cc89f4df6dfb8719cbbe32fd288d8a4bb1e26a1932817814734d3bf556b1


Use it yourself!

1. Clone this PR
2. corepack pnpm i
3. cd packages/light-client-experimental
4. corepack pnpm turbo build
5. pnpm dlx tsx ./scripts/testing.ts

If you want to have some fun you can also adjust the log levels in the testing script.

image

image

@ryanleecode ryanleecode force-pushed the feat/smoldot-effect-bindings branch from 5d9b087 to 0bd1a32 Compare May 4, 2024 07:07
@ryanleecode ryanleecode force-pushed the json-rpc-effect-bindings branch 2 times, most recently from 3960cd4 to 8b66785 Compare May 4, 2024 13:53
@ryanleecode ryanleecode force-pushed the feat/smoldot-effect-bindings branch from 0bd1a32 to 02dcfc5 Compare May 4, 2024 13:55
@ryanleecode ryanleecode force-pushed the json-rpc-effect-bindings branch 2 times, most recently from 43010a8 to 7f27ec1 Compare May 4, 2024 17:00
@ryanleecode ryanleecode force-pushed the json-rpc-effect-bindings branch 3 times, most recently from db7734e to 58f1b5a Compare May 6, 2024 00:26
@ryanleecode ryanleecode changed the title feat: json rpc effect bindings light client experimental May 6, 2024
@ryanleecode ryanleecode changed the base branch from feat/smoldot-effect-bindings to main May 6, 2024 00:39
@ryanleecode ryanleecode force-pushed the json-rpc-effect-bindings branch 4 times, most recently from 08f3132 to 0651f5e Compare May 6, 2024 03:15
@ryanleecode ryanleecode marked this pull request as ready for review May 7, 2024 17:58
Comment on lines +1 to +3
export * from "./client"
export * from "./types"
export * from "./tasks"
Copy link
Contributor

@jsdw jsdw May 20, 2024

Choose a reason for hiding this comment

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

I know that this pattern exists throughout the repo, but IMO I think it'd be better practice to be explicit about the exports from a package rather than use * exports (just so the library interface is obvious just looking at this root file and not needing to traverse other stuff :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah but I find its really easy to forget to add a new type that should get re-exported and then it gets missed during code review because people don't really pay attention to that.

For anything that should be kept 100% internal I like to use the @internal jsdoc tag and then with stripeInternal set true in your tsconfig, these definitions won't be included in the d.ts`

https://www.typescriptlang.org/tsconfig/#stripInternal

Copy link
Contributor

@jsdw jsdw May 21, 2024

Choose a reason for hiding this comment

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

Yup totally true; we forget to export types in Rust a fair bit, but personally I much prefer to forget exporting a type than to accidentally export a type I didn't mean to; it's easier to go one way than the other! But mainly it just makes it super easy at a glance to see what's being provided by the package.

TIL about @internal; that's cool to know about! Ultimately I'm not super fussed about this so happy to stick with the *'s + @internal's if you prefer that way around!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Gonna opt for the YOLO approach and just use @internal.

But if you want to actually see what the publicly export types are u can run corepack pnpm turbo build then open the dist folder and each of the the subpath exports will have a d.ts file in it showing the public api.

image

@ryanleecode
Copy link
Collaborator Author

I think this is ready to ship. Made a slight tweak to the superivse method to accept an abort signal instead of returning a stop function.

@ryanleecode
Copy link
Collaborator Author

Lets try to get 2 approvals on this so James + either one of @TarikGul / @marshacb

Comment on lines +72 to +77
if (options.abortSignal) {
options.abortSignal.addEventListener("abort", () => {
stopped = true
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: could move this next to the other options.abortSignal code so it's clear that we either bail immediately if stopped or add event to listen for stop if not already :)

Copy link
Contributor

@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.

LGTM from what I understand, and much more readable now! Good job :)

Copy link
Contributor

@marshacb marshacb left a comment

Choose a reason for hiding this comment

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

Solid PR! LGTM!

@ryanleecode ryanleecode merged commit f6f3ed0 into main May 22, 2024
13 checks passed
@ryanleecode ryanleecode deleted the json-rpc-effect-bindings branch May 22, 2024 13:16
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.

The extension gets "stuck" in the past
4 participants