From 4fde3673582ad3bf50c4a20809e43e1b60095b5b Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:43:00 +0200 Subject: [PATCH 1/7] docs: add code coverage doc --- doc/coverage.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 doc/coverage.md diff --git a/doc/coverage.md b/doc/coverage.md new file mode 100644 index 00000000..0e83513a --- /dev/null +++ b/doc/coverage.md @@ -0,0 +1,66 @@ +How to make a code coverage report + +1. Install [tarpaulin](https://github.com/xd009642/tarpaulin) + +``` +cargo install cargo-tarpaulin +``` + +1. Run the tests + + +``` +## Exclude ./web from coverage +## WARNING: Commit any changes made to ./web/* first, or they will be lost +rm -rf web/* + +export STARKNET_MAINNET_URL: https://starknet-mainnet.g.alchemy.com/starknet/version/rpc/v0_7/${ALCHEMY_KEY} +export STARKNET_SEPOLIA_URL: https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/${ALCHEMY_KEY} +BEERUS_TEST_RUN=1 cargo tarpaulin --out html + +## Restore content of ./web +git restore web +``` + +``` +2024-10-23T09:38:36.285998Z INFO cargo_tarpaulin::report: Coverage Results: +|| Tested/Total Lines: +|| src/client.rs: 9/63 +|| src/config.rs: 21/59 +|| src/eth.rs: 0/78 +|| src/exe/err.rs: 0/6 +|| src/exe/map.rs: 48/50 +|| src/exe/mod.rs: 75/127 +|| src/proof.rs: 86/157 +|| src/rpc.rs: 114/154 +|| src/util.rs: 13/14 +|| +51.69% coverage, 366/708 lines covered +``` + +1. Check out the report + +Open `tarpaulin-report.html` in a browser. + +1. Update report (optional) + +``` +mv tarpaulin-report.html coverage.html +rm doc/coverage.html +mv coverage.html doc/ + +git add doc/coverage.html +git commit -m 'docs(cov): update coverage report' +``` + +1. Alternative coverage (optional) + +Use [llvm-cov](https://github.com/taiki-e/cargo-llvm-cov): + +``` +cargo +stable install cargo-llvm-cov --locked + +export STARKNET_MAINNET_URL: https://starknet-mainnet.g.alchemy.com/starknet/version/rpc/v0_7/${ALCHEMY_KEY} +export STARKNET_SEPOLIA_URL: https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/${ALCHEMY_KEY} +BEERUS_TEST_RUN=1 cargo llvm-cov --html +``` From e9f9edd667244c37503d20354ffa60294fc986d7 Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:43:57 +0200 Subject: [PATCH 2/7] chore(cov): exclude `bin/beerus` & `gen.rs` --- Cargo.toml | 3 +++ src/bin/beerus.rs | 2 ++ src/lib.rs | 3 +++ 3 files changed, 8 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 566762d4..55386798 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,3 +79,6 @@ wiremock = "0.6.2" [patch.crates-io] starknet-core = { git = "https://github.com/kariy/starknet-rs", branch = "dojo-patch" } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] } diff --git a/src/bin/beerus.rs b/src/bin/beerus.rs index 92beea43..127263e3 100644 --- a/src/bin/beerus.rs +++ b/src/bin/beerus.rs @@ -7,6 +7,7 @@ use beerus::{ use tokio::sync::RwLock; use validator::Validate; +#[cfg(not(tarpaulin_include))] // exclude from code-coverage report #[tokio::main] async fn main() -> eyre::Result<()> { tracing_subscriber::fmt::init(); @@ -56,6 +57,7 @@ async fn main() -> eyre::Result<()> { Ok(()) } +#[cfg(not(tarpaulin_include))] // exclude from code-coverage report async fn get_config() -> eyre::Result { let path = std::env::args().nth(1); let config = if let Some(path) = path { diff --git a/src/lib.rs b/src/lib.rs index f74ccb81..9230fc91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,10 @@ pub mod client; pub mod config; pub mod eth; pub mod exe; + +#[cfg(not(tarpaulin_include))] // exclude from code-coverage report pub mod gen; + pub mod proof; #[cfg(not(target_arch = "wasm32"))] From 5655fd9e0ebf677f7e08523e1903da7c66a6adde Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:44:33 +0200 Subject: [PATCH 3/7] docs(cov): add coverage report --- doc/coverage.html | 671 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 doc/coverage.html diff --git a/doc/coverage.html b/doc/coverage.html new file mode 100644 index 00000000..3301fc5f --- /dev/null +++ b/doc/coverage.html @@ -0,0 +1,671 @@ + + + + + + + +
+ + + + + + \ No newline at end of file From 9b5dce6f8048623f905f24c7785590a4d1c2253b Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:04:52 +0200 Subject: [PATCH 4/7] doc: add architecture overview --- doc/architecture.md | 114 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 doc/architecture.md diff --git a/doc/architecture.md b/doc/architecture.md new file mode 100644 index 00000000..457b0482 --- /dev/null +++ b/doc/architecture.md @@ -0,0 +1,114 @@ +Beerus Architecture Overview +============================ + +## Components + +* Beerus client library (`src/client.rs`) +* Beerus RPC server + - Based on `axum` HTTP server + - RPC impl (`src/rpc.rs`) +* JSON-RPC spec (generated code: `src/gen.rs`) + - Starknet spec 0.7.1 (`etc/spec/starknet/0.7.1`) + - Generated by `iamgroot` (Rust DTO codegen tool) +* Ethereum client (`src/eth.rs`) + - Based on `helios` Ethereum light client +* Merkle proof check (`src/proof.rs`) +* Stateless execution (`src/exe/mod.rs`) + - `blockifier` + - `cairo-vm` + - `cairo-lang-*` +* WebAssembly library (`web/beerus-web`) + +## Execution + +### Get current state + +```mermaid +sequenceDiagram +Beerus->>Helios: Start +loop Sync +Helios->>(Beacon Chain): Query Beacon Chain +(Beacon Chain)->>Helios: Beacon Chain data +end +Note right of Helios: Helios is ready +Helios->>Beerus: Synced +Note right of Beerus: Beerus is ready +Beerus->>Helios: Query State +Beerus->>Helios: Get Latest Block +Helios->>(Ethereum RPC): Get Latest Block +(Ethereum RPC)->>Helios: Latest Block Number +Helios->>Beerus: Latest Block Number + +Beerus->>Helios: Call stateBlockNumber() +Helios->>(Ethereum RPC): Call Starknet Core Contract +(Ethereum RPC)->>Helios: Get Result +Helios->>Beerus: Get Result + +Beerus->>Helios: Call stateBlockHash() +Helios->>(Ethereum RPC): Call Starknet Core Contract +(Ethereum RPC)->>Helios: Get Result +Helios->>Beerus: Get Result + +Beerus->>Helios: Call stateRoot() +Helios->>(Ethereum RPC): Call Starknet Core Contract +(Ethereum RPC)->>Helios: Get Result +Helios->>Beerus: Get Result + +Beerus->>Beerus: Store Current State +``` + +### Stateless call (RPC) + +```mermaid +sequenceDiagram +(RPC Server)->>Beerus: starknet_call +Beerus->>Beerus: Check current state +Beerus->>Blockifier: Prepare execution context +Blockifier->>Blockifier: Create Starknet client +Blockifier->>Blockifier: Create State reader & write +loop Stateless Execution +Blockifier->>State Reader: State Request +State Reader->>(Starknet RPC): Query State +(Starknet RPC)->>State Reader: State Result +State Reader->>(Starknet RPC): Query State Proof +(Starknet RPC)->>State Reader: State Proof +State Reader->>State Reader: Verify State Proof +State Reader->>Blockifier: State Result +end +Note right of (RPC Server): Other methods are proxied +(RPC Server)->>Beerus: starknet_* +Beerus->>(Starknet RPC): (proxy the request) +(Starknet RPC)->>Beerus: (proxy the response) +Beerus->>(RPC Server): response +``` + +### Stateless call (WASM) + +```mermaid +sequenceDiagram +(Browser)->>(Browser): Check Proxy +(Browser)->>Beerus: Init +Note right of Beerus: Beerus is set up to run in a WebWorker +Beerus->>(Browser): Ready +(Browser)->>Beerus: Call +Beerus->>Client: Inject post() function +Client->>Client: create blocking StateReader +Note right of Client: Blocking StateReader is required by Blockifier +Client->>Client: create async StateReader +Client->>Beerus: Ready +Beerus->>Blockifier: Execute call +loop Stateless Execution +Blockifier->>Client: State Request +Client->>(Starknet RPC): State Request +(Starknet RPC)->>Client: State Result +Client->>(Starknet RPC): Get State Proof +(Starknet RPC)->>Client: State Proof +Client->>Client: Verify State Proof +Client->>Blockifier: State Result +end +Blockifier->>Beerus: Call Result +``` + +Beerus allows Blockifier to execute calls in a stateless manner by providing implementation of a `StateReader`. The `StateReader` implementation fetches necessary state (the value for the provided key to be exact) directly from Starknet RPC (and then pulls merkle proof for the value and verifies that it is valid). Thus during call execution Beerus has no control over which specific RPC methods are being called and how often - it depends on Blockifier and specific execution context of the call (contract & method that are being executed). + +Beerus workload is purely IO bound, as the only computation being performed is the verification of a merkle proof for a received key-value pairs. Thus performance of the stateless call execution depends on latency and frequency of RPC calls performed by Blockifier. From f5b4db7fdacc76e26fa66df551e51d8abf00e80b Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:05:10 +0200 Subject: [PATCH 5/7] chore(typos): exclude coverage report --- _typos.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/_typos.toml b/_typos.toml index 390f8188..68561c36 100644 --- a/_typos.toml +++ b/_typos.toml @@ -1,2 +1,7 @@ [default.extend-words] wrk = "wrk" + +[files] +extend-exclude = [ + "coverage.html", +] From b24bd431d40bf79b7cea93ffa8f7b562a21e2dae Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:21:56 +0200 Subject: [PATCH 6/7] style: clippy --- src/gen.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gen.rs b/src/gen.rs index 17b5b987..e8cbdcc4 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -4,6 +4,7 @@ pub use gen::*; #[allow(clippy::module_inception)] #[allow(non_snake_case)] #[allow(clippy::enum_variant_names)] +#[allow(clippy::large_enum_variant)] pub mod gen { use serde::{Deserialize, Serialize}; use serde_json::Value; From e233e0c38f583db60e1104fe7eead4c9b8d05e64 Mon Sep 17 00:00:00 2001 From: sergey-melnychuk <8093171+sergey-melnychuk@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:45:48 +0200 Subject: [PATCH 7/7] doc: update stateless call diagram --- doc/architecture.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/architecture.md b/doc/architecture.md index 457b0482..d3924e46 100644 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -68,13 +68,20 @@ Blockifier->>Blockifier: Create Starknet client Blockifier->>Blockifier: Create State reader & write loop Stateless Execution Blockifier->>State Reader: State Request -State Reader->>(Starknet RPC): Query State -(Starknet RPC)->>State Reader: State Result -State Reader->>(Starknet RPC): Query State Proof -(Starknet RPC)->>State Reader: State Proof -State Reader->>State Reader: Verify State Proof +State Reader->>(Starknet RPC): starknet_getStorageAt +(Starknet RPC)->>State Reader: storage result +State Reader->>(Starknet RPC): pathfinder_getProof +(Starknet RPC)->>State Reader: merkle proof +State Reader->>State Reader: verify merkle proof State Reader->>Blockifier: State Result end + +(RPC Server)->>Beerus: starknet_getStorageAt +Beerus->>(Starknet RPC): pathfinder_getProof +(Starknet RPC)->>Beerus: merkle proof +Beerus->>Beerus: verify merkle proof +Beerus->>(RPC Server): storage result + Note right of (RPC Server): Other methods are proxied (RPC Server)->>Beerus: starknet_* Beerus->>(Starknet RPC): (proxy the request)