From d8db74ede9b37ad517c02443fa7aa502ce4cb0e4 Mon Sep 17 00:00:00 2001 From: sragss <65786432+sragss@users.noreply.github.com> Date: Thu, 8 Dec 2022 07:57:21 -0800 Subject: [PATCH 1/7] fix: surface eth_getStorageAt (#124) * feat: surface eth_getStorageAt * add blocktag * cargo fmt --- client/src/client.rs | 13 +++++++++++-- client/src/node.rs | 9 +++++++-- client/src/rpc.rs | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 23c435c..353cc1c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -344,8 +344,17 @@ impl Client { self.node.read().await.get_code(address, block).await } - pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result { - self.node.read().await.get_storage_at(address, slot).await + pub async fn get_storage_at( + &self, + address: &Address, + slot: H256, + block: BlockTag, + ) -> Result { + self.node + .read() + .await + .get_storage_at(address, slot, block) + .await } pub async fn send_raw_transaction(&self, bytes: &[u8]) -> Result { diff --git a/client/src/node.rs b/client/src/node.rs index fb98292..02d02af 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -163,10 +163,15 @@ impl Node { Ok(account.code) } - pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result { + pub async fn get_storage_at( + &self, + address: &Address, + slot: H256, + block: BlockTag, + ) -> Result { self.check_head_age()?; - let payload = self.get_payload(BlockTag::Latest)?; + let payload = self.get_payload(block)?; let account = self .execution .get_account(address, Some(&[slot]), payload) diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 93832c3..3f72c7b 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -94,6 +94,13 @@ trait EthRpc { async fn get_transaction_by_hash(&self, hash: &str) -> Result, Error>; #[method(name = "getLogs")] async fn get_logs(&self, filter: Filter) -> Result, Error>; + #[method(name = "getStorageAt")] + async fn get_storage_at( + &self, + address: &str, + slot: H256, + block: BlockTag, + ) -> Result; } #[rpc(client, server, namespace = "net")] @@ -227,6 +234,19 @@ impl EthRpcServer for RpcInner { let node = self.node.read().await; convert_err(node.get_logs(&filter).await) } + + async fn get_storage_at( + &self, + address: &str, + slot: H256, + block: BlockTag, + ) -> Result { + let address = convert_err(Address::from_str(address))?; + let node = self.node.read().await; + let storage = convert_err(node.get_storage_at(&address, slot, block).await)?; + + Ok(format_hex(&storage)) + } } #[async_trait] From f37aa2aa45d8f85c5bd4813b71acef62be83af03 Mon Sep 17 00:00:00 2001 From: Giovanni Vignone <72773059+giovannivignone@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:45:34 -0500 Subject: [PATCH 2/7] documentation: add rpc docs (#136) * adding documentation for rpc.md * adding rpc methods in table for rpc.md * adjusting readme to link to rpc.md * fixing grammar * grammar * adding RPC Methods according to documentation and listing column as Client Function * adding more description space * undoing description spacing --- README.md | 3 ++- rpc.md | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 rpc.md diff --git a/README.md b/README.md index b6129c8..3d51dd1 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,9 @@ helios --execution-rpc $ETH_RPC_URL Helios will now run a local RPC server at `http://127.0.0.1:8545`. -Helios also provides examples in the [`examples/`](./examples/) directory. To run an example, you can execute `cargo run --example ` from inside the helios repository. +Helios provides examples in the [`examples/`](./examples/) directory. To run an example, you can execute `cargo run --example ` from inside the helios repository. +Helios also provides documentation of its supported RPC methods in the [rpc.md](./rpc.md) file. ### Warning diff --git a/rpc.md b/rpc.md new file mode 100644 index 0000000..987a21e --- /dev/null +++ b/rpc.md @@ -0,0 +1,23 @@ +# Helios Remote Procedure Calls + +Helios provides a variety of RPC methods for interacting with the Ethereum network. These methods are exposed via the `Client` struct. The RPC methods follow the [Ethereum JSON RPC Spec](https://ethereum.github.io/execution-apis/api-documentation). See [examples](./examples/readme.rs) of running remote procedure calls with Helios. + +## RPC Methods + +| RPC Method | Client Function | Description | Example | +| ---------- | --------------- | ----------- | ------- | +| `eth_getBalance` | `get_balance` | Returns the balance of the account given an address. | `client.get_balance(&self, address: &str, block: BlockTag)` | +| `eth_getTransactionCount` | `get_transaction_count` | Returns the number of transactions sent from the given address. | `client.get_transaction_count(&self, address: &str, block: BlockTag)` | +| `eth_getCode` | `get_code` | Returns the code at a given address. | `client.get_code(&self, address: &str, block: BlockTag)` | +| `eth_call` | `call` | Executes a new message call immediately without creating a transaction on the blockchain. | `client.call(&self, opts: CallOpts, block: BlockTag)` | +| `eth_estimateGas` | `estimate_gas` | Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. | `client.estimate_gas(&self, opts: CallOpts)` | +| `eth_getChainId` | `chain_id` | Returns the chain ID of the current network. | `client.chain_id(&self)` | +| `eth_gasPrice` | `gas_price` | Returns the current price per gas in wei. | `client.gas_price(&self)` | +| `eth_maxPriorityFeePerGas` | `max_priority_fee_per_gas` | Returns the current max priority fee per gas in wei. | `client.max_priority_fee_per_gas(&self)` | +| `eth_blockNumber` | `block_number` | Returns the number of the most recent block. | `client.block_number(&self)` | +| `eth_getBlockByNumber` | `get_block_by_number` | Returns the information of a block by number. | `get_block_by_number(&self, block: BlockTag, full_tx: bool)` | +| `eth_getBlockByHash` | `get_block_by_hash` | Returns the information of a block by hash. | `get_block_by_hash(&self, hash: &str, full_tx: bool)` | +| `eth_sendRawTransaction` | `send_raw_transaction` | Submits a raw transaction to the network. | `client.send_raw_transaction(&self, bytes: &str)` | +| `eth_getTransactionReceipt` | `get_transaction_receipt` | Returns the receipt of a transaction by transaction hash. | `client.get_transaction_receipt(&self, hash: &str)` | +| `eth_getLogs` | `get_logs` | Returns an array of logs matching the filter. | `client.get_logs(&self, filter: Filter)` | +| `eth_getStorageAt` | `get_storage_at` | Returns the value from a storage position at a given address. | `client.get_storage_at(&self, address: &str, slot: H256, block: BlockTag)` | \ No newline at end of file From 94bf458d941f30e34faeaa7d2484898dba54234d Mon Sep 17 00:00:00 2001 From: "refcell.eth" Date: Sun, 11 Dec 2022 11:42:52 -0800 Subject: [PATCH 3/7] feat(benches): Criterion + Iai Benchmarking [RFC] (#131) * :gear: benches * :memo: docs * :building_construction: file_db benches and checkpoint fixes * :hammer: fix github action env vars * :white_check_mark: benchmark env vars * :gear: sync benchmarks * :sparkles: cargo fmt touchups --- .github/workflows/test.yml | 33 +- .gitignore | 2 + Cargo.lock | 699 ++++++++++++++++++++++++++++++++++++- Cargo.toml | 32 +- README.md | 13 +- benches/file_db.rs | 43 +++ benches/get_balance.rs | 63 ++++ benches/get_code.rs | 63 ++++ benches/harness.rs | 113 ++++++ benches/sync.rs | 81 +++++ client/src/database.rs | 18 +- config/src/checkpoints.rs | 41 ++- 12 files changed, 1167 insertions(+), 34 deletions(-) create mode 100644 benches/file_db.rs create mode 100644 benches/get_balance.rs create mode 100644 benches/get_code.rs create mode 100644 benches/harness.rs create mode 100644 benches/sync.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 295d046..1066a60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,12 +6,15 @@ on: pull_request: branches: [ "master" ] +env: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }} + jobs: check: - name: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -23,10 +26,9 @@ jobs: command: check test: - name: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -39,10 +41,9 @@ jobs: args: --all fmt: - name: fmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -55,11 +56,25 @@ jobs: command: fmt args: --all -- --check - clippy: - name: clippy + benches: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt + - uses: Swatinem/rust-cache@v2 + - uses: actions-rs/cargo@v1 + with: + command: bench + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: profile: minimal diff --git a/.gitignore b/.gitignore index ea8c4bf..5868362 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target + +*.env diff --git a/Cargo.lock b/Cargo.lock index 98e05a9..88ad67b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,12 @@ dependencies = [ "regex", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aes" version = "0.8.2" @@ -52,6 +58,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anyhow" version = "1.0.66" @@ -105,7 +117,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -350,6 +362,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + [[package]] name = "byteorder" version = "1.4.3" @@ -391,12 +409,18 @@ checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.14", "serde", "serde_json", "thiserror", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.0.77" @@ -424,6 +448,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.3" @@ -510,6 +561,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "cmake" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +dependencies = [ + "cc", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -577,6 +637,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "common" version = "0.1.0" @@ -635,6 +701,12 @@ dependencies = [ "toml", ] +[[package]] +name = "const-cstr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" + [[package]] name = "const-oid" version = "0.9.1" @@ -666,6 +738,43 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -675,6 +784,96 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "futures", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "tokio", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -825,6 +1024,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.7" @@ -836,12 +1045,44 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + [[package]] name = "dunce" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "ecdsa" version = "0.14.8" @@ -1125,7 +1366,7 @@ dependencies = [ "ethers-core", "getrandom 0.2.8", "reqwest", - "semver", + "semver 1.0.14", "serde", "serde-aux", "serde_json", @@ -1316,12 +1557,53 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-ord" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "font-kit" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fe28504d371085fae9ac7a3450f0b289ab71e07c8e57baa3fb68b9e57d6ce5" +dependencies = [ + "bitflags", + "byteorder", + "core-foundation", + "core-graphics", + "core-text", + "dirs-next", + "dwrote", + "float-ord", + "freetype", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -1346,6 +1628,27 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "freetype" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6" +dependencies = [ + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + [[package]] name = "funty" version = "2.0.0" @@ -1528,6 +1831,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gif" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "glob" version = "0.3.0" @@ -1622,6 +1935,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hash-db" version = "0.15.2" @@ -1660,19 +1979,24 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "helios" -version = "0.1.1" +version = "0.1.2" dependencies = [ "client", "common", "config", "consensus", + "criterion", "env_logger", "ethers", "execution", "eyre", + "hex", "home", "log", + "plotters", + "tempfile", "tokio", + "tracing-test", ] [[package]] @@ -1835,6 +2159,21 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "image" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", +] + [[package]] name = "impl-codec" version = "0.4.2" @@ -1958,12 +2297,27 @@ version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + [[package]] name = "js-sys" version = "0.3.60" @@ -2204,6 +2558,16 @@ version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "link-cplusplus" version = "1.0.7" @@ -2232,12 +2596,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" @@ -2254,6 +2636,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.5" @@ -2296,6 +2687,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num" version = "0.4.0" @@ -2409,6 +2810,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -2507,6 +2914,12 @@ version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parity-scale-codec" version = "1.3.7" @@ -2610,6 +3023,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" +dependencies = [ + "rustc_version 0.3.3", +] + [[package]] name = "pbkdf2" version = "0.11.0" @@ -2651,6 +3083,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pest" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +dependencies = [ + "thiserror", + "ucd-trie", +] + [[package]] name = "pharos" version = "0.5.3" @@ -2658,7 +3100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -2718,6 +3160,64 @@ dependencies = [ "crunchy", ] +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "chrono", + "font-kit", + "image", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-bitmap" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4a1f21490a6cf4a84c272ad20bd7844ed99a3178187a4c5ab7f2051295beef" +dependencies = [ + "gif", + "image", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2900,6 +3400,29 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rayon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +dependencies = [ + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2931,6 +3454,15 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.28" @@ -3148,13 +3680,22 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.14", ] [[package]] @@ -3343,6 +3884,15 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.14" @@ -3352,6 +3902,15 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "send_wrapper" version = "0.4.0" @@ -3489,6 +4048,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -3729,6 +4297,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -3767,6 +4344,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3905,6 +4492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -3917,6 +4505,58 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-test" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3d272c44878d2bbc9f4a20ad463724f03e19dbc667c6e84ac433ab7ffcc70b" +dependencies = [ + "lazy_static", + "tracing-core", + "tracing-subscriber", + "tracing-test-macro", +] + +[[package]] +name = "tracing-test-macro" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744324b12d69a9fc1edea4b38b7b1311295b662d161ad5deac17bb1358224a08" +dependencies = [ + "lazy_static", + "quote", + "syn", +] + [[package]] name = "triehash" version = "0.8.4" @@ -3943,12 +4583,24 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +[[package]] +name = "ttf-parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" + [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + [[package]] name = "uint" version = "0.8.5" @@ -4063,6 +4715,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4230,6 +4888,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "which" version = "4.3.0" @@ -4381,6 +5045,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "ws_stream_wasm" version = "0.7.3" @@ -4391,7 +5064,7 @@ dependencies = [ "futures", "js-sys", "pharos", - "rustc_version", + "rustc_version 0.4.0", "send_wrapper 0.5.0", "thiserror", "wasm-bindgen", @@ -4414,6 +5087,18 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yeslogic-fontconfig-sys" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" +dependencies = [ + "const-cstr", + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "zeroize" version = "1.5.7" diff --git a/Cargo.toml b/Cargo.toml index e099335..3e617cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "helios" -version = "0.1.1" +version = "0.1.2" edition = "2021" +autobenches = false [workspace] - members = [ "cli", "client", @@ -28,6 +28,15 @@ home = "0.5.4" ethers = "1.0.2" env_logger = "0.9.0" log = "0.4.17" +tracing-test = "0.2.3" +criterion = { version = "0.4", features = [ "async_tokio", "plotters" ]} +plotters = "0.3.3" +tempfile = "3.3.0" +hex = "0.4.3" + +###################################### +# Examples +###################################### [[example]] name = "checkpoints" @@ -45,3 +54,22 @@ path = "examples/client.rs" name = "config" path = "examples/config.rs" +###################################### +# Benchmarks +###################################### + +[[bench]] +name = "file_db" +harness = false + +[[bench]] +name = "get_balance" +harness = false + +[[bench]] +name = "get_code" +harness = false + +[[bench]] +name = "sync" +harness = false diff --git a/README.md b/README.md index 3d51dd1..633cef4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ Helios converts an untrusted centralized RPC endpoint into a safe unmanipulable The entire size of Helios's binary is 13Mb and should be easy to compile into WebAssembly. This makes it a perfect target to embed directly inside wallets and dapps. - ## Installing First install `heliosup`, Helios's installer: @@ -19,7 +18,6 @@ curl https://raw.githubusercontent.com/a16z/helios/master/heliosup/install | bas To install Helios, run `heliosup`. - ## Usage To run Helios, run the below command, replacing `$ETH_RPC_URL` with an RPC provider URL such as Alchemy or Infura: @@ -40,7 +38,6 @@ Helios also provides documentation of its supported RPC methods in the [rpc.md]( Helios is still experimental software. While we hope you try it out, we do not suggest adding it as your main RPC in wallets yet. Sending high-value transactions from a wallet connected to Helios is discouraged. - ### Additional Options `--consensus-rpc` or `-c` can be used to set a custom consensus layer rpc endpoint. This must be a consenus node that supports the light client beaconchain api. We recommend using Nimbus for this. If no consensus rpc is supplied, it defaults to `https://www.lightclientdata.org` which is run by us. @@ -68,7 +65,6 @@ This can be run like so: `helios --load-external-fallback` (or `helios -l` with `--help` or `-h` prints the help message. - ### Configuration Files All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file: @@ -85,7 +81,6 @@ execution_rpc = "https://eth-goerli.g.alchemy.com/v2/XXXXX" checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495" ``` - ### Using Helios as a Library Helios can be imported into any Rust project. Helios requires the Rust nightly toolchain to compile. @@ -148,16 +143,20 @@ async fn main() -> Result<()> { } ``` +## Benchmarks + +Benchmarks are defined in the [benches](./benches/) subdirectory. They are built using the [criterion](https://github.com/bheisler/criterion.rs) statistics-driven benchmarking library. + +To run all benchmarks, you can use `cargo bench`. To run a specific benchmark, you can use `cargo bench --bench `, where `` is one of the benchmarks defined in the [Cargo.toml](./Cargo.toml) file under a `[[bench]]` section. + ## Contributing All contributions to Helios are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the nightly rust toolchain, has been linted with `cargo fmt`, and contains tests when applicable. - ## Telegram If you are having trouble with Helios or are considering contributing, feel free to join our telegram [here](https://t.me/+IntDY_gZJSRkNTJj). - ## Disclaimer _This code is being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the code. It has not been audited and as such there can be no assurance it will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. Nothing in this repo should be construed as investment advice or legal advice for any particular facts or circumstances and is not meant to replace competent counsel. It is strongly advised for you to contact a reputable attorney in your jurisdiction for any questions or concerns with respect thereto. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/benches/file_db.rs b/benches/file_db.rs new file mode 100644 index 0000000..6d0baec --- /dev/null +++ b/benches/file_db.rs @@ -0,0 +1,43 @@ +use client::database::Database; +use criterion::{criterion_group, criterion_main, Criterion}; +use helios::prelude::FileDB; +use tempfile::tempdir; + +mod harness; + +criterion_main!(file_db); +criterion_group! { + name = file_db; + config = Criterion::default(); + targets = save_checkpoint, load_checkpoint +} + +/// Benchmark saving/writing a checkpoint to the file db. +pub fn save_checkpoint(c: &mut Criterion) { + c.bench_function("save_checkpoint", |b| { + let checkpoint = vec![1, 2, 3]; + b.iter(|| { + let temp_dir = tempdir().unwrap().into_path(); + let db = FileDB::new(temp_dir); + db.save_checkpoint(checkpoint.clone()).unwrap(); + }) + }); +} + +/// Benchmark loading a checkpoint from the file db. +pub fn load_checkpoint(c: &mut Criterion) { + c.bench_function("load_checkpoint", |b| { + // First write to the db + let temp_dir = tempdir().unwrap().into_path(); + let db = FileDB::new(temp_dir.clone()); + let written_checkpoint = vec![1, 2, 3]; + db.save_checkpoint(written_checkpoint.clone()).unwrap(); + + // Then read from the db + b.iter(|| { + let db = FileDB::new(temp_dir.clone()); + let checkpoint = db.load_checkpoint().unwrap(); + assert_eq!(checkpoint, written_checkpoint.clone()); + }) + }); +} diff --git a/benches/get_balance.rs b/benches/get_balance.rs new file mode 100644 index 0000000..19cd314 --- /dev/null +++ b/benches/get_balance.rs @@ -0,0 +1,63 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use ethers::prelude::*; +use helios::types::BlockTag; +use std::str::FromStr; + +mod harness; + +criterion_main!(get_balance); +criterion_group! { + name = get_balance; + config = Criterion::default().sample_size(10); + targets = bench_mainnet_get_balance, bench_goerli_get_balance +} + +/// Benchmark mainnet get balance. +/// Address: 0x00000000219ab540356cbb839cbe05303d7705fa (beacon chain deposit address) +pub fn bench_mainnet_get_balance(c: &mut Criterion) { + c.bench_function("get_balance", |b| { + // Create a new multi-threaded tokio runtime. + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + // Construct a mainnet client using our harness and tokio runtime. + let client = std::sync::Arc::new(harness::construct_mainnet_client(&rt).unwrap()); + + // Get the beacon chain deposit contract address. + let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa").unwrap(); + let block = BlockTag::Latest; + + // Execute the benchmark asynchronously. + b.to_async(rt).iter(|| async { + let inner = std::sync::Arc::clone(&client); + inner.get_balance(&addr, block).await.unwrap() + }) + }); +} + +/// Benchmark goerli get balance. +/// Address: 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6 (goerli weth) +pub fn bench_goerli_get_balance(c: &mut Criterion) { + c.bench_function("get_balance", |b| { + // Create a new multi-threaded tokio runtime. + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + // Construct a goerli client using our harness and tokio runtime. + let client = std::sync::Arc::new(harness::construct_goerli_client(&rt).unwrap()); + + // Get the beacon chain deposit contract address. + let addr = Address::from_str("0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6").unwrap(); + let block = BlockTag::Latest; + + // Execute the benchmark asynchronously. + b.to_async(rt).iter(|| async { + let inner = std::sync::Arc::clone(&client); + inner.get_balance(&addr, block).await.unwrap() + }) + }); +} diff --git a/benches/get_code.rs b/benches/get_code.rs new file mode 100644 index 0000000..f8dd900 --- /dev/null +++ b/benches/get_code.rs @@ -0,0 +1,63 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use ethers::prelude::*; +use helios::types::BlockTag; +use std::str::FromStr; + +mod harness; + +criterion_main!(get_code); +criterion_group! { + name = get_code; + config = Criterion::default().sample_size(10); + targets = bench_mainnet_get_code, bench_goerli_get_code +} + +/// Benchmark mainnet get code call. +/// Address: 0x00000000219ab540356cbb839cbe05303d7705fa (beacon chain deposit address) +pub fn bench_mainnet_get_code(c: &mut Criterion) { + c.bench_function("get_code", |b| { + // Create a new multi-threaded tokio runtime. + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + // Construct a mainnet client using our harness and tokio runtime. + let client = std::sync::Arc::new(harness::construct_mainnet_client(&rt).unwrap()); + + // Get the beacon chain deposit contract address. + let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa").unwrap(); + let block = BlockTag::Latest; + + // Execute the benchmark asynchronously. + b.to_async(rt).iter(|| async { + let inner = std::sync::Arc::clone(&client); + inner.get_code(&addr, block).await.unwrap() + }) + }); +} + +/// Benchmark goerli get code call. +/// Address: 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6 (goerli weth) +pub fn bench_goerli_get_code(c: &mut Criterion) { + c.bench_function("get_code", |b| { + // Create a new multi-threaded tokio runtime. + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + // Construct a goerli client using our harness and tokio runtime. + let client = std::sync::Arc::new(harness::construct_goerli_client(&rt).unwrap()); + + // Get the beacon chain deposit contract address. + let addr = Address::from_str("0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6").unwrap(); + let block = BlockTag::Latest; + + // Execute the benchmark asynchronously. + b.to_async(rt).iter(|| async { + let inner = std::sync::Arc::clone(&client); + inner.get_code(&addr, block).await.unwrap() + }) + }); +} diff --git a/benches/harness.rs b/benches/harness.rs new file mode 100644 index 0000000..1f9b069 --- /dev/null +++ b/benches/harness.rs @@ -0,0 +1,113 @@ +#![allow(dead_code)] + +use std::{str::FromStr, sync::Arc}; + +use ::client::Client; +use ethers::{ + abi::Address, + types::{H256, U256}, +}; +use helios::{client, config::networks, prelude::FileDB, types::BlockTag}; + +/// Fetches the latest mainnet checkpoint from the fallback service. +/// +/// Uses the [CheckpointFallback](config::CheckpointFallback). +/// The `build` method will fetch a list of [CheckpointFallbackService](config::CheckpointFallbackService)s from a community-mainained list by ethPandaOps. +/// This list is NOT guaranteed to be secure, but is provided in good faith. +/// The raw list can be found here: https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml +pub async fn fetch_mainnet_checkpoint() -> eyre::Result { + let cf = config::CheckpointFallback::new().build().await.unwrap(); + cf.fetch_latest_checkpoint(&networks::Network::MAINNET) + .await +} + +/// Constructs a mainnet [Client](client::Client) for benchmark usage. +/// +/// Requires a [Runtime](tokio::runtime::Runtime) to be passed in by reference. +/// The client is parameterized with a [FileDB](client::FileDB). +/// It will also use the environment variable `MAINNET_RPC_URL` to connect to a mainnet node. +/// The client will use `https://www.lightclientdata.org` as the consensus RPC. +pub fn construct_mainnet_client( + rt: &tokio::runtime::Runtime, +) -> eyre::Result> { + rt.block_on(inner_construct_mainnet_client()) +} + +pub async fn inner_construct_mainnet_client() -> eyre::Result> { + let benchmark_rpc_url = std::env::var("MAINNET_RPC_URL")?; + let mut client = client::ClientBuilder::new() + .network(networks::Network::MAINNET) + .consensus_rpc("https://www.lightclientdata.org") + .execution_rpc(&benchmark_rpc_url) + .load_external_fallback() + .build()?; + client.start().await?; + Ok(client) +} + +pub async fn construct_mainnet_client_with_checkpoint( + checkpoint: &str, +) -> eyre::Result> { + let benchmark_rpc_url = std::env::var("MAINNET_RPC_URL")?; + let mut client = client::ClientBuilder::new() + .network(networks::Network::MAINNET) + .consensus_rpc("https://www.lightclientdata.org") + .execution_rpc(&benchmark_rpc_url) + .checkpoint(checkpoint) + .build()?; + client.start().await?; + Ok(client) +} + +/// Create a tokio multi-threaded runtime. +/// +/// # Panics +/// +/// Panics if the runtime cannot be created. +pub fn construct_runtime() -> tokio::runtime::Runtime { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() +} + +/// Constructs a goerli client for benchmark usage. +/// +/// Requires a [Runtime](tokio::runtime::Runtime) to be passed in by reference. +/// The client is parameterized with a [FileDB](client::FileDB). +/// It will also use the environment variable `GOERLI_RPC_URL` to connect to a mainnet node. +/// The client will use `http://testing.prater.beacon-api.nimbus.team` as the consensus RPC. +pub fn construct_goerli_client( + rt: &tokio::runtime::Runtime, +) -> eyre::Result> { + rt.block_on(async { + let benchmark_rpc_url = std::env::var("GOERLI_RPC_URL")?; + let mut client = client::ClientBuilder::new() + .network(networks::Network::GOERLI) + .consensus_rpc("http://testing.prater.beacon-api.nimbus.team") + .execution_rpc(&benchmark_rpc_url) + .load_external_fallback() + .build()?; + client.start().await?; + Ok(client) + }) +} + +/// Gets the balance of the given address on mainnet. +pub fn get_balance( + rt: &tokio::runtime::Runtime, + client: Arc>, + address: &str, +) -> eyre::Result { + rt.block_on(async { + let block = BlockTag::Latest; + let address = Address::from_str(address)?; + client.get_balance(&address, block).await + }) +} + +// h/t @ https://github.com/smrpn +// rev: https://github.com/smrpn/casbin-rs/commit/7a0a75d8075440ee65acdac3ee9c0de6fcbd5c48 +pub fn await_future, T>(future: F) -> T { + tokio::runtime::Runtime::new().unwrap().block_on(future) +} diff --git a/benches/sync.rs b/benches/sync.rs new file mode 100644 index 0000000..dffe950 --- /dev/null +++ b/benches/sync.rs @@ -0,0 +1,81 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use ethers::types::Address; +use helios::types::BlockTag; + +mod harness; + +criterion_main!(sync); +criterion_group! { + name = sync; + config = Criterion::default().sample_size(10); + targets = + bench_full_sync, + bench_full_sync_with_call, + bench_full_sync_checkpoint_fallback, + bench_full_sync_with_call_checkpoint_fallback, +} + +/// Benchmark full client sync. +pub fn bench_full_sync(c: &mut Criterion) { + // Externally, let's fetch the latest checkpoint from our fallback service so as not to benchmark the checkpoint fetch. + let checkpoint = harness::await_future(harness::fetch_mainnet_checkpoint()).unwrap(); + let checkpoint = hex::encode(checkpoint); + + // On client construction, it will sync to the latest checkpoint using our fetched checkpoint. + c.bench_function("full_sync", |b| { + b.to_async(harness::construct_runtime()).iter(|| async { + let _client = std::sync::Arc::new( + harness::construct_mainnet_client_with_checkpoint(&checkpoint) + .await + .unwrap(), + ); + }) + }); +} + +/// Benchmark full client sync. +/// Address: 0x00000000219ab540356cbb839cbe05303d7705fa (beacon chain deposit address) +pub fn bench_full_sync_with_call(c: &mut Criterion) { + // Externally, let's fetch the latest checkpoint from our fallback service so as not to benchmark the checkpoint fetch. + let checkpoint = harness::await_future(harness::fetch_mainnet_checkpoint()).unwrap(); + let checkpoint = hex::encode(checkpoint); + + // On client construction, it will sync to the latest checkpoint using our fetched checkpoint. + c.bench_function("full_sync_call", |b| { + b.to_async(harness::construct_runtime()).iter(|| async { + let client = std::sync::Arc::new( + harness::construct_mainnet_client_with_checkpoint(&checkpoint) + .await + .unwrap(), + ); + let addr = "0x00000000219ab540356cbb839cbe05303d7705fa" + .parse::
() + .unwrap(); + let block = BlockTag::Latest; + client.get_balance(&addr, block).await.unwrap() + }) + }); +} + +/// Benchmark full client sync with checkpoint fallback. +pub fn bench_full_sync_checkpoint_fallback(c: &mut Criterion) { + c.bench_function("full_sync_fallback", |b| { + let rt = harness::construct_runtime(); + b.iter(|| { + let _client = std::sync::Arc::new(harness::construct_mainnet_client(&rt).unwrap()); + }) + }); +} + +/// Benchmark full client sync with a call and checkpoint fallback. +/// Address: 0x00000000219ab540356cbb839cbe05303d7705fa (beacon chain deposit address) +pub fn bench_full_sync_with_call_checkpoint_fallback(c: &mut Criterion) { + c.bench_function("full_sync_call", |b| { + let addr = "0x00000000219ab540356cbb839cbe05303d7705fa"; + let rt = harness::construct_runtime(); + b.iter(|| { + let client = std::sync::Arc::new(harness::construct_mainnet_client(&rt).unwrap()); + harness::get_balance(&rt, client, addr).unwrap(); + }) + }); +} diff --git a/client/src/database.rs b/client/src/database.rs index 48373b2..3736f93 100644 --- a/client/src/database.rs +++ b/client/src/database.rs @@ -1,9 +1,14 @@ -use std::{fs, io::Write, path::PathBuf}; +use std::{ + fs, + io::{Read, Write}, + path::PathBuf, +}; use eyre::Result; pub trait Database { fn save_checkpoint(&self, checkpoint: Vec) -> Result<()>; + fn load_checkpoint(&self) -> Result>; } pub struct FileDB { @@ -30,4 +35,15 @@ impl Database for FileDB { Ok(()) } + + fn load_checkpoint(&self) -> Result> { + let mut f = fs::OpenOptions::new() + .read(true) + .open(self.data_dir.join("checkpoint"))?; + + let mut buf = Vec::new(); + f.read_to_end(&mut buf)?; + + Ok(buf) + } } diff --git a/config/src/checkpoints.rs b/config/src/checkpoints.rs index 827cac6..65fe45a 100644 --- a/config/src/checkpoints.rs +++ b/config/src/checkpoints.rs @@ -117,10 +117,18 @@ impl CheckpointFallback { &self, network: &crate::networks::Network, ) -> eyre::Result { - let services = &self.services[network]; + let services = &self.get_healthy_fallback_services(network); Self::fetch_latest_checkpoint_from_services(&services[..]).await } + async fn query_service(endpoint: &str) -> Option { + let client = reqwest::Client::new(); + let constructed_url = Self::construct_url(endpoint); + let res = client.get(&constructed_url).send().await.ok()?; + let raw: RawSlotResponse = res.json().await.ok()?; + Some(raw) + } + /// Fetch the latest checkpoint from a list of checkpoint fallback services. pub async fn fetch_latest_checkpoint_from_services( services: &[CheckpointFallbackService], @@ -131,14 +139,15 @@ impl CheckpointFallback { .map(|service| { let service = service.clone(); tokio::spawn(async move { - let client = reqwest::Client::new(); - let constructed_url = Self::construct_url(&service.endpoint); - let res = client.get(&constructed_url).send().await?; - let raw: RawSlotResponse = res.json().await?; - if raw.data.slots.is_empty() { - return Err(eyre::eyre!("no slots")); + match Self::query_service(&service.endpoint).await { + Some(raw) => { + if raw.data.slots.is_empty() { + return Err(eyre::eyre!("no slots")); + } + Ok(raw.data.slots[0].clone()) + } + None => Err(eyre::eyre!("failed to query service")), } - Ok(raw.data.slots[0].clone()) }) }) .collect(); @@ -230,6 +239,22 @@ impl CheckpointFallback { .collect() } + /// Returns a list of healthchecked checkpoint fallback services. + /// + /// ### Warning + /// + /// These services are not trustworthy and may act with malice by returning invalid checkpoints. + pub fn get_healthy_fallback_services( + &self, + network: &networks::Network, + ) -> Vec { + self.services[network] + .iter() + .filter(|service| service.state) + .cloned() + .collect::>() + } + /// Returns the raw checkpoint fallback service objects for a given network. pub fn get_fallback_services( &self, From c26e393b7d086bd6977939dabc4ab544b5c40925 Mon Sep 17 00:00:00 2001 From: Giovanni Vignone <72773059+giovannivignone@users.noreply.github.com> Date: Tue, 13 Dec 2022 19:19:36 -0500 Subject: [PATCH 4/7] feat: add tx length rpc methods (#142) * adding documentation for rpc.md * adding rpc methods in table for rpc.md * adjusting readme to link to rpc.md * fixing grammar * grammar * adding RPC Methods according to documentation and listing column as Client Function * adding more description space * undoing description spacing * adding get block transaction count by hash to node.rs and rpc.rs * functioning getblocktransactioncountbyhash function * removing documentation * adding second rpc method and simplifying logic * adjusting example and node.rs * formatting * fixing clippy errors * adding to client and to rpc.md * formatting * integrating into client * u64 return types, rpc.md updated to get_nonce, get_transaction_count -> get_nonce revert * cargo fmt --- client/src/client.rs | 14 ++++++++++++++ client/src/node.rs | 43 +++++++++++++++++++++++++++++++------------ client/src/rpc.rs | 22 ++++++++++++++++++++++ examples/readme.rs | 2 +- rpc.md | 6 ++++-- 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 353cc1c..6068987 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -340,6 +340,20 @@ impl Client { self.node.read().await.get_nonce(address, block).await } + pub async fn get_block_transaction_count_by_hash(&self, hash: &Vec) -> Result { + self.node + .read() + .await + .get_block_transaction_count_by_hash(hash) + } + + pub async fn get_block_transaction_count_by_number(&self, block: BlockTag) -> Result { + self.node + .read() + .await + .get_block_transaction_count_by_number(block) + } + pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result> { self.node.read().await.get_code(address, block).await } diff --git a/client/src/node.rs b/client/src/node.rs index 02d02af..7db7416 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -155,6 +155,20 @@ impl Node { Ok(account.nonce) } + pub fn get_block_transaction_count_by_hash(&self, hash: &Vec) -> Result { + let payload = self.get_payload_by_hash(hash)?; + let transaction_count = payload.1.transactions.len(); + + Ok(transaction_count as u64) + } + + pub fn get_block_transaction_count_by_number(&self, block: BlockTag) -> Result { + let payload = self.get_payload(block)?; + let transaction_count = payload.transactions.len(); + + Ok(transaction_count as u64) + } + pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result> { self.check_blocktag_age(&block)?; @@ -248,19 +262,11 @@ impl Node { hash: &Vec, full_tx: bool, ) -> Result> { - let payloads = self - .payloads - .iter() - .filter(|entry| &entry.1.block_hash.to_vec() == hash) - .collect::>(); + let payload = self.get_payload_by_hash(hash); - if let Some(payload_entry) = payloads.get(0) { - self.execution - .get_block(payload_entry.1, full_tx) - .await - .map(Some) - } else { - Ok(None) + match payload { + Ok(payload) => self.execution.get_block(payload.1, full_tx).await.map(Some), + Err(_) => Ok(None), } } @@ -296,6 +302,19 @@ impl Node { } } + fn get_payload_by_hash(&self, hash: &Vec) -> Result<(&u64, &ExecutionPayload)> { + let payloads = self + .payloads + .iter() + .filter(|entry| &entry.1.block_hash.to_vec() == hash) + .collect::>(); + + payloads + .get(0) + .cloned() + .ok_or(eyre!("Block not found by hash")) + } + fn check_head_age(&self) -> Result<(), NodeError> { let synced_slot = self.consensus.get_header().slot; let expected_slot = self.consensus.expected_current_slot(); diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 3f72c7b..34e9295 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -57,6 +57,11 @@ trait EthRpc { async fn get_balance(&self, address: &str, block: BlockTag) -> Result; #[method(name = "getTransactionCount")] async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result; + #[method(name = "getBlockTransactionCountByHash")] + async fn get_block_transaction_count_by_hash(&self, hash: &str) -> Result; + #[method(name = "getBlockTransactionCountByNumber")] + async fn get_block_transaction_count_by_number(&self, block: BlockTag) + -> Result; #[method(name = "getCode")] async fn get_code(&self, address: &str, block: BlockTag) -> Result; #[method(name = "call")] @@ -133,6 +138,23 @@ impl EthRpcServer for RpcInner { Ok(format!("0x{nonce:x}")) } + async fn get_block_transaction_count_by_hash(&self, hash: &str) -> Result { + let hash = convert_err(hex_str_to_bytes(hash))?; + let node = self.node.read().await; + let transaction_count = convert_err(node.get_block_transaction_count_by_hash(&hash))?; + + Ok(u64_to_hex_string(transaction_count)) + } + + async fn get_block_transaction_count_by_number( + &self, + block: BlockTag, + ) -> Result { + let node = self.node.read().await; + let transaction_count = convert_err(node.get_block_transaction_count_by_number(block))?; + Ok(u64_to_hex_string(transaction_count)) + } + async fn get_code(&self, address: &str, block: BlockTag) -> Result { let address = convert_err(Address::from_str(address))?; let node = self.node.read().await; diff --git a/examples/readme.rs b/examples/readme.rs index 24e4ddc..1c4d5ce 100644 --- a/examples/readme.rs +++ b/examples/readme.rs @@ -9,7 +9,7 @@ use helios::{client::ClientBuilder, config::networks::Network, types::BlockTag}; async fn main() -> Result<()> { env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); - let untrusted_rpc_url = "https://mainnet.infura.io/v3/"; + let untrusted_rpc_url = "https://eth-mainnet.g.alchemy.com/v2/"; log::info!("Using untrusted RPC URL [REDACTED]"); let consensus_rpc = "https://www.lightclientdata.org"; diff --git a/rpc.md b/rpc.md index 987a21e..07c5097 100644 --- a/rpc.md +++ b/rpc.md @@ -7,7 +7,7 @@ Helios provides a variety of RPC methods for interacting with the Ethereum netwo | RPC Method | Client Function | Description | Example | | ---------- | --------------- | ----------- | ------- | | `eth_getBalance` | `get_balance` | Returns the balance of the account given an address. | `client.get_balance(&self, address: &str, block: BlockTag)` | -| `eth_getTransactionCount` | `get_transaction_count` | Returns the number of transactions sent from the given address. | `client.get_transaction_count(&self, address: &str, block: BlockTag)` | +| `eth_getTransactionCount` | `get_nonce` | Returns the number of transactions sent from the given address. | `client.get_nonce(&self, address: &str, block: BlockTag)` | | `eth_getCode` | `get_code` | Returns the code at a given address. | `client.get_code(&self, address: &str, block: BlockTag)` | | `eth_call` | `call` | Executes a new message call immediately without creating a transaction on the blockchain. | `client.call(&self, opts: CallOpts, block: BlockTag)` | | `eth_estimateGas` | `estimate_gas` | Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. | `client.estimate_gas(&self, opts: CallOpts)` | @@ -20,4 +20,6 @@ Helios provides a variety of RPC methods for interacting with the Ethereum netwo | `eth_sendRawTransaction` | `send_raw_transaction` | Submits a raw transaction to the network. | `client.send_raw_transaction(&self, bytes: &str)` | | `eth_getTransactionReceipt` | `get_transaction_receipt` | Returns the receipt of a transaction by transaction hash. | `client.get_transaction_receipt(&self, hash: &str)` | | `eth_getLogs` | `get_logs` | Returns an array of logs matching the filter. | `client.get_logs(&self, filter: Filter)` | -| `eth_getStorageAt` | `get_storage_at` | Returns the value from a storage position at a given address. | `client.get_storage_at(&self, address: &str, slot: H256, block: BlockTag)` | \ No newline at end of file +| `eth_getStorageAt` | `get_storage_at` | Returns the value from a storage position at a given address. | `client.get_storage_at(&self, address: &str, slot: H256, block: BlockTag)` | +| `eth_getBlockTransactionCountByHash` | `get_block_transaction_count_by_hash` | Returns the number of transactions in a block from a block matching the transaction hash. | `client.get_block_transaction_count_by_hash(&self, hash: &str)` | +| `eth_getBlockTransactionCountByNumber` | `get_block_transaction_count_by_number` | Returns the number of transactions in a block from a block matching the block number. | `client.get_block_transaction_count_by_number(&self, block: BlockTag)` | \ No newline at end of file From 56f9d89525692f686495a5728a133cce0390972a Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Tue, 13 Dec 2022 20:22:53 -0500 Subject: [PATCH 5/7] fix(ci): move benchmark ci to separate action (#143) --- .github/workflows/benchmarks.yml | 25 +++++++++++++++++++++++++ .github/workflows/test.yml | 19 ------------------- 2 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/benchmarks.yml diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 0000000..4507a62 --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,25 @@ +name: benchmarks + +on: + push: + branches: [ "master" ] + +env: + MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }} + +jobs: + benches: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt + - uses: Swatinem/rust-cache@v2 + - uses: actions-rs/cargo@v1 + with: + command: bench diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1066a60..9f0a89c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,10 +6,6 @@ on: pull_request: branches: [ "master" ] -env: - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }} - jobs: check: runs-on: ubuntu-latest @@ -56,21 +52,6 @@ jobs: command: fmt args: --all -- --check - benches: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt - - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 - with: - command: bench - clippy: runs-on: ubuntu-latest steps: From 4707a0a9d4b2c8f6714d1a5ac7f000f8fcf8e8df Mon Sep 17 00:00:00 2001 From: "refcell.eth" Date: Tue, 13 Dec 2022 22:10:24 -0700 Subject: [PATCH 6/7] feat(docs): Config (#140) * :memo: comprehensive config options * :hammer: remove forks and chain parameters --- README.md | 3 +++ config.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 config.md diff --git a/README.md b/README.md index 633cef4..44bbe6a 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,9 @@ execution_rpc = "https://eth-goerli.g.alchemy.com/v2/XXXXX" checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495" ``` +A comprehensive breakdown of config options is available in the [config.md](./config.md) file. + + ### Using Helios as a Library Helios can be imported into any Rust project. Helios requires the Rust nightly toolchain to compile. diff --git a/config.md b/config.md new file mode 100644 index 0000000..33f6ba4 --- /dev/null +++ b/config.md @@ -0,0 +1,74 @@ +## Helios Configuration + +All configuration options can be set on a per-network level in `~/.helios/helios.toml`. + +#### Comprehensive Example + +```toml +[mainnet] +# The consensus rpc to use. This should be a trusted rpc endpoint. Defaults to "https://www.lightclientdata.org". +consensus_rpc = "https://www.lightclientdata.org" +# [REQUIRED] The execution rpc to use. This should be a trusted rpc endpoint. +execution_rpc = "https://eth-mainnet.g.alchemy.com/v2/XXXXX" +# The port to run the JSON-RPC server on. By default, Helios will use port 8545. +rpc_port = 8545 +# The latest checkpoint. This should be a trusted checkpoint that is no greater than ~2 weeks old. +# If you are unsure what checkpoint to use, you can skip this option and set either `load_external_fallback` or `fallback` values (described below) to fetch a checkpoint. Though this is not recommended and less secure. +checkpoint = "0x85e6151a246e8fdba36db27a0c7678a575346272fe978c9281e13a8b26cdfa68" +# The directory to store the checkpoint database in. If not provided, Helios will use "~/.helios/data/mainnet", where `mainnet` is the network. +# It is recommended to set this directory to a persistent location mapped to a fast storage device. +data_dir = "/home/user/.helios/mainnet" +# The maximum age of a checkpoint in seconds. If the checkpoint is older than this, Helios will attempt to fetch a new checkpoint. +max_checkpoint_age = 86400 +# A checkpoint fallback is used if no checkpoint is provided or the given checkpoint is too old. +# This is expected to be a trusted checkpoint sync api (like provided in https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml). +fallback = "https://sync-mainnet.beaconcha.in" +# If no checkpoint is provided, or the checkpoint is too old, Helios will attempt to dynamically fetch a checkpoint from a maintained list of checkpoint sync apis. +# NOTE: This is an insecure feature and not recommended for production use. Checkpoint manipulation is possible. +load_external_fallback = true + +[goerli] +# The consensus rpc to use. This should be a trusted rpc endpoint. Defaults to Nimbus testnet. +consensus_rpc = "http://testing.prater.beacon-api.nimbus.team" +# [REQUIRED] The execution rpc to use. This should be a trusted rpc endpoint. +execution_rpc = "https://eth-goerli.g.alchemy.com/v2/XXXXX" +# The port to run the JSON-RPC server on. By default, Helios will use port 8545. +rpc_port = 8545 +# The latest checkpoint. This should be a trusted checkpoint that is no greater than ~2 weeks old. +# If you are unsure what checkpoint to use, you can skip this option and set either `load_external_fallback` or `fallback` values (described below) to fetch a checkpoint. Though this is not recommended and less secure. +checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495" +# The directory to store the checkpoint database in. If not provided, Helios will use "~/.helios/data/goerli", where `goerli` is the network. +# It is recommended to set this directory to a persistent location mapped to a fast storage device. +data_dir = "/home/user/.helios/goerli" +# The maximum age of a checkpoint in seconds. If the checkpoint is older than this, Helios will attempt to fetch a new checkpoint. +max_checkpoint_age = 86400 +# A checkpoint fallback is used if no checkpoint is provided or the given checkpoint is too old. +# This is expected to be a trusted checkpoint sync api (like provided in https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml). +fallback = "https://sync-goerli.beaconcha.in" +# If no checkpoint is provided, or the checkpoint is too old, Helios will attempt to dynamically fetch a checkpoint from a maintained list of checkpoint sync apis. +# NOTE: This is an insecure feature and not recommended for production use. Checkpoint manipulation is possible. +load_external_fallback = true +``` + + +#### Options + +All configuration options below are available on a per-network level, where network is specified by a header (eg `[mainnet]` or `[goerli]`). Many of these options can be configured through cli flags as well. See [README.md](./README.md#additional-options) or run `helios --help` for more information. + + +- `consensus_rpc` - The URL of the consensus RPC endpoint used to fetch the latest beacon chain head and sync status. This must be a consenus node that supports the light client beaconchain api. We recommend using Nimbus for this. If no consensus rpc is supplied, it defaults to `https://www.lightclientdata.org` which is run by us. + +- `execution_rpc` - The URL of the execution RPC endpoint used to fetch the latest execution chain head and sync status. This must be an execution node that supports the light client execution api. We recommend using Geth for this. + +- `rpc_port` - The port to run the JSON-RPC server on. By default, Helios will use port 8545. + +- `checkpoint` - The latest checkpoint. This should be a trusted checkpoint that is no greater than ~2 weeks old. If you are unsure what checkpoint to use, you can skip this option and set either `load_external_fallback` or `fallback` values (described below) to fetch a checkpoint. Though this is not recommended and less secure. + +- `data_dir` - The directory to store the checkpoint database in. If not provided, Helios will use "~/.helios/data/", where `` is the network. It is recommended to set this directory to a persistent location mapped to a fast storage device. + +- `max_checkpoint_age` - The maximum age of a checkpoint in seconds. If the checkpoint is older than this, Helios will attempt to fetch a new checkpoint. + +- `fallback` - A checkpoint fallback is used if no checkpoint is provided or the given checkpoint is too old. This is expected to be a trusted checkpoint sync api (eg https://sync-mainnet.beaconcha.in). An extensive list of checkpoint sync apis can be found here: https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml. + +- `load_external_fallback` - If no checkpoint is provided, or the checkpoint is too old, Helios will attempt to dynamically fetch a checkpoint from a maintained list of checkpoint sync apis. NOTE: This is an insecure feature and not recommended for production use. Checkpoint manipulation is possible. + From 9f53fc9bfcda22eab7953c75c680b62e584eff88 Mon Sep 17 00:00:00 2001 From: Mathieu <60658558+msaug@users.noreply.github.com> Date: Wed, 14 Dec 2022 17:43:43 +0100 Subject: [PATCH 7/7] chore: export ExecutionBlock type (#146) * export ExecutionBlock type * fix linting error * Format with cargo fmt --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 914e9f6..b54ebc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub mod config { pub mod types { pub use common::types::BlockTag; - pub use execution::types::CallOpts; + pub use execution::types::{CallOpts, ExecutionBlock}; } pub mod errors {