dip icon indicating copy to clipboard operation
dip copied to clipboard

Add StarknetLightClientPlugin

Open JunichiSugiura opened this issue 2 years ago • 6 comments

#145

Only Dust Tel Aviv Hacker Building Report

WTF is dip

Dip is a composable cross-platform application framework in Rust. It allows you build desktop apps, command line tools, games, and [WIP] web, mobile apps under the same scalable Entity Component System architecture. Unique point is that you can share logic between different platforms as a form of plugin. Transforming dip based desktop/web application into a 2D/3D game is as simple as swapping UI plugins targeting different platform. Your core logic stay the same no matter what platform you're targeting. Dip is based on a game engine called Bevy.

Scope of this PR

Provide StarknetLightClientPlugin that wraps Beerus and provide event driven interface for dip/bevy based developers. This is the first web3 plugin that dip offers besides Ledger device integration.

Demo

Very primitive demo of StarknetLightClientPlugin for Bevy game engine. It has desktop window made with React-like declarative UI (dip DesktopPlugin) with a button to fetch block number via Beerus.

I didn't have time to PoC yet but this plugin should also work in other platforms such as Bevy's 3D render plugins, dip CLIPlugin, etc.

  • UI window pops up around 1.20 mins. Please be patient while Beerus is synchronising :)

https://user-images.githubusercontent.com/8398372/216758739-73a2768e-97d3-42eb-90b2-0b23689c5b21.mp4

[TODO] Architecture

sequenceDiagram
    participant UI component (VirtualDOM)
    participant Bevy ECS
    participant Light client (Beerus)

Things to improve in the future

Check my review comments for more details

  • Synchronisation of Beerus takes some time (around 1.20 mins). UI window should be rendered before staring a synchronisation and show some progress.
  • Right now, the RPC request can be trigger from UI but the result is only show in the console. There should be a global state that UI component can be listening to via custom hook, so it can re-render when the state changes.
// Super basic React-like UI component with a button to request block number via Beerus.

#[allow(non_snake_case)]
fn Root(cx: Scope) -> Element {
    let block_number = use_read(&cx, BLOCK_NUMBER); // <- Reading global state via custom hook

    let window = use_window::<UiAction, NoAsyncAction>(&cx); // <- to delegate action to ECS thread

   // rsx macro is the new jsx
    cx.render(rsx! {
        h1 { "Starknet Light Client (Beerus) Plugin Example" }
        
        p { "block_number: {block_number.value}" }

        button {
            onclick: move |_| window.send(UiAction::get_block_number()),
            "Get Block Number",
        }
    })
}

What's next

On this plugin (StraknetLightClientPlugin)

  • Support all JSON-RPC methods provided by Beerus.
  • Improve application startup time
  • Provide visual feedback on synchronisation progress
  • Expose Beerus response as a global state so UI component automatically re-renders when the state changes.

My initial intention for this experiment is to be used by Dojo project as a gaming client layer. As described in the previous section, the light client is still in a breeding edge. In the long-run, be able to verify on-chain data via Beerus light client provides great values because we don't have to trust untrusted data coming from full-node provider such as Alchemy or Infura. But for a sake of making playable games, we need more practical solution at least for now.

Apibara plugin

That being said, the next step for dip is to create another plugin that wraps Apibara Rust SDK which Dojo WG is already started working on. It requires game client to trust a server that Apibara is hosted but that would provide more realistic UX.

StarknetRsPlugin

Plugin to directly send JSON-RPC request to full-node without verification. You need to trust full-node provider but it's simpler than going through light client.

Auto Dojo <-> Bevy ECS synchronisation

The plugin should automatically sync on-chain ECS state with ECS on the client side (Bevy). As a gaming/application developer standpoint, they just query Entity/Component in Bevy instead of manually implementing logics to fetch data from the chain and store.

JunichiSugiura avatar Feb 01 '23 09:02 JunichiSugiura

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
dip ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Feb 4, 2023 at 7:48AM (UTC)

vercel[bot] avatar Feb 01 '23 09:02 vercel[bot]

Instant crash after starting beerus client. Things are going great.

Screenshot 2023-02-01 at 11 38 36

JunichiSugiura avatar Feb 01 '23 09:02 JunichiSugiura

Need to set data_dir config?

https://github.com/a16z/helios/blob/master/client/src/database.rs#L27...L36

Screenshot 2023-02-02 at 08 36 16

JunichiSugiura avatar Feb 02 '23 06:02 JunichiSugiura

This PR seems to fix the issue above.

https://github.com/keep-starknet-strange/beerus/pull/194

JunichiSugiura avatar Feb 02 '23 07:02 JunichiSugiura

BeerusLightClient has to be clonable in order to fit into Bevy. I need to work on their repo first (potentially helios too)

Workaround for now is to spawn thread and listening to rpc request events via mpsc channel. Get Res<Sender<RpcRequest>> from any system and emit rpc event.

JunichiSugiura avatar Feb 03 '23 09:02 JunichiSugiura

https://user-images.githubusercontent.com/8398372/216756431-0ecabaf9-e3b8-4ded-aae4-9872bb0c11f1.mp4

Improvement needed:

  • Takes time to sync full nodes on initialisation. Right now, synchronisation calls before desktop window starts, so not a good UX.
  • When click get_block_number button on UI, not it only logs result in console. need to think a way to update resources so that UI can listened to changes via custom hook.

Something like

// Super basic React-lie UI component
#[allow(non_snake_case)]
fn Root(cx: Scope) -> Element {
    let block_number = use_read(&cx, BLOCK_NUMBER);

    let window = use_window::<UiAction, NoAsyncAction>(&cx);

    cx.render(rsx! {
        h1 { "Starknet Light Client (Beerus) Plugin Example" }
        p { "block_number: {block_number.value}" }
        button {
            onclick: move |_| window.send(UiAction::get_block_number()),
            "Get Block Number",
        }
    })
}

JunichiSugiura avatar Feb 04 '23 07:02 JunichiSugiura