From 781cbbdb54033048b9a7df8e64dc3a5ba47cee59 Mon Sep 17 00:00:00 2001 From: Konstantin Zolotarev Date: Thu, 16 Jan 2025 20:07:38 +0200 Subject: [PATCH] Refactoring and updates (#19) * Switched to nightly rust * Fixed comments * Upgraded dependencies --- .github/workflows/release.docker.yml | 35 +- .github/workflows/release.yml | 52 +- .github/workflows/tests.yml | 27 +- .gitignore | 1 + .rustfmt.toml | 4 + Cargo.lock | 1609 +++++++++++------------ Cargo.toml | 15 +- Dockerfile | 12 +- README.md | 63 +- crates/scribe/Cargo.toml | 2 - crates/scribe/src/contract.rs | 306 ++--- crates/scribe/src/events_handler.rs | 815 ++++++------ crates/scribe/src/events_listener.rs | 335 +++-- crates/scribe/src/metrics.rs | 50 +- rust-toolchain.toml | 2 + src/main.rs | 1797 +++++++++++++------------- src/wallet.rs | 189 +-- 17 files changed, 2619 insertions(+), 2695 deletions(-) create mode 100644 .rustfmt.toml create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/release.docker.yml b/.github/workflows/release.docker.yml index 798e979..ff65c23 100644 --- a/.github/workflows/release.docker.yml +++ b/.github/workflows/release.docker.yml @@ -2,30 +2,27 @@ name: release-docker on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+" workflow_dispatch: {} jobs: docker-image-alpine: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest # https://docs.github.com/en/actions/reference/authentication-in-a-workflow permissions: - id-token: write - packages: write - contents: read + id-token: write + packages: write + contents: read timeout-minutes: 120 steps: - - - name: Checkout repository + - name: Checkout repository uses: actions/checkout@v3 with: fetch-depth: 1 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v2 - - - name: Docker meta alpine + - name: Docker meta alpine id: meta_alpine uses: docker/metadata-action@v4 with: @@ -38,23 +35,19 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - - name: Login to ghcr.io + - name: Login to ghcr.io uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - - name: Prepare Docker envs + - name: Prepare Docker envs shell: bash run: | echo "VERSION=${GITHUB_REF##*/v}" >> $GITHUB_ENV - - - name: Build and push (alpine) + - name: Build and push (alpine) uses: docker/build-push-action@v4 with: push: true @@ -63,4 +56,4 @@ jobs: file: ./Dockerfile tags: ${{ steps.meta_alpine.outputs.tags }} build-args: | - VERSION=${{ env.VERSION }} \ No newline at end of file + VERSION=${{ env.VERSION }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4d0b45d..7ba5dc2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: jobs: create-release: name: create-release - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest outputs: upload_url: ${{ steps.release.outputs.upload_url }} sws_version: ${{ env.SWS_VERSION }} @@ -66,64 +66,64 @@ jobs: # - windows-msvc-arm64 include: - build: linux-musl - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: x86_64-unknown-linux-musl - build: linux-musl-i686 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: i686-unknown-linux-musl - build: linux-musl-arm64 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: aarch64-unknown-linux-musl - build: linux-gnu - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: x86_64-unknown-linux-gnu - build: linux-gnu-i686 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: i686-unknown-linux-gnu - build: linux-gnu-arm64 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: aarch64-unknown-linux-gnu - build: linux-arm-gnueabihf - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: arm-unknown-linux-gnueabihf - build: linux-musl-armv6 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: arm-unknown-linux-musleabihf - build: linux-musl-armv7 - os: ubuntu-22.04 - rust: stable + os: ubuntu-latest + rust: nightly target: armv7-unknown-linux-musleabihf - build: macos os: macos-12 - rust: stable + rust: nightly target: x86_64-apple-darwin - build: macos-arm64 os: macos-12 - rust: stable + rust: nightly target: aarch64-apple-darwin # - build: windows-msvc # os: windows-2022 - # rust: stable + # rust: nightly # target: x86_64-pc-windows-msvc # - build: windows-msvc-i686 # os: windows-2022 - # rust: stable + # rust: nightly # target: i686-pc-windows-msvc # - build: windows-pc-gnu # os: windows-2022 - # rust: stable-x86_64-gnu + # rust: nightly-x86_64-gnu # target: x86_64-pc-windows-gnu # - build: windows-msvc-arm64 # os: windows-2022 - # rust: stable + # rust: nightly # target: aarch64-pc-windows-msvc steps: @@ -141,7 +141,7 @@ jobs: - name: Set up Cross shell: bash run: | - if [ "${{ matrix.os }}" = "ubuntu-22.04" ]; then + if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then cargo install cross@^0.2 echo "CARGO_BIN=cross" >> $GITHUB_ENV fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6968b1f..add6f6f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,6 +11,18 @@ env: CARGO_TERM_COLOR: always jobs: + fmt: + name: fmt + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + components: rustfmt + - run: cargo fmt --all --check + test: name: tests runs-on: ubuntu-latest @@ -18,6 +30,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -38,6 +52,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@clippy + with: + toolchain: nightly - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -45,17 +61,6 @@ jobs: env: RUSTFLAGS: -Dwarnings - fmt: - name: fmt - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt --all --check - typos-check: name: TyposCheck timeout-minutes: 5 diff --git a/.gitignore b/.gitignore index 3677c68..94b3fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .DS_Store .vscode .idea +.zed LOCAL.md diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..4da51cf --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,4 @@ +indent_style = "Block" +tab_spaces = 2 +imports_granularity = "Crate" +edition = "2021" diff --git a/Cargo.lock b/Cargo.lock index 2544352..c73134f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -35,6 +35,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -51,41 +52,41 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367891bf380210abb0d6aa30c5f85a9080cb4a066c4d5c5acadad630823751b" +checksum = "bbcc41e8a11a4975b18ec6afba2cc48d591fa63336a4c526dacb50479a8d6b35" dependencies = [ - "alloy-consensus 0.3.6", - "alloy-contract 0.3.6", + "alloy-consensus", + "alloy-contract", "alloy-core", - "alloy-eips 0.3.6", + "alloy-eips", "alloy-genesis", - "alloy-network 0.3.6", + "alloy-network", "alloy-node-bindings", - "alloy-provider 0.3.6", + "alloy-provider", "alloy-pubsub", - "alloy-rpc-client 0.3.6", + "alloy-rpc-client", "alloy-rpc-types", - "alloy-serde 0.3.6", - "alloy-signer 0.3.6", + "alloy-serde", + "alloy-signer", "alloy-signer-local", - "alloy-transport 0.3.6", - "alloy-transport-http 0.3.6", + "alloy-transport", + "alloy-transport-http", "alloy-transport-ipc", "alloy-transport-ws", ] [[package]] name = "alloy-chains" -version = "0.1.47" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" +checksum = "1e39f295f876b61a1222d937e1dd31f965e4a1acc3bba98e448dd7e84b1a4566" dependencies = [ "alloy-primitives", "num_enum", @@ -94,80 +95,62 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" +checksum = "f4138dc275554afa6f18c4217262ac9388790b2fc393c2dfe03c51d357abf013" dependencies = [ - "alloy-eips 0.3.6", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.3.6", + "alloy-serde", + "alloy-trie", + "auto_impl", "c-kzg", + "derive_more", + "k256", "serde", ] [[package]] -name = "alloy-consensus" -version = "0.4.2" +name = "alloy-consensus-any" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" +checksum = "0fa04e1882c31288ce1028fdf31b6ea94cfa9eafa2e497f903ded631c8c6a42c" dependencies = [ - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", - "auto_impl", - "c-kzg", - "derive_more", + "alloy-serde", "serde", ] [[package]] name = "alloy-contract" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eefe64fd344cffa9cf9e3435ec4e93e6e9c3481bc37269af988bf497faf4a6a" +checksum = "5f21886c1fea0626f755a49b2ac653b396fb345233f6170db2da3d0ada31560c" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-network 0.3.6", - "alloy-network-primitives 0.3.6", + "alloy-network", + "alloy-network-primitives", "alloy-primitives", - "alloy-provider 0.3.6", + "alloy-provider", "alloy-pubsub", - "alloy-rpc-types-eth 0.3.6", + "alloy-rpc-types-eth", "alloy-sol-types", - "alloy-transport 0.3.6", + "alloy-transport", "futures", "futures-util", - "thiserror", -] - -[[package]] -name = "alloy-contract" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917f7d12cf3971dc8c11c9972f732b35ccb9aaaf5f28f2f87e9e6523bee3a8ad" -dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-network 0.4.2", - "alloy-network-primitives 0.4.2", - "alloy-primitives", - "alloy-provider 0.4.2", - "alloy-rpc-types-eth 0.4.2", - "alloy-sol-types", - "alloy-transport 0.4.2", - "futures", - "futures-util", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "alloy-core" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8316d83e590f4163b221b8180008f302bda5cf5451202855cdd323e588849c" +checksum = "648275bb59110f88cc5fa9a176845e52a554ebfebac2d21220bcda8c9220f797" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -178,9 +161,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2364c782a245cf8725ea6dbfca5f530162702b5d685992ea03ce64529136cc" +checksum = "bc9138f4f0912793642d453523c3116bd5d9e11de73b70177aa7cb3e94b98ad2" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -206,45 +189,28 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "k256", - "serde", -] - -[[package]] -name = "alloy-eips" -version = "0.3.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" +checksum = "cabf647eb4650c91a9d38cb6f972bb320009e7e9d61765fb688a86f1563b33e8" dependencies = [ - "alloy-eip2930", - "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.3.6", - "c-kzg", "derive_more", - "once_cell", + "k256", "serde", - "sha2", ] [[package]] name = "alloy-eips" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" +checksum = "52dd5869ed09e399003e0e0ec6903d981b2a92e74c5d37e6b40890bad2517526" dependencies = [ "alloy-eip2930", "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "c-kzg", "derive_more", "once_cell", @@ -254,20 +220,22 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a7a18afb0b318616b6b2b0e2e7ac5529d32a966c673b48091c9919e284e6aca" +checksum = "e7d2a7fe5c1a9bd6793829ea21a636f30fc2b3f5d2e7418ba86d96e41dd1f460" dependencies = [ + "alloy-eips", "alloy-primitives", - "alloy-serde 0.3.6", + "alloy-serde", + "alloy-trie", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84c506bf264110fa7e90d9924f742f40ef53c6572ea56a0b0bd714a567ed389" +checksum = "24acd2f5ba97c7a320e67217274bc81fe3c3174b8e6144ec875d9d54e760e278" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -277,104 +245,61 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3c717b5298fad078cd3a418335b266eba91b511383ca9bd497f742d5975d5ab" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "alloy-json-rpc" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fa8a1a3c4cbd221f2b8e3693aeb328fca79a757fe556ed08e47bbbc2a70db7" +checksum = "2008bedb8159a255b46b7c8614516eda06679ea82f620913679afbd8031fea72" dependencies = [ "alloy-primitives", "alloy-sol-types", "serde", "serde_json", - "thiserror", + "thiserror 2.0.11", "tracing", ] [[package]] name = "alloy-network" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3705ce7d8602132bcf5ac7a1dd293a42adc2f183abf5907c30ac535ceca049" -dependencies = [ - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", - "alloy-json-rpc 0.3.6", - "alloy-network-primitives 0.3.6", - "alloy-primitives", - "alloy-rpc-types-eth 0.3.6", - "alloy-serde 0.3.6", - "alloy-signer 0.3.6", - "alloy-sol-types", - "async-trait", - "auto_impl", - "futures-utils-wasm", - "thiserror", -] - -[[package]] -name = "alloy-network" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd" +checksum = "4556f01fe41d0677495df10a648ddcf7ce118b0e8aa9642a0e2b6dd1fb7259de" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", - "alloy-json-rpc 0.4.2", - "alloy-network-primitives 0.4.2", + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", "alloy-primitives", - "alloy-rpc-types-eth 0.4.2", - "alloy-serde 0.4.2", - "alloy-signer 0.4.2", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", "alloy-sol-types", "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror", -] - -[[package]] -name = "alloy-network-primitives" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" -dependencies = [ - "alloy-eips 0.3.6", - "alloy-primitives", - "alloy-serde 0.3.6", "serde", + "serde_json", + "thiserror 2.0.11", ] [[package]] name = "alloy-network-primitives" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" +checksum = "f31c3c6b71340a1d076831823f09cb6e02de01de5c6630a9631bdb36f947ff80" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", + "alloy-consensus", + "alloy-eips", "alloy-primitives", - "alloy-serde 0.4.2", + "alloy-serde", "serde", ] [[package]] name = "alloy-node-bindings" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5988a227293f949525f0a1b3e1ef728d2ef24afa96bad2b7788c6c9617fa3eec" +checksum = "4520cd4bc5cec20c32c98e4bc38914c7fb96bf4a712105e44da186a54e65e3ba" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -382,16 +307,16 @@ dependencies = [ "rand", "serde_json", "tempfile", - "thiserror", + "thiserror 2.0.11", "tracing", "url", ] [[package]] name = "alloy-primitives" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" +checksum = "ec878088ec6283ce1e90d280316aadd3d6ce3de06ff63d68953c855e7e447e92" dependencies = [ "alloy-rlp", "bytes", @@ -399,8 +324,7 @@ dependencies = [ "const-hex", "derive_more", "foldhash", - "hashbrown 0.15.1", - "hex-literal", + "hashbrown 0.15.2", "indexmap", "itoa", "k256", @@ -409,7 +333,7 @@ dependencies = [ "proptest", "rand", "ruint", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "sha3", "tiny-keccak", @@ -417,25 +341,26 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927f708dd457ed63420400ee5f06945df9632d5d101851952056840426a10dc5" +checksum = "5a22c4441b3ebe2d77fa9cf629ba68c3f713eb91779cff84275393db97eddd82" dependencies = [ "alloy-chains", - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", - "alloy-json-rpc 0.3.6", - "alloy-network 0.3.6", - "alloy-network-primitives 0.3.6", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", "alloy-node-bindings", "alloy-primitives", "alloy-pubsub", - "alloy-rpc-client 0.3.6", + "alloy-rpc-client", "alloy-rpc-types-anvil", - "alloy-rpc-types-eth 0.3.6", + "alloy-rpc-types-eth", + "alloy-signer", "alloy-signer-local", - "alloy-transport 0.3.6", - "alloy-transport-http 0.3.6", + "alloy-transport", + "alloy-transport-http", "alloy-transport-ipc", "alloy-transport-ws", "async-stream", @@ -445,56 +370,28 @@ dependencies = [ "futures", "futures-utils-wasm", "lru", + "parking_lot", "pin-project", "reqwest", + "schnellru", "serde", "serde_json", - "thiserror", + "thiserror 2.0.11", "tokio", "tracing", "url", -] - -[[package]] -name = "alloy-provider" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6" -dependencies = [ - "alloy-chains", - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", - "alloy-json-rpc 0.4.2", - "alloy-network 0.4.2", - "alloy-network-primitives 0.4.2", - "alloy-primitives", - "alloy-rpc-client 0.4.2", - "alloy-rpc-types-eth 0.4.2", - "alloy-transport 0.4.2", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "futures", - "futures-utils-wasm", - "lru", - "pin-project", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", + "wasmtimer", ] [[package]] name = "alloy-pubsub" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d05f63677e210d758cd5d6d1ce10f20c980c3560ccfbe79ba1997791862a04f" +checksum = "2269fd635f7b505f27c63a3cb293148cd02301efce4c8bdd9ff54fbfc4a20e23" dependencies = [ - "alloy-json-rpc 0.3.6", + "alloy-json-rpc", "alloy-primitives", - "alloy-transport 0.3.6", + "alloy-transport", "bimap", "futures", "serde", @@ -507,9 +404,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -518,26 +415,26 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "alloy-rpc-client" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82952dca71173813d4e5733e2c986d8b04aea9e0f3b0a576664c232ad050a5" +checksum = "d06a292b37e182e514903ede6e623b9de96420e8109ce300da288a96d88b7e4b" dependencies = [ - "alloy-json-rpc 0.3.6", + "alloy-json-rpc", "alloy-primitives", "alloy-pubsub", - "alloy-transport 0.3.6", - "alloy-transport-http 0.3.6", + "alloy-transport", + "alloy-transport-http", "alloy-transport-ipc", "alloy-transport-ws", "futures", @@ -550,120 +447,86 @@ dependencies = [ "tower", "tracing", "url", -] - -[[package]] -name = "alloy-rpc-client" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370143ed581aace6e663342d21d209c6b2e34ee6142f7d6675adb518deeaf0dc" -dependencies = [ - "alloy-json-rpc 0.4.2", - "alloy-primitives", - "alloy-transport 0.4.2", - "alloy-transport-http 0.4.2", - "futures", - "pin-project", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", + "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64333d639f2a0cf73491813c629a405744e16343a4bc5640931be707c345ecc5" +checksum = "9383845dd924939e7ab0298bbfe231505e20928907d7905aa3bf112287305e06" dependencies = [ + "alloy-primitives", "alloy-rpc-types-engine", - "alloy-rpc-types-eth 0.3.6", - "alloy-serde 0.3.6", + "alloy-rpc-types-eth", + "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-anvil" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25cb45ad7c0930dd62eecf164d2afe4c3d2dd2c82af85680ad1f118e1e5cb83" +checksum = "11495cb8c8d3141fc27556a4c9188b81531ad5ec3076a0394c61a6dcfbce9f34" dependencies = [ "alloy-primitives", - "alloy-serde 0.3.6", + "alloy-rpc-types-eth", + "alloy-serde", "serde", ] [[package]] -name = "alloy-rpc-types-engine" -version = "0.3.6" +name = "alloy-rpc-types-any" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1464c4dd646e1bdfde86ae65ce5ba168dbb29180b478011fe87117ae46b1629b" +checksum = "ca445cef0eb6c2cf51cfb4e214fbf1ebd00893ae2e6f3b944c8101b07990f988" dependencies = [ - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", - "alloy-primitives", - "alloy-rlp", - "derive_more", + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", ] [[package]] -name = "alloy-rpc-types-eth" -version = "0.3.6" +name = "alloy-rpc-types-engine" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83aa984386deda02482660aa31cb8ca1e63d533f1c31a52d7d181ac5ec68e9b8" +checksum = "4a5f821f30344862a0b6eb9a1c2eb91dfb2ff44c7489f37152a526cdcab79264" dependencies = [ - "alloy-consensus 0.3.6", - "alloy-eips 0.3.6", - "alloy-network-primitives 0.3.6", + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.3.6", - "alloy-sol-types", - "cfg-if", + "alloy-serde", "derive_more", - "hashbrown 0.14.5", - "itertools 0.13.0", "serde", - "serde_json", + "strum", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" +checksum = "0938bc615c02421bd86c1733ca7205cc3d99a122d9f9bff05726bd604b76a5c2" dependencies = [ - "alloy-consensus 0.4.2", - "alloy-eips 0.4.2", - "alloy-network-primitives 0.4.2", + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.4.2", + "alloy-serde", "alloy-sol-types", - "derive_more", "itertools 0.13.0", "serde", "serde_json", + "thiserror 2.0.11", ] [[package]] name = "alloy-serde" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-serde" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" +checksum = "ae0465c71d4dced7525f408d84873aeebb71faf807d22d74c4a426430ccd9b55" dependencies = [ "alloy-primitives", "serde", @@ -672,69 +535,54 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307324cca94354cd654d6713629f0383ec037e1ff9e3e3d547212471209860c0" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "elliptic-curve", - "k256", - "thiserror", -] - -[[package]] -name = "alloy-signer" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd4e0ad79c81a27ca659be5d176ca12399141659fef2bcbfdc848da478f4504" +checksum = "9bfa395ad5cc952c82358d31e4c68b27bf4a89a5456d9b27e226e77dac50e4ff" dependencies = [ "alloy-primitives", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "alloy-signer-local" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fabe917ab1778e760b4701628d1cae8e028ee9d52ac6307de4e1e9286ab6b5f" +checksum = "fbdc63ce9eda1283fcbaca66ba4a414b841c0e3edbeef9c86a71242fc9e84ccc" dependencies = [ - "alloy-consensus 0.3.6", - "alloy-network 0.3.6", + "alloy-consensus", + "alloy-network", "alloy-primitives", - "alloy-signer 0.3.6", + "alloy-signer", "async-trait", - "elliptic-curve", "eth-keystore", "k256", "rand", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "alloy-sol-macro" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9343289b4a7461ed8bab8618504c995c049c082b70c7332efd7b32125633dc05" +checksum = "8d039d267aa5cbb7732fa6ce1fd9b5e9e29368f580f80ba9d7a8450c794de4b2" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4222d70bec485ceccc5d8fd4f2909edd65b5d5e43d4aca0b5dcee65d519ae98f" +checksum = "620ae5eee30ee7216a38027dec34e0585c55099f827f92f50d11e3d2d3a4a954" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -744,16 +592,16 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e17f2677369571b976e51ea1430eb41c3690d344fef567b840bfc0b01b6f83a" +checksum = "ad9f7d057e00f8c5994e4ff4492b76532c51ead39353aa2ed63f8c50c0f4d52e" dependencies = [ "alloy-json-abi", "const-hex", @@ -762,15 +610,15 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.89", + "syn 2.0.96", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa64d80ae58ffaafdff9d5d84f58d03775f66c84433916dc9a64ed16af5755da" +checksum = "74e60b084fe1aef8acecda2743ff2d93c18ff3eb67a2d3b12f62582a1e66ef5e" dependencies = [ "serde", "winnow", @@ -778,9 +626,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6520d427d4a8eb7aa803d852d7a52ceb0c519e784c292f64bb339e636918cf27" +checksum = "c1382302752cd751efd275f4d6ef65877ddf61e0e6f5ac84ef4302b79a33a31a" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -791,50 +639,32 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33616b2edf7454302a1d48084db185e52c309f73f6c10be99b0fe39354b3f1e9" -dependencies = [ - "alloy-json-rpc 0.3.6", - "base64 0.22.1", - "futures-util", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-transport" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3e97dad3d31770db0fc89bd6a63b789fbae78963086733f960cf32c483904" +checksum = "d17722a198f33bbd25337660787aea8b8f57814febb7c746bc30407bdfc39448" dependencies = [ - "alloy-json-rpc 0.4.2", - "base64 0.22.1", + "alloy-json-rpc", + "base64", "futures-util", "futures-utils-wasm", "serde", "serde_json", - "thiserror", + "thiserror 2.0.11", "tokio", "tower", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a944f5310c690b62bbb3e7e5ce34527cbd36b2d18532a797af123271ce595a49" +checksum = "6e1509599021330a31c4a6816b655e34bf67acb1cc03c564e09fd8754ff6c5de" dependencies = [ - "alloy-json-rpc 0.3.6", - "alloy-transport 0.3.6", + "alloy-json-rpc", + "alloy-transport", "reqwest", "serde_json", "tower", @@ -842,25 +672,15 @@ dependencies = [ "url", ] -[[package]] -name = "alloy-transport-http" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" -dependencies = [ - "alloy-transport 0.4.2", - "url", -] - [[package]] name = "alloy-transport-ipc" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fd8491249f74d16ec979b1f5672377b12ebb818e6056478ffa386954dbd350" +checksum = "fa4da44bc9a5155ab599666d26decafcf12204b72a80eeaba7c5e234ee8ac205" dependencies = [ - "alloy-json-rpc 0.3.6", + "alloy-json-rpc", "alloy-pubsub", - "alloy-transport 0.3.6", + "alloy-transport", "bytes", "futures", "interprocess", @@ -873,22 +693,38 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.3.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9704761f6297fe482276bee7f77a93cb42bd541c2bd6c1c560b6f3a9ece672e" +checksum = "58011745b2f17b334db40df9077d75b181f78360a5bc5c35519e15d4bfce15e2" dependencies = [ "alloy-pubsub", - "alloy-transport 0.3.6", + "alloy-transport", "futures", - "http 1.1.0", + "http", "rustls", "serde_json", "tokio", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite", "tracing", "ws_stream_wasm", ] +[[package]] +name = "alloy-trie" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more", + "nybbles", + "serde", + "smallvec", + "tracing", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -945,11 +781,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -1082,6 +919,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "async-stream" @@ -1102,18 +942,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -1135,13 +975,13 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "auto_impl" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -1150,6 +990,31 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +dependencies = [ + "aws-lc-sys", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923ded50f602b3007e5e63e3f094c479d9c8a9b42d7f4034e4afe456aa48bfd2" +dependencies = [ + "bindgen 0.69.5", + "cc", + "cmake", + "dunce", + "fs_extra", + "paste", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -1171,12 +1036,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -1195,6 +1054,29 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.10.5", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.96", + "which", +] + [[package]] name = "bindgen" version = "0.70.1" @@ -1210,7 +1092,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -1230,9 +1112,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitvec" @@ -1287,9 +1169,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1311,10 +1193,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -1338,9 +1222,6 @@ name = "challenger" version = "0.1.0" dependencies = [ "alloy", - "alloy-contract 0.4.2", - "alloy-rlp", - "alloy-signer 0.4.2", "chrono", "clap", "env_logger", @@ -1354,15 +1235,13 @@ dependencies = [ "testing_logger", "tokio", "tokio-util", - "tower", - "warp", ] [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1395,9 +1274,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" dependencies = [ "clap_builder", "clap_derive", @@ -1405,9 +1284,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" dependencies = [ "anstream", "anstyle", @@ -1417,21 +1296,30 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "cmake" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +dependencies = [ + "cc", +] [[package]] name = "colorchoice" @@ -1441,9 +1329,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "const-hex" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487981fa1af147182687064d0a2c336586d337a606595ced9ffb0c685c250c73" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -1468,6 +1356,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1494,9 +1392,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -1551,9 +1449,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" [[package]] name = "der" @@ -1593,7 +1491,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "unicode-xid", ] @@ -1626,7 +1524,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -1680,20 +1578,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -1701,9 +1590,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -1720,12 +1609,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1746,7 +1635,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "thiserror", + "thiserror 1.0.69", "uuid", ] @@ -1762,9 +1651,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1777,6 +1666,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" @@ -1807,9 +1707,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -1835,6 +1735,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -1897,7 +1803,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -1966,9 +1872,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "group" @@ -1981,25 +1887,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.7" @@ -2011,7 +1898,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap", "slab", "tokio", @@ -2019,22 +1906,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", @@ -2042,30 +1930,6 @@ dependencies = [ "serde", ] -[[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64 0.21.7", - "bytes", - "headers-core", - "http 0.2.12", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http 0.2.12", -] - [[package]] name = "heck" version = "0.5.0" @@ -2087,12 +1951,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hmac" version = "0.12.1" @@ -2103,38 +1961,25 @@ dependencies = [ ] [[package]] -name = "http" -version = "0.2.12" +name = "home" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "bytes", - "fnv", - "itoa", + "windows-sys 0.59.0", ] [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2142,7 +1987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -2153,8 +1998,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2171,47 +2016,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.14.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -2221,6 +2042,24 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -2229,7 +2068,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -2246,9 +2085,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.5.1", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -2394,7 +2233,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -2435,7 +2274,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -2446,12 +2285,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "serde", ] @@ -2466,9 +2305,9 @@ dependencies = [ [[package]] name = "interprocess" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" +checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb" dependencies = [ "doctest-file", "futures-core", @@ -2511,16 +2350,26 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.13" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2562,17 +2411,23 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" -version = "0.2.164" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2590,16 +2445,16 @@ version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb" dependencies = [ - "bindgen", + "bindgen 0.70.1", "errno", "libc", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" @@ -2619,9 +2474,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "lru" @@ -2629,7 +2484,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.1", + "hashbrown 0.15.2", ] [[package]] @@ -2649,9 +2504,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "metrics" -version = "0.22.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" +checksum = "7a7deb012b3b2767169ff203fadb4c6b0b82b947512e5eb9e0b78c2e186ad9e3" dependencies = [ "ahash", "portable-atomic", @@ -2659,31 +2514,32 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.14.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d58e362dc7206e9456ddbcdbd53c71ba441020e62104703075a69151e38d85f" +checksum = "12779523996a67c13c84906a876ac6fe4d07a6e1adb54978378e13f199251a62" dependencies = [ - "base64 0.22.1", + "base64", "http-body-util", - "hyper 1.5.1", - "hyper-tls", + "hyper", + "hyper-rustls", "hyper-util", "indexmap", "ipnet", "metrics", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "metrics-process" -version = "1.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f69c2a98ebe047f74b834c7eeaad0db5a9fd3604e129721d212e0ef9442e238a" +checksum = "4a82c8add4382f29a122fa64fff1891453ed0f6b2867d971e7d60cb8dfa322ff" dependencies = [ + "libc", "libproc", "mach2", "metrics", @@ -2695,16 +2551,17 @@ dependencies = [ [[package]] name = "metrics-util" -version = "0.16.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b07a5eb561b8cbc16be2d216faf7757f9baf3bfb94dbb0fae3df8387a5bb47f" +checksum = "dbd4884b1dd24f7d6628274a2f5ae22465c337c5ba065ec9b6edccddf8acc673" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "metrics", - "num_cpus", "quanta", + "rand", + "rand_xoshiro", "sketches-ddsketch", ] @@ -2714,16 +2571,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2732,43 +2579,24 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 0.2.12", - "httparse", - "log", - "memchr", - "mime", - "spin", - "version_check", -] - [[package]] name = "native-tls" version = "0.2.12" @@ -2781,7 +2609,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -2852,14 +2680,27 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", +] + +[[package]] +name = "nybbles" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +dependencies = [ + "alloy-rlp", + "const-hex", + "proptest", + "serde", + "smallvec", ] [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -2893,7 +2734,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -2916,29 +2757,28 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", - "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.7.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.89", + "syn 1.0.109", ] [[package]] @@ -2987,12 +2827,12 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.11", "ucd-trie", ] @@ -3008,29 +2848,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3056,9 +2896,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "ppv-lite86" @@ -3069,6 +2909,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +dependencies = [ + "proc-macro2", + "syn 2.0.96", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -3108,36 +2958,35 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "procfs" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags", "hex", - "lazy_static", "procfs-core", "rustix", ] [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags", "hex", @@ -3165,9 +3014,9 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" dependencies = [ "crossbeam-utils", "libc", @@ -3186,9 +3035,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -3239,11 +3088,20 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + [[package]] name = "raw-cpuid" -version = "11.2.0" +version = "11.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e" dependencies = [ "bitflags", ] @@ -3256,9 +3114,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] @@ -3294,18 +3152,18 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.5.1", + "hyper", "hyper-tls", "hyper-util", "ipnet", @@ -3320,9 +3178,10 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-native-tls", + "tower", "tower-service", "url", "wasm-bindgen", @@ -3398,16 +3257,18 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint", + "num-integer", "num-traits", "parity-scale-codec", "primitive-types", @@ -3440,9 +3301,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-hex" @@ -3465,28 +3326,29 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.24", ] [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" dependencies = [ + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", @@ -3495,6 +3357,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -3506,9 +3380,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" [[package]] name = "rustls-webpki" @@ -3516,6 +3390,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3523,9 +3398,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rusty-fork" @@ -3564,10 +3439,15 @@ dependencies = [ ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "schnellru" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" +dependencies = [ + "ahash", + "cfg-if", + "hashbrown 0.13.2", +] [[package]] name = "scopeguard" @@ -3584,10 +3464,8 @@ dependencies = [ "eyre", "log", "metrics", - "once_cell", "tokio", "tokio-util", - "tower", ] [[package]] @@ -3623,7 +3501,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -3631,9 +3522,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -3650,9 +3541,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "semver-parser" @@ -3671,29 +3562,29 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -3782,9 +3673,9 @@ dependencies = [ [[package]] name = "sketches-ddsketch" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" [[package]] name = "slab" @@ -3800,12 +3691,15 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3864,7 +3758,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -3886,9 +3780,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.89" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -3897,22 +3791,16 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76fe0a3e1476bdaa0775b9aec5b869ed9520c2b2fedfe9c6df3618f8ea6290b" +checksum = "b84e4d83a0a6704561302b917a932484e1cae2d8c6354c64be8b7bac1c1fe057" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3930,7 +3818,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -3941,12 +3829,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -3967,7 +3856,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -3978,7 +3876,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] @@ -4011,9 +3920,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.41.1" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -4029,13 +3938,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -4050,20 +3959,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -4073,21 +3981,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.21.0", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", @@ -4095,15 +3991,15 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.23.0", + "tungstenite", "webpki-roots", ] [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -4131,14 +4027,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -4158,11 +4054,10 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4170,20 +4065,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] @@ -4196,40 +4091,21 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http", "httparse", "log", "rand", "rustls", "rustls-pki-types", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -4263,12 +4139,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - [[package]] name = "unicode-ident" version = "1.0.14" @@ -4368,35 +4238,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http 0.2.12", - "hyper 0.14.31", - "log", - "mime", - "mime_guess", - "multer", - "percent-encoding", - "pin-project", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-tungstenite 0.21.0", - "tokio-util", - "tower-service", - "tracing", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -4405,47 +4246,48 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4453,28 +4295,45 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasmtimer" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -4489,6 +4348,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "widestring" version = "1.1.0" @@ -4519,11 +4390,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.54.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core 0.54.0", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -4538,31 +4409,47 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.54.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-result 0.1.2", + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] [[package]] -name = "windows-registry" -version = "0.2.0" +name = "windows-implement" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ - "windows-result 0.2.0", - "windows-strings", - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] @@ -4581,7 +4468,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] @@ -4735,9 +4622,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] @@ -4767,7 +4654,7 @@ dependencies = [ "pharos", "rustc_version 0.4.1", "send_wrapper", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -4802,7 +4689,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "synstructure", ] @@ -4824,7 +4711,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -4844,7 +4731,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", "synstructure", ] @@ -4865,7 +4752,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] [[package]] @@ -4887,5 +4774,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.96", ] diff --git a/Cargo.toml b/Cargo.toml index 1309ae4..67464ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,15 +17,13 @@ eyre = "0.6.8" tokio = { version = "1", features = ["full"] } tokio-util = "0.7.12" -alloy = { version = "0.3.6", features = ["full", "signer-keystore", "node-bindings"] } -warp = "0.3" -tower = { version = "0.5.1", features = ["retry"] } +alloy = { version = "0.9.2", features = ["full", "signer-keystore", "node-bindings"] } -metrics-process = "1.2.1" -metrics-exporter-prometheus = { version = "0.14.0", features = [ +metrics-process = "2.4.0" +metrics-exporter-prometheus = { version = "0.16.1", features = [ "http-listener", ] } -metrics = "0.22.3" +metrics = "0.24.1" [dependencies] scribe = {workspace = true} @@ -33,8 +31,6 @@ alloy = { workspace = true, features = ["full", "signer-keystore"] } env_logger = { workspace = true } log = { workspace = true, features = ["kv"] } eyre = { workspace = true } -warp = { workspace = true } -tower = { workspace = true, features = ["retry"] } tokio = { workspace = true, features = ["full"] } tokio-util = { workspace = true } @@ -45,8 +41,5 @@ metrics-exporter-prometheus = { workspace = true } clap = { version = "4.3.21", features = ["derive", "env"] } rpassword = "7.2.0" chrono = "0.4.38" -alloy-contract = "0.4.2" -alloy-rlp = "0.3.8" -alloy-signer = "0.4.2" futures-util = "0.3.31" testing_logger = "0.1.1" diff --git a/Dockerfile b/Dockerfile index 9c2af90..a8a9c3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.4 -FROM rust:alpine3.19 as build-environment +FROM rust:alpine3.20 as build-environment ARG TARGETARCH WORKDIR /opt @@ -10,20 +10,20 @@ RUN echo "export RUSTFLAGS='-Ctarget-feature=-crt-static'" >> $HOME/.profile # Mac M1 workaround RUN [[ "$TARGETARCH" = "arm64" ]] && echo "export CFLAGS=-mno-outline-atomics" >> $HOME/.profile || true +# Install nightly and set as default toolchain +RUN rustup update nightly && rustup default nightly + WORKDIR /opt/challenger COPY . . -RUN --mount=type=cache,target=/root/.cargo/registry \ - --mount=type=cache,target=/root/.cargo/git \ - --mount=type=cache,target=/opt/challenger/target \ - source $HOME/.profile \ +RUN source $HOME/.profile \ && cargo build --release \ && mkdir out \ && mv target/release/challenger out/challenger \ && strip out/challenger; # Runner image -FROM alpine:3.19 as challenger-client +FROM alpine:3.20 as challenger-client RUN apk add --no-cache linux-headers gcompat libgcc diff --git a/README.md b/README.md index 17b8546..4042251 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,65 @@ challenger -a 0x891E368fE81cBa2aC6F6cc4b98e684c106e2EF4f -a 0x******* --rpc-url By default `challenger` uses log level `info`. If you want to get debug information use `RUST_LOG=debug` env variable ! +# Development + +## Rust toolchain + +For this project we use the nightly toolchain. To install it, run: +```sh +rustup toolchain install nightly +``` + +To set the nightly toolchain as the default for folder, run: +```sh +rustup override set nightly +``` + +As well we provide a `rust-toolchain.toml` file that sets the nightly toolchain for the project. + +### Rust analyzer + +For rust-analyzer to work correctly, you need to install the nightly toolchain and set it as the default for the folder. +Also `RUST_TOOLCHAIN` environment variable should be set to `nightly`. + +Intellij Example: + +``` +settings -> Language & Frameworks -> Rust -> Rustfmt + +Add the environment Variable = "RUSTUP_TOOLCHAIN": "nightly" + +Add Additional argument = "+nightly" +``` + + +Zed example: + +`.zed/settings.json` +```json +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{ + "tab_size": 2, + "lsp": { + "rust-analyzer": { + "initialization_options": { + "server": { + "extraEnv": { + "RUSTUP_TOOLCHAIN": "nightly" + } + }, + "rustfmt": { + "extraArgs": ["+nightly"] + } + } + } + } +} +``` + ## Building docker image @@ -45,7 +104,7 @@ SERVER_VERSION have to be same as release but without `v`, if release is `v0.0.1 docker build --build-arg SERVER_VERSION=0.0.10 -t challenger . ``` -usage: +usage: ```bash docker run --rm challenger @@ -93,7 +152,7 @@ async fn main() -> Result<(), Box> { In this example, we're using the `Http` provider from the `ethers` crate to connect to the Ethereum mainnet. We're also passing in a contract address and a tick interval of 30 seconds to the `Challenger::new` method. -Once you have an instance of the `Challenger` struct, you can start processing pokes by calling the `start` method. This method will start continues checks for new pokes every `tick_interval` seconds and process them if they're within the challenge period. +Once you have an instance of the `Challenger` struct, you can start processing pokes by calling the `start` method. This method will start continues checks for new pokes every `tick_interval` seconds and process them if they're within the challenge period. You can also customize the behavior of the `Challenger` struct by setting the `max_failure_count` field to control how many failures are allowed before processing is stopped for a particular address, and by setting the `challenge_period_reload_interval` field to control how often the challenge period is reloaded from the contract. Here's an example: diff --git a/crates/scribe/Cargo.toml b/crates/scribe/Cargo.toml index b765b29..1f729b5 100644 --- a/crates/scribe/Cargo.toml +++ b/crates/scribe/Cargo.toml @@ -6,10 +6,8 @@ edition = "2021" [dependencies] alloy = {workspace = true, features = ["full"]} eyre = {workspace = true} -once_cell = "1.10.0" log = {workspace = true} tokio = {workspace = true, features = ["full"]} tokio-util = {workspace = true} -tower = {workspace = true, features = ["retry"]} metrics = { workspace = true } chrono = "0.4.38" diff --git a/crates/scribe/src/contract.rs b/crates/scribe/src/contract.rs index 8271f0b..30c6062 100644 --- a/crates/scribe/src/contract.rs +++ b/crates/scribe/src/contract.rs @@ -16,16 +16,16 @@ use std::{fmt::Debug, sync::Arc}; use alloy::{ - primitives::{Address, FixedBytes, LogData}, - rpc::types::Log, - sol, - sol_types::SolEvent, + primitives::{Address, FixedBytes, LogData}, + rpc::types::Log, + sol, + sol_types::SolEvent, }; use eyre::{bail, Result, WrapErr}; -use IScribe::SchnorrData; -use ScribeOptimistic::{OpPoked, ScribeOptimisticInstance}; use crate::events_listener::{RetryProviderWithSigner, RpcRetryProvider}; +use IScribe::SchnorrData; +use ScribeOptimistic::{OpPoked, ScribeOptimisticInstance}; // Generate the contract bindings for the ScribeOptimistic contract sol! { @@ -42,10 +42,10 @@ sol! { // let event: ScribeOptimistic::OpPoked = decode_log::(&log)?; // ``` fn decode_log(log: &Log) -> Result { - let log_data: &LogData = log.as_ref(); + let log_data: &LogData = log.as_ref(); - E::decode_raw_log(log_data.topics().iter().copied(), &log_data.data, false) - .wrap_err_with(|| "Failed to decode log") + E::decode_raw_log(log_data.topics().iter().copied(), &log_data.data, false) + .wrap_err_with(|| "Failed to decode log") } /// Events emitted by the ScribeOptimistic contract. @@ -53,36 +53,36 @@ fn decode_log(log: &Log) -> Result { /// In `challenger` we only care about `OpPoked` and `OpPokeChallengedSuccessfully` events. #[derive(Debug, Clone)] pub enum Event { - OpPoked(ScribeOptimistic::OpPoked), - OpPokeChallengedSuccessfully(ScribeOptimistic::OpPokeChallengedSuccessfully), + OpPoked(ScribeOptimistic::OpPoked), + OpPokeChallengedSuccessfully(ScribeOptimistic::OpPokeChallengedSuccessfully), } impl Event { - /// Creates a new [Event] from a Log - pub fn from_log(log: Log) -> Result { - let Some(topic) = log.topic0() else { - bail!( - "Failed to convert log to event: empty topic0 for log under tx {:?}", - log.transaction_hash - ) - }; - - // Match the event by `topic0 - match *topic { - ScribeOptimistic::OpPoked::SIGNATURE_HASH => { - let event = decode_log::(&log)?; - Ok(Self::OpPoked(event)) - } - ScribeOptimistic::OpPokeChallengedSuccessfully::SIGNATURE_HASH => { - let event = decode_log::(&log)?; - Ok(Self::OpPokeChallengedSuccessfully(event)) - } - _ => bail!( - "Failed to convert log to event: Unknown topic0: {:#x}", - topic - ), - } + /// Creates a new [Event] from a Log + pub fn from_log(log: Log) -> Result { + let Some(topic) = log.topic0() else { + bail!( + "Failed to convert log to event: empty topic0 for log under tx {:?}", + log.transaction_hash + ) + }; + + // Match the event by `topic0 + match *topic { + ScribeOptimistic::OpPoked::SIGNATURE_HASH => { + let event = decode_log::(&log)?; + Ok(Self::OpPoked(event)) + } + ScribeOptimistic::OpPokeChallengedSuccessfully::SIGNATURE_HASH => { + let event = decode_log::(&log)?; + Ok(Self::OpPokeChallengedSuccessfully(event)) + } + _ => bail!( + "Failed to convert log to event: Unknown topic0: {:#x}", + topic + ), } + } } /// Event with initial onchain data. @@ -90,146 +90,146 @@ impl Event { /// and contract [alloy::primitives::Address] that emitted `log`. #[derive(Debug, Clone)] pub struct EventWithMetadata { - pub event: Event, - pub log: Log, - pub address: Address, + pub event: Event, + pub log: Log, + pub address: Address, } impl EventWithMetadata { - /// Creates a new [EventWithMetadata] from a Log - pub fn from_log(log: Log) -> Result { - let event: Event = Event::from_log(log.clone())?; - let address = log.address(); - - Ok(Self { - event, - log, - address, - }) - } + /// Creates a new [EventWithMetadata] from a Log + pub fn from_log(log: Log) -> Result { + let event: Event = Event::from_log(log.clone())?; + let address = log.address(); + + Ok(Self { + event, + log, + address, + }) + } } /// This trait provides methods required for `challenger` to interact with the ScribeOptimistic smart contract. /// #[allow(async_fn_in_trait)] pub trait ScribeOptimisticProvider { - /// Returns challenge period from ScribeOptimistic smart contract deployed to `address`. - /// NOTE: From time to time challenger might need to refresh this value, because it might be changed by the contract owner. - async fn get_challenge_period(&self) -> Result; + /// Returns challenge period from ScribeOptimistic smart contract deployed to `address`. + /// NOTE: From time to time challenger might need to refresh this value, because it might be changed by the contract owner. + async fn get_challenge_period(&self) -> Result; - /// Returns true if given `OpPoked` schnorr signature is valid. - async fn is_schnorr_signature_valid(&self, op_poked: OpPoked) -> Result; + /// Returns true if given `OpPoked` schnorr signature is valid. + async fn is_schnorr_signature_valid(&self, op_poked: OpPoked) -> Result; - /// Challenges given `OpPoked` event with given `schnorr_data`. - /// See: `IScribeOptimistic::opChallenge(SchnorrData calldata schnorrData)` for more details. - async fn challenge(&self, schnorr_data: SchnorrData) -> Result>; + /// Challenges given `OpPoked` event with given `schnorr_data`. + /// See: `IScribeOptimistic::opChallenge(SchnorrData calldata schnorrData)` for more details. + async fn challenge(&self, schnorr_data: SchnorrData) -> Result>; - /// Returns the address of the contract. - fn address(&self) -> &Address; + /// Returns the address of the contract. + fn address(&self) -> &Address; - /// Returns a new provider with the same signer. - fn get_new_provider(&self) -> Arc; + /// Returns a new provider with the same signer. + fn get_new_provider(&self) -> Arc; } /// ScribeOptimisticProviderInstance is a real implementation of ScribeOptimisticProvider based on raw JSON-RPC calls. #[derive(Debug, Clone)] pub struct ScribeOptimisticProviderInstance { - pub contract: ScribeOptimisticInstance>, + pub contract: ScribeOptimisticInstance>, } impl ScribeOptimisticProviderInstance { - /// Creates a new ScribeOptimisticInstance - pub fn new(address: Address, provider: Arc) -> Self { - let contract = ScribeOptimistic::new(address, provider.clone()); - Self { contract } - } + /// Creates a new ScribeOptimisticInstance + pub fn new(address: Address, provider: Arc) -> Self { + let contract = ScribeOptimistic::new(address, provider.clone()); + Self { contract } + } } impl ScribeOptimisticProvider for ScribeOptimisticProviderInstance { - /// Returns challenge period from ScribeOptimistic smart contract deployed to `address`. - async fn get_challenge_period(&self) -> Result { - Ok(self.contract.opChallengePeriod().call().await?._0) - } - - /// Validates given `OpPoked` schnorr signature. - /// Uses `constructPokeMessage` and `isAcceptableSchnorrSignatureNow` methods from the contract. - /// Returns true if the signature is valid. - async fn is_schnorr_signature_valid(&self, op_poked: OpPoked) -> Result { - log::trace!( - "Contract {:?}: Validating OpPoke signature", - self.contract.address() - ); - - let message = self - .contract - .constructPokeMessage(op_poked.pokeData) - .call() - .await - .wrap_err_with(|| { - format!( - "Contract {:?}: failed to construct poke message", - self.contract.address() - ) - })? - ._0; - - let acceptable = self - .contract - .isAcceptableSchnorrSignatureNow(message, op_poked.schnorrData) - .call() - .await - .wrap_err_with(|| { - format!( - "Contract {:?}: failed to call isAcceptableSchnorrSignatureNow() method", - self.contract.address() - ) - })? - ._0; - - Ok(acceptable) - } - - /// Challenges given `OpPoked` event with given `schnorr_data`. - /// Executes `opChallenge` method on the contract and returns transaction hash if everything worked well. - async fn challenge(&self, schnorr_data: SchnorrData) -> Result> { - log::warn!( - "Contract {:?}: Challenging OpPoke with shnorr_data {:?}", - self.contract.address(), - &schnorr_data - ); - - let transaction = self - .contract - .opChallenge(schnorr_data.clone()) - // TODO: set gas limit properly - .gas(200000); - - transaction - .send() - .await - .wrap_err_with(|| { - format!( - "Contract {:?} Failed to send transaction", - self.contract.address() - ) - })? - .watch() - .await - .wrap_err_with(|| { - format!( - "Contract {:?} Failed to wait for challenge confirmation", - self.contract.address() - ) - }) - } - - /// Returns the address of the contract. - fn address(&self) -> &Address { - self.contract.address() - } - - /// Returns a new provider (clone) with the same signer. - fn get_new_provider(&self) -> Arc { - self.contract.provider().clone() - } + /// Returns challenge period from ScribeOptimistic smart contract deployed to `address`. + async fn get_challenge_period(&self) -> Result { + Ok(self.contract.opChallengePeriod().call().await?._0) + } + + /// Validates given `OpPoked` schnorr signature. + /// Uses `constructPokeMessage` and `isAcceptableSchnorrSignatureNow` methods from the contract. + /// Returns true if the signature is valid. + async fn is_schnorr_signature_valid(&self, op_poked: OpPoked) -> Result { + log::trace!( + "Contract {:?}: Validating OpPoke signature", + self.contract.address() + ); + + let message = self + .contract + .constructPokeMessage(op_poked.pokeData) + .call() + .await + .wrap_err_with(|| { + format!( + "Contract {:?}: failed to construct poke message", + self.contract.address() + ) + })? + ._0; + + let acceptable = self + .contract + .isAcceptableSchnorrSignatureNow(message, op_poked.schnorrData) + .call() + .await + .wrap_err_with(|| { + format!( + "Contract {:?}: failed to call isAcceptableSchnorrSignatureNow() method", + self.contract.address() + ) + })? + ._0; + + Ok(acceptable) + } + + /// Challenges given `OpPoked` event with given `schnorr_data`. + /// Executes `opChallenge` method on the contract and returns transaction hash if everything worked well. + async fn challenge(&self, schnorr_data: SchnorrData) -> Result> { + log::warn!( + "Contract {:?}: Challenging OpPoke with shnorr_data {:?}", + self.contract.address(), + &schnorr_data + ); + + let transaction = self + .contract + .opChallenge(schnorr_data.clone()) + // TODO: set gas limit properly + .gas(200000); + + transaction + .send() + .await + .wrap_err_with(|| { + format!( + "Contract {:?} Failed to send transaction", + self.contract.address() + ) + })? + .watch() + .await + .wrap_err_with(|| { + format!( + "Contract {:?} Failed to wait for challenge confirmation", + self.contract.address() + ) + }) + } + + /// Returns the address of the contract. + fn address(&self) -> &Address { + self.contract.address() + } + + /// Returns a new provider (clone) with the same signer. + fn get_new_provider(&self) -> Arc { + self.contract.provider().clone() + } } diff --git a/crates/scribe/src/events_handler.rs b/crates/scribe/src/events_handler.rs index 6908548..4c55093 100644 --- a/crates/scribe/src/events_handler.rs +++ b/crates/scribe/src/events_handler.rs @@ -13,26 +13,30 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; - -use alloy::primitives::{Address, FixedBytes}; -use alloy::providers::Provider; -use alloy::rpc::types::BlockTransactionsKind; +use alloy::{ + primitives::{Address, FixedBytes}, + providers::Provider, + rpc::types::BlockTransactionsKind, +}; use eyre::{bail, Context, Result}; -use tokio::sync::mpsc::{Receiver, Sender}; -use tokio::sync::Mutex; -use tokio::task::JoinSet; +use std::{collections::HashMap, sync::Arc, time::Duration}; +use tokio::{ + sync::{ + mpsc::{Receiver, Sender}, + Mutex, + }, + task::JoinSet, +}; use tokio_util::sync::CancellationToken; -use crate::contract::Event; -use crate::contract::ScribeOptimistic::OpPoked; -use crate::contract::{ - EventWithMetadata, ScribeOptimisticProvider, ScribeOptimisticProviderInstance, +use crate::{ + contract::{ + Event, EventWithMetadata, ScribeOptimistic::OpPoked, ScribeOptimisticProvider, + ScribeOptimisticProviderInstance, + }, + events_listener::RetryProviderWithSigner, + metrics, }; -use crate::events_listener::RetryProviderWithSigner; -use crate::metrics; const CHALLENGE_POKE_DELAY_MS: u64 = 200; const FLASHBOT_CHALLENGE_RETRY_COUNT: u64 = 3; @@ -45,83 +49,83 @@ const CLASSIC_CHALLENGE_RETRY_COUNT: u64 = 3; /// `EventDistributor` is responsible for creating and managing `ScribeEventsProcessor` instances. /// You don't need to spawn anything manually, just call `start` and it will take care of the rest. pub struct EventDistributor { + addresses: Vec
, + cancel: CancellationToken, + provider: Arc, + flashbot_provider: Arc, + rx: Receiver, + txs: HashMap>, +} + +impl EventDistributor { + pub fn new( addresses: Vec
, cancel: CancellationToken, provider: Arc, flashbot_provider: Arc, rx: Receiver, - txs: HashMap>, -} - -impl EventDistributor { - pub fn new( - addresses: Vec
, - cancel: CancellationToken, - provider: Arc, - flashbot_provider: Arc, - rx: Receiver, - ) -> Self { - Self { - addresses, - cancel, - provider, - flashbot_provider, - rx, - txs: HashMap::new(), - } + ) -> Self { + Self { + addresses, + cancel, + provider, + flashbot_provider, + rx, + txs: HashMap::new(), } - - /// Spawns list of `ScribeEventsProcessor` instances for each address in `addresses`, - /// creates a channel for each address and starts listening for events. - pub async fn start(&mut self) -> Result<()> { - let mut contract_handler_set = JoinSet::new(); - // Create a contract handler for each scribe address - for address in &self.addresses { - let (tx, rx) = tokio::sync::mpsc::channel::(100); - self.txs.insert(*address, tx); - - let mut contract_handler = ScribeEventsProcessor::new( - *address, - self.provider.clone(), - self.flashbot_provider.clone(), - self.cancel.clone(), - rx, - ); - contract_handler_set.spawn(async move { - let _ = contract_handler.start().await; - }); - } - log::debug!("EventDistributor: All processors started, listening for events..."); - - loop { - tokio::select! { - _ = self.cancel.cancelled() => { - log::info!("EventDistributor: received cancel command, stopping..."); - break; - } - event = self.rx.recv() => { - if let Some(event) = event { - // Send the event to the appropriate contract handler - match self.txs.get(&event.address) { - Some(tx) => { - let _ = tx.send(event).await; - } - _ => { - // Should never happen - log::warn!( - "EventDistributor: Received event from unknown address or receiver is dead: {:?}", - event - ); - } - } - } - } - } - } - // Wait for all tasks to finish - contract_handler_set.join_all().await; - Ok(()) + } + + /// Spawns list of `ScribeEventsProcessor` instances for each address in `addresses`, + /// creates a channel for each address and starts listening for events. + pub async fn start(&mut self) -> Result<()> { + let mut contract_handler_set = JoinSet::new(); + // Create a contract handler for each scribe address + for address in &self.addresses { + let (tx, rx) = tokio::sync::mpsc::channel::(100); + self.txs.insert(*address, tx); + + let mut contract_handler = ScribeEventsProcessor::new( + *address, + self.provider.clone(), + self.flashbot_provider.clone(), + self.cancel.clone(), + rx, + ); + contract_handler_set.spawn(async move { + let _ = contract_handler.start().await; + }); + } + log::debug!("EventDistributor: All processors started, listening for events..."); + + loop { + tokio::select! { + _ = self.cancel.cancelled() => { + log::info!("EventDistributor: received cancel command, stopping..."); + break; + } + event = self.rx.recv() => { + if let Some(event) = event { + // Send the event to the appropriate contract handler + match self.txs.get(&event.address) { + Some(tx) => { + let _ = tx.send(event).await; + } + _ => { + // Should never happen + log::warn!( + "EventDistributor: Received event from unknown address or receiver for it is dead: {:?}", + event + ); + } + } + } + } + } } + // Wait for all tasks to finish + contract_handler_set.join_all().await; + Ok(()) + } } // Receives preparsed [crate::contract::EventWithMetadata] events for a `ScribeOptimistic` instance on address, @@ -132,361 +136,354 @@ impl EventDistributor { // If next received event will be `OpPokeChallengedSuccessfully`, the challenge process is cancelled (no need to spend resources on validation). // Otherwise, the challenge process will start procecssing. struct ScribeEventsProcessor { - address: Address, - provider: Arc, - flashbot_provider: Arc, - cancellation_token: CancellationToken, - rx: Receiver, - cancel_challenge: Option, - challenge_period: Option, + address: Address, + provider: Arc, + flashbot_provider: Arc, + cancellation_token: CancellationToken, + rx: Receiver, + cancel_challenge: Option, + challenge_period: Option, } impl ScribeEventsProcessor { - pub fn new( - scribe_address: Address, - provider: Arc, - flashbot_provider: Arc, - cancel: CancellationToken, - rx: Receiver, - ) -> Self { - Self { - address: scribe_address, - provider, - flashbot_provider, - cancellation_token: cancel, - rx, - cancel_challenge: None, - challenge_period: None, - } + pub fn new( + scribe_address: Address, + provider: Arc, + flashbot_provider: Arc, + cancel: CancellationToken, + rx: Receiver, + ) -> Self { + Self { + address: scribe_address, + provider, + flashbot_provider, + cancellation_token: cancel, + rx, + cancel_challenge: None, + challenge_period: None, } - - async fn start(&mut self) -> Result<()> { - log::debug!( - "ScribeEventsProcessor[{:?}] Starting new contract handler", - self.address - ); - // We have to fail if no challenge period is fetched on start - self.refresh_challenge_period().await.unwrap(); - - loop { - tokio::select! { - // main process terminates, need to finish work and exit... - _ = self.cancellation_token.cancelled() => { - log::info!( - "ScribeEventsProcessor[{:?}] Cancellation requested, stopping contract handler", - self.address - ); - return Ok(()); - } - // new [EventWithMetadata] received, process it... - event = self.rx.recv() => { - if let Some(event) = event { - match &event.event { - // For `OpPoked` events, check if `schnorr_signature` is valid, - // if not - check if event is within the challenge period, send challenge. - // If `schnorr_signature` is valid, do nothing. - Event::OpPoked(op_poked) => { - log::trace!( - "ScribeEventsProcessor[{:?}] OpPoked received, start processing", - self.address - ); - - if let Err(err) = self.process_op_poked(event.clone(), op_poked.clone()).await { - log::error!( - "ScribeEventsProcessor[{:?}] Error processing OpPoked event: {:?}", - self.address, - err - ); - } - } - // If the challenge is already successful, cancel the previous challenge process - Event::OpPokeChallengedSuccessfully(_) => { - log::debug!( - "ScribeEventsProcessor[{:?}] OpPokeChallengedSuccessfully received, cancelling challenge process", - self.address - ); - self.cancel_challenge().await; - } - } - } else { - log::warn!( - "ScribeEventsProcessor[{:?}] Received None event in contract handler", - self.address - ); - } - } - } - } + } + + async fn start(&mut self) -> Result<()> { + log::debug!( + "ScribeEventsProcessor[{:?}] Starting new contract handler", + self.address + ); + // We have to fail if no challenge period is fetched on start + self.refresh_challenge_period().await.unwrap(); + + loop { + tokio::select! { + // main process terminates, need to finish work and exit... + _ = self.cancellation_token.cancelled() => { + log::info!( + "ScribeEventsProcessor[{:?}] Cancellation requested, stopping contract handler", + self.address + ); + return Ok(()); + } + // new [EventWithMetadata] received, process it... + event = self.rx.recv() => { + if let Some(event) = event { + match &event.event { + // For `OpPoked` events, check if `schnorr_signature` is valid, + // if not - check if event is within the challenge period, send challenge. + // If `schnorr_signature` is valid, do nothing. + Event::OpPoked(op_poked) => { + log::trace!( + "ScribeEventsProcessor[{:?}] OpPoked received, start processing", + self.address + ); + + if let Err(err) = self.process_op_poked(event.clone(), op_poked.clone()).await { + log::error!( + "ScribeEventsProcessor[{:?}] Error processing OpPoked event: {:?}", + self.address, + err + ); + } + } + // If the challenge is already successful, cancel the previous challenge process + Event::OpPokeChallengedSuccessfully(_) => { + log::debug!( + "ScribeEventsProcessor[{:?}] OpPokeChallengedSuccessfully received, cancelling challenge process", + self.address + ); + self.cancel_challenge().await; + } + } + } else { + log::warn!( + "ScribeEventsProcessor[{:?}] Received None event in contract handler", + self.address + ); + } + } + } } - - // Starts the validation and challenge process for the `OpPoked` event. - async fn process_op_poked( - &mut self, - event: EventWithMetadata, - op_poked: OpPoked, - ) -> Result<()> { - // Check if the poke is within the challenge period - let event_timestamp = match event.log.block_timestamp { - Some(timestamp) => timestamp, - None => self - .get_timestamp_from_block(&event) - .await - .wrap_err("Failed to get timestamp from block via RPC call")?, - }; - - let current_timestamp = chrono::Utc::now().timestamp() as u64; - log::debug!( - "ScribeEventsProcessor[{:?}] OpPoked, event_timestamp: {:?}, current_timestamp: {:?}", - self.address, - event_timestamp, - current_timestamp - ); - if current_timestamp - event_timestamp > self.challenge_period.unwrap() { - // This log is expected in tests, tests must be updated if log message is changed - log::debug!( - "ScribeEventsProcessor[{:?}] OpPoked received outside of challenge period", - self.address - ); - return Ok(()); - } - - log::debug!( - "ScribeEventsProcessor[{:?}] Spawning validation and challenge process...", - self.address - ); - self.spawn_challenge(op_poked).await; - - Ok(()) + } + + // Starts the validation and challenge process for the `OpPoked` event. + async fn process_op_poked(&mut self, event: EventWithMetadata, op_poked: OpPoked) -> Result<()> { + // Check if the poke is within the challenge period + let event_timestamp = match event.log.block_timestamp { + Some(timestamp) => timestamp, + None => self + .get_timestamp_from_block(&event) + .await + .wrap_err("Failed to get timestamp from block via RPC call")?, + }; + + let current_timestamp = chrono::Utc::now().timestamp() as u64; + log::debug!( + "ScribeEventsProcessor[{:?}] OpPoked, event_timestamp: {:?}, current_timestamp: {:?}", + self.address, + event_timestamp, + current_timestamp + ); + if current_timestamp - event_timestamp > self.challenge_period.unwrap() { + // This log is expected in tests, tests must be updated if log message is changed + log::debug!( + "ScribeEventsProcessor[{:?}] OpPoked received outside of challenge period", + self.address + ); + return Ok(()); } - // Gets the timestamp from the block by `event.log.block_number`, if it is missing, returns an error - async fn get_timestamp_from_block(&self, event: &EventWithMetadata) -> Result { - // Possible block number to be missing for unconfirmed blocks - if event.log.block_number.is_none() { - bail!("Block number is missing for log {:?}", event.log); - } - let block_number = event.log.block_number.unwrap(); - - let block = self - .provider - .get_block(block_number.into(), BlockTransactionsKind::Hashes) - .await?; + log::debug!( + "ScribeEventsProcessor[{:?}] Spawning validation and challenge process...", + self.address + ); + self.spawn_challenge(op_poked).await; - let block = match block { - Some(block) => block, - None => { - bail!("Block with number {:?} not found", block_number); - } - }; + Ok(()) + } - Ok(block.header.timestamp) + // Gets the timestamp from the block by `event.log.block_number`, if it is missing, returns an error + async fn get_timestamp_from_block(&self, event: &EventWithMetadata) -> Result { + // Possible block number to be missing for unconfirmed blocks + if event.log.block_number.is_none() { + bail!("Block number is missing for log {:?}", event.log); } - - async fn refresh_challenge_period(&mut self) -> Result<()> { - let period = ScribeOptimisticProviderInstance::new(self.address, self.provider.clone()) - .get_challenge_period() - .await?; - - self.challenge_period = Some(period as u64); - Ok(()) - } - - async fn spawn_challenge(&mut self, op_poked: OpPoked) { - // Ensure there is no existing challenge - self.cancel_challenge().await; - // Create a new cancellation token - self.cancel_challenge = Some(CancellationToken::new()); - // Create a new challenger instance - let challenge_handler = Some(Arc::new(Mutex::new(OpPokedValidator::new( - op_poked, - self.cancellation_token.clone(), - // cancel_challenge guaranteed to be Some - self.cancel_challenge.as_ref().unwrap().clone(), - self.address, - self.provider.clone(), - self.flashbot_provider.clone(), - )))); - - // Spawn the asynchronous task - tokio::spawn(async move { - let handler = challenge_handler.as_ref().unwrap().lock().await; - let _ = handler.start().await; - }); - log::debug!( - "ScribeEventsProcessor[{:?}] Spawned New challenger process", - self.address - ); - } - - async fn cancel_challenge(&mut self) { - if let Some(cancel) = &self.cancel_challenge { - log::debug!( - "ScribeEventsProcessor[{:?}] Cancelling existing challenge", - self.address - ); - cancel.cancel(); - self.cancel_challenge = None; - } + let block_number = event.log.block_number.unwrap(); + + let block = self + .provider + .get_block(block_number.into(), BlockTransactionsKind::Hashes) + .await?; + + let block = match block { + Some(block) => block, + None => { + bail!("Block with number {:?} not found", block_number); + } + }; + + Ok(block.header.timestamp) + } + + async fn refresh_challenge_period(&mut self) -> Result<()> { + let period = ScribeOptimisticProviderInstance::new(self.address, self.provider.clone()) + .get_challenge_period() + .await?; + + self.challenge_period = Some(period as u64); + Ok(()) + } + + async fn spawn_challenge(&mut self, op_poked: OpPoked) { + // Ensure there is no existing challenge existing + self.cancel_challenge().await; + // Create a new cancellation token + self.cancel_challenge = Some(CancellationToken::new()); + // Create a new challenger instance + let challenge_handler = Some(Arc::new(Mutex::new(OpPokedValidator::new( + op_poked, + self.cancellation_token.clone(), + // cancel_challenge guaranteed to be Some + self.cancel_challenge.as_ref().unwrap().clone(), + self.address, + self.provider.clone(), + self.flashbot_provider.clone(), + )))); + + // Spawn the asynchronous task + tokio::spawn(async move { + let handler = challenge_handler.as_ref().unwrap().lock().await; + let _ = handler.start().await; + }); + log::debug!( + "ScribeEventsProcessor[{:?}] Spawned New challenger process", + self.address + ); + } + + async fn cancel_challenge(&mut self) { + if let Some(cancel) = &self.cancel_challenge { + log::debug!( + "ScribeEventsProcessor[{:?}] Cancelling existing challenge", + self.address + ); + cancel.cancel(); + self.cancel_challenge = None; } + } } // Handle the challenge process for a specific OpPoked event after a delay // If cancelled before end of delay or inbetween retries stop process // First try challenge with flashbot provider, then with normal provider struct OpPokedValidator { + op_poked: OpPoked, + global_cancel: CancellationToken, + cancel: CancellationToken, + address: Address, + // TODO replace with ScribeOptimisticProviderInstances + provider: Arc, + flashbot_provider: Arc, +} + +impl OpPokedValidator { + pub fn new( op_poked: OpPoked, global_cancel: CancellationToken, cancel: CancellationToken, address: Address, - // TODO replace with ScribeOptimisticProviderInstances provider: Arc, flashbot_provider: Arc, -} + ) -> Self { + Self { + op_poked, + global_cancel, + cancel, + address, + provider, + flashbot_provider, + } + } + + pub async fn start(&self) -> Result<()> { + // This checked for in tests, tests must be updated if log is changed + log::debug!( + "OpPokedValidator[{:?}] OpPoked validation started", + self.address + ); + tokio::select! { + // Check if the challenge has been cancelled + _ = self.cancel.cancelled() => { + log::debug!("OpPokedValidator[{:?}] Challenge cancelled", self.address); + Ok(()) + } + // Check if the global cancel command sent + _ = self.global_cancel.cancelled() => { + log::debug!("OpPokedValidator[{:?}] Global cancel command received", self.address); + Ok(()) + } + _ = tokio::time::sleep(Duration::from_millis(CHALLENGE_POKE_DELAY_MS)) => { + // Verify that the OpPoked is valid + let is_valid = ScribeOptimisticProviderInstance::new( + self.address, + self.provider.clone() + ).is_schnorr_signature_valid(self.op_poked.clone()).await?; + + if is_valid { + log::debug!("OpPokedValidator[{:?}] OpPoked is valid, no need to challenge", self.address); + return Ok(()); + } -impl OpPokedValidator { - pub fn new( - op_poked: OpPoked, - global_cancel: CancellationToken, - cancel: CancellationToken, - address: Address, - provider: Arc, - flashbot_provider: Arc, - ) -> Self { - Self { - op_poked, - global_cancel, - cancel, - address, - provider, - flashbot_provider, + // Perform the challenge process + self.challenge().await?; + Ok(()) } } - - pub async fn start(&self) -> Result<()> { - // This checked for in tests, tests must be updated if log is changed - log::debug!( - "OpPokedValidator[{:?}] OpPoked validation started", + } + + // Perform the challenge process, first with flashbot provider, then with normal provider. + async fn challenge(&self) -> Result> { + // Perform the challenge after 200ms + let mut challenge_attempts: u64 = 0; + const RETRY_RANGE_END: u64 = CLASSIC_CHALLENGE_RETRY_COUNT + FLASHBOT_CHALLENGE_RETRY_COUNT; + + log::info!( + "OpPokedValidator[{:?}] Challending data: {:?}", + self.address, + self.op_poked + ); + + loop { + match challenge_attempts { + 0..FLASHBOT_CHALLENGE_RETRY_COUNT => { + log::debug!( + "OpPokedValidator[{:?}] Attempting flashbot challenge", self.address - ); - tokio::select! { - // Check if the challenge has been cancelled - _ = self.cancel.cancelled() => { - log::debug!("OpPokedValidator[{:?}] Challenge cancelled", self.address); - Ok(()) - } - // Check if the global cancel command sent - _ = self.global_cancel.cancelled() => { - log::debug!("OpPokedValidator[{:?}] Global cancel command received", self.address); - Ok(()) + ); + let contract = + ScribeOptimisticProviderInstance::new(self.address, self.flashbot_provider.clone()); + + let result = contract.challenge(self.op_poked.schnorrData.clone()).await; + + match result { + Ok(tx_hash) => { + log::info!( + "OpPokedValidator[{:?}] Flashbot transaction sent via flashbots RPC: {:?}", + self.address, + tx_hash + ); + + // Increment the challenge counter + metrics::inc_challenge_counter(self.address, true); + return Ok(tx_hash); } - _ = tokio::time::sleep(Duration::from_millis(CHALLENGE_POKE_DELAY_MS)) => { - // Verify that the OpPoked is valid - let is_valid = ScribeOptimisticProviderInstance::new( - self.address, - self.provider.clone() - ).is_schnorr_signature_valid(self.op_poked.clone()).await?; - - if is_valid { - log::debug!("OpPokedValidator[{:?}] OpPoked is valid, no need to challenge", self.address); - return Ok(()); - } - - // Perform the challenge process - self.challenge().await?; - Ok(()) + Err(e) => { + log::error!( + "OpPokedValidator[{:?}] Failed to send challenge transaction via flashbots: {:?}", + self.address, + e + ); } + } } - } - - // Perform the challenge process, first with flashbot provider, then with normal provider. - async fn challenge(&self) -> Result> { - // Perform the challenge after 200ms - let mut challenge_attempts: u64 = 0; - const RETRY_RANGE_END: u64 = CLASSIC_CHALLENGE_RETRY_COUNT + FLASHBOT_CHALLENGE_RETRY_COUNT; - - log::info!( - "OpPokedValidator[{:?}] Challending data: {:?}", - self.address, - self.op_poked - ); - - loop { - match challenge_attempts { - 0..FLASHBOT_CHALLENGE_RETRY_COUNT => { - log::debug!( - "OpPokedValidator[{:?}] Attempting flashbot challenge", - self.address - ); - let contract = ScribeOptimisticProviderInstance::new( - self.address, - self.flashbot_provider.clone(), - ); - - let result = contract.challenge(self.op_poked.schnorrData.clone()).await; - - match result { - Ok(tx_hash) => { - log::info!( - "OpPokedValidator[{:?}] Flashbot transaction sent via flashbots RPC: {:?}", - self.address, - tx_hash - ); - - // Increment the challenge counter - metrics::inc_challenge_counter(self.address, true); - return Ok(tx_hash); - } - Err(e) => { - log::error!( - "OpPokedValidator[{:?}] Failed to send challenge transaction via flashbots: {:?}", - self.address, - e - ); - } - } - } - FLASHBOT_CHALLENGE_RETRY_COUNT..RETRY_RANGE_END => { - log::debug!( - "OpPokedValidator[{:?}] Attempting public challenge", - self.address - ); - let contract = - ScribeOptimisticProviderInstance::new(self.address, self.provider.clone()); - match contract.challenge(self.op_poked.schnorrData.clone()).await { - Ok(tx_hash) => { - log::info!( - "OpPokedValidator[{:?}] Challenge transaction sent via public RPC: {:?}", - self.address, - tx_hash - ); - // Increment the challenge counter - metrics::inc_challenge_counter(self.address, false); - return Ok(tx_hash); - } - Err(e) => { - log::error!( - "OpPokedValidator[{:?}] Failed to send challenge transaction via public RPC: {:?}", - self.address, - e - ); - } - } - } - _ => { - log::error!( - "OpPokedValidator[{:?}] Challenge failed, total attempts {:?}", - self.address, - challenge_attempts - ); - break; - } + FLASHBOT_CHALLENGE_RETRY_COUNT..RETRY_RANGE_END => { + log::debug!( + "OpPokedValidator[{:?}] Attempting public challenge", + self.address + ); + let contract = ScribeOptimisticProviderInstance::new(self.address, self.provider.clone()); + match contract.challenge(self.op_poked.schnorrData.clone()).await { + Ok(tx_hash) => { + log::info!( + "OpPokedValidator[{:?}] Challenge transaction sent via public RPC: {:?}", + self.address, + tx_hash + ); + // Increment the challenge counter + metrics::inc_challenge_counter(self.address, false); + return Ok(tx_hash); + } + Err(e) => { + log::error!( + "OpPokedValidator[{:?}] Failed to send challenge transaction via public RPC: {:?}", + self.address, + e + ); } - challenge_attempts += 1; + } } - - bail!(format!( + _ => { + log::error!( "OpPokedValidator[{:?}] Challenge failed, total attempts {:?}", - self.address, challenge_attempts - )) + self.address, + challenge_attempts + ); + break; + } + } + challenge_attempts += 1; } + + bail!(format!( + "OpPokedValidator[{:?}] Challenge failed, total attempts {:?}", + self.address, challenge_attempts + )) + } } diff --git a/crates/scribe/src/events_listener.rs b/crates/scribe/src/events_listener.rs index f7d72a5..460540a 100644 --- a/crates/scribe/src/events_listener.rs +++ b/crates/scribe/src/events_listener.rs @@ -16,32 +16,32 @@ use std::{sync::Arc, time::Duration}; use alloy::{ - network::{Ethereum, EthereumWallet}, - primitives::Address, - providers::{ - fillers::{ - BlobGasFiller, CachedNonceManager, ChainIdFiller, FillProvider, GasFiller, JoinFill, - NonceFiller, WalletFiller, - }, - Identity, Provider, RootProvider, WalletProvider, - }, - rpc::types::{Filter, Log}, - sol_types::SolEvent, - transports::{ - http::{Client, Http}, - layers::RetryBackoffService, + network::{Ethereum, EthereumWallet}, + primitives::Address, + providers::{ + fillers::{ + BlobGasFiller, CachedNonceManager, ChainIdFiller, FillProvider, GasFiller, JoinFill, + NonceFiller, WalletFiller, }, + Identity, Provider, RootProvider, WalletProvider, + }, + rpc::types::{Filter, Log}, + sol_types::SolEvent, + transports::{ + http::{Client, Http}, + layers::RetryBackoffService, + }, }; use eyre::{bail, Context, Result}; use tokio::{select, sync::mpsc::Sender}; use tokio_util::sync::CancellationToken; use crate::{ - contract::{ - EventWithMetadata, - ScribeOptimistic::{OpPokeChallengedSuccessfully, OpPoked}, - }, - metrics, + contract::{ + EventWithMetadata, + ScribeOptimistic::{OpPokeChallengedSuccessfully, OpPoked}, + }, + metrics, }; // const POLL_INTERVAL_SEC: u64 = 30; @@ -53,25 +53,22 @@ pub type RpcRetryProvider = RetryBackoffService>; /// The provider type used to interact with the Ethereum network with a signer. pub type RetryProviderWithSigner = FillProvider< + JoinFill< JoinFill< + JoinFill< JoinFill< - JoinFill< - JoinFill< - Identity, - JoinFill< - GasFiller, - JoinFill>, - >, - >, - ChainIdFiller, - >, - NonceFiller, + Identity, + JoinFill>>, >, - WalletFiller, + ChainIdFiller, + >, + NonceFiller, >, - RootProvider>>, - RetryBackoffService>, - Ethereum, + WalletFiller, + >, + RootProvider>>, + RetryBackoffService>, + Ethereum, >; /// Poller is responsible for polling for new events in the Ethereum network. @@ -81,152 +78,150 @@ pub type RetryProviderWithSigner = FillProvider< /// For optimization reasons, it will query for events in chunks of `MAX_ADDRESS_PER_REQUEST` addresses. #[derive(Debug, Clone)] pub struct Poller { + addresses: Vec
, + cancelation_token: CancellationToken, + provider: Arc, + last_processes_block: Option, + tx: Sender, + poll_interval_seconds: u64, + retry_count: u16, +} + +impl Poller { + pub fn new( addresses: Vec
, cancelation_token: CancellationToken, provider: Arc, - last_processes_block: Option, tx: Sender, poll_interval_seconds: u64, - retry_count: u16, -} - -impl Poller { - pub fn new( - addresses: Vec
, - cancelation_token: CancellationToken, - provider: Arc, - tx: Sender, - poll_interval_seconds: u64, - ) -> Self { - Self { - addresses, - cancelation_token, - provider, - tx, - last_processes_block: None, - poll_interval_seconds, - retry_count: 0, - } + ) -> Self { + Self { + addresses, + cancelation_token, + provider, + tx, + last_processes_block: None, + poll_interval_seconds, + retry_count: 0, } - - async fn query_logs( - &self, - chunk: Vec
, - from_block: u64, - to_block: u64, - ) -> Result> { - let filter = Filter::new() - .address(chunk.to_vec()) - .from_block(from_block) - .to_block(to_block) - .event_signature(vec![ - OpPoked::SIGNATURE_HASH, - OpPokeChallengedSuccessfully::SIGNATURE_HASH, - ]); - - log::trace!("Poller: [{:?}] Getting for new events", &chunk); - - self.provider - .get_logs(&filter) - .await - .wrap_err_with(|| format!("Failed to get logs for addresses: {:?}", chunk)) + } + + async fn query_logs( + &self, + chunk: Vec
, + from_block: u64, + to_block: u64, + ) -> Result> { + let filter = Filter::new() + .address(chunk.to_vec()) + .from_block(from_block) + .to_block(to_block) + .event_signature(vec![ + OpPoked::SIGNATURE_HASH, + OpPokeChallengedSuccessfully::SIGNATURE_HASH, + ]); + + log::trace!("Poller: [{:?}] Getting for new events", &chunk); + + self + .provider + .get_logs(&filter) + .await + .wrap_err_with(|| format!("Failed to get logs for addresses: {:?}", chunk)) + } + + // Poll for new events in block range `self.last_processes_block..latest_block` + async fn poll(&mut self) -> Result<()> { + log::trace!("Poller: polling for new events"); + // Get latest block number + let latest_block = self.provider.get_block_number().await?; + if self.last_processes_block.is_none() { + log::info!("Poller: First run, setting last processed block to latest block"); + self.last_processes_block = Some(latest_block); } - - // Poll for new events in block range `self.last_processes_block..latest_block` - async fn poll(&mut self) -> Result<()> { - log::trace!("Poller: polling for new events"); - // Get latest block number - let latest_block = self.provider.get_block_number().await?; - if self.last_processes_block.is_none() { - log::info!("Poller: First run, setting last processed block to latest block"); - self.last_processes_block = Some(latest_block); - } - // TODO remove this line - if latest_block <= self.last_processes_block.unwrap_or(0) { - log::warn!( - "Poller: latest block {:?} is not greater than last processed block {:?}", - latest_block, - self.last_processes_block - ); - return Ok(()); + // TODO remove this line + if latest_block <= self.last_processes_block.unwrap_or(0) { + log::warn!( + "Poller: latest block {:?} is not greater than last processed block {:?}", + latest_block, + self.last_processes_block + ); + return Ok(()); + } + // Split addresses into chunks of MAX_ADDRESS_PER_REQUEST to optimize amount of requests + for chunk in self.addresses.chunks(MAX_ADDRESS_PER_REQUEST) { + let logs = self + .query_logs( + chunk.to_vec(), + self.last_processes_block.unwrap(), // unwrap is safe because we checked it in the beginning + latest_block, + ) + .await; + + match logs { + Ok(logs) => { + log::debug!("Poller: [{:?}] Received {} logs", chunk, logs.len()); + for log in logs { + match EventWithMetadata::from_log(log) { + Ok(event) => { + log::debug!( + "Poller: [{:?}] Event received for address {:?} processing", + chunk, + &event.address + ); + // Send event to the channel + self.tx.send(event).await?; + } + Err(e) => { + log::error!("Poller: [{:?}] Failed to parse log: {:?}", chunk, e); + continue; + } + }; + } } - // Split addresses into chunks of MAX_ADDRESS_PER_REQUEST to optimize amount of requests - for chunk in self.addresses.chunks(MAX_ADDRESS_PER_REQUEST) { - let logs = self - .query_logs( - chunk.to_vec(), - self.last_processes_block.unwrap(), // unwrap is safe because we checked it in the beginning - latest_block, - ) - .await; - - match logs { - Ok(logs) => { - log::debug!("Poller: [{:?}] Received {} logs", chunk, logs.len()); - for log in logs { - match EventWithMetadata::from_log(log) { - Ok(event) => { - log::debug!( - "Poller: [{:?}] Event received for address {:?} processing", - chunk, - &event.address - ); - // Send event to the channel - self.tx.send(event).await?; - } - Err(e) => { - log::error!("Poller: [{:?}] Failed to parse log: {:?}", chunk, e); - continue; - } - }; - } - } - Err(e) => { - // TODO: retry? - bail!("Poller: Failed to query logs: {:?}", e); - } - } + Err(e) => { + // TODO: retry? + bail!("Poller: Failed to query logs: {:?}", e); } - - // Reset retry count, or might be issues - self.retry_count = 0; - self.last_processes_block = Some(latest_block); - // Updating last scanned block metric - metrics::set_last_scanned_block( - self.provider.default_signer_address(), - latest_block as i64, - ); - - Ok(()) + } } - /// Start the event listener - pub async fn start(&mut self) -> Result<()> { - log::info!("Poller: Starting polling events from RPC..."); - - loop { - select! { - _ = self.cancelation_token.cancelled() => { - log::info!("Poller: got cancel signal, terminating..."); - return Ok(()); - } - _ = tokio::time::sleep(Duration::from_secs(self.poll_interval_seconds)) => { - log::info!("Poller: Executing tick for events listener..."); - if let Err(err) = self.poll().await { - if self.retry_count >= MAX_RETRY_COUNT { - log::error!( - "Poller: Max {} reties reached, will not retry anymore: {:?}", - MAX_RETRY_COUNT, - err - ); - return Err(err); - } - - self.retry_count += 1; - log::error!("Poller: Failed to poll for events, will retry: {:?}", err); - } - } - } - } + // Reset retry count, or might be issues + self.retry_count = 0; + self.last_processes_block = Some(latest_block); + // Updating last scanned block metric + metrics::set_last_scanned_block(self.provider.default_signer_address(), latest_block as i64); + + Ok(()) + } + + /// Start the event listener + pub async fn start(&mut self) -> Result<()> { + log::info!("Poller: Starting polling events from RPC..."); + + loop { + select! { + _ = self.cancelation_token.cancelled() => { + log::info!("Poller: got cancel signal, terminating..."); + return Ok(()); + } + _ = tokio::time::sleep(Duration::from_secs(self.poll_interval_seconds)) => { + log::info!("Poller: Executing tick for events listener..."); + if let Err(err) = self.poll().await { + if self.retry_count >= MAX_RETRY_COUNT { + log::error!( + "Poller: Max {} reties reached, will not retry anymore: {:?}", + MAX_RETRY_COUNT, + err + ); + return Err(err); + } + + self.retry_count += 1; + log::error!("Poller: Failed to poll for events, will retry: {:?}", err); + } + } + } } + } } diff --git a/crates/scribe/src/metrics.rs b/crates/scribe/src/metrics.rs index f2a7ce9..bdc7f34 100644 --- a/crates/scribe/src/metrics.rs +++ b/crates/scribe/src/metrics.rs @@ -22,42 +22,42 @@ const CHALLENGE_COUNTER: &str = "challenger_challenges_total"; /// `set_last_scanned_block` sets the last scanned block for given `address` and `from` account. pub fn set_last_scanned_block(from: Address, block: i64) { - let labels = [(("from"), format!("{:?}", from))]; - gauge!(LAST_SCANNED_BLOCK_GAUGE, &labels).set(block as f64); + let labels = [(("from"), format!("{:?}", from))]; + gauge!(LAST_SCANNED_BLOCK_GAUGE, &labels).set(block as f64); } /// `inc_errors_counter` increments the errors counter for given `address`, `from` account pub fn inc_errors_counter(address: Address, error: &str) { - // TODO: Use it... - let labels = [ - ("address", format!("{:?}", address)), - ("error", String::from(error)), - ]; - counter!(ERRORS_COUNTER, &labels).increment(1); + // TODO: Use it... + let labels = [ + ("address", format!("{:?}", address)), + ("error", String::from(error)), + ]; + counter!(ERRORS_COUNTER, &labels).increment(1); } /// `inc_challenge_counter` increments the challenges counter for given `address` and `tx` hash. pub fn inc_challenge_counter(address: Address, flashbots: bool) { - let labels = [ - ("address", format!("{:?}", address)), - ("flashbots", format!("{:?}", flashbots)), - ]; - counter!(CHALLENGE_COUNTER, &labels).increment(1); + let labels = [ + ("address", format!("{:?}", address)), + ("flashbots", format!("{:?}", flashbots)), + ]; + counter!(CHALLENGE_COUNTER, &labels).increment(1); } /// `register_custom_metrics` registers custom metrics to the registry. /// It have to be called before you start processing & if you plans to serve `/metrics` route. pub fn describe() { - describe_counter!( - ERRORS_COUNTER, - "Counts different errors in challenger process by given address" - ); - describe_counter!( - CHALLENGE_COUNTER, - "Counts happened challenges for given address and from account" - ); - describe_gauge!( - LAST_SCANNED_BLOCK_GAUGE, - "Keeps track of last scanned block for given address and from account" - ); + describe_counter!( + ERRORS_COUNTER, + "Counts different errors in challenger process by given address" + ); + describe_counter!( + CHALLENGE_COUNTER, + "Counts happened challenges for given address and from account" + ); + describe_gauge!( + LAST_SCANNED_BLOCK_GAUGE, + "Keeps track of last scanned block for given address and from account" + ); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/src/main.rs b/src/main.rs index 1275e59..cbb3823 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,429 +13,421 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use alloy::primitives::Address; -use alloy::providers::fillers::{CachedNonceManager, ChainIdFiller, NonceFiller}; -use alloy::providers::ProviderBuilder; -use alloy::rpc::client::ClientBuilder; -use alloy::transports::layers::RetryBackoffLayer; +use alloy::{ + primitives::Address, + providers::{ + fillers::{CachedNonceManager, ChainIdFiller, NonceFiller}, + ProviderBuilder, + }, + rpc::client::ClientBuilder, + transports::layers::RetryBackoffLayer, +}; use clap::Parser; use env_logger::Env; - use eyre::Result; use log::{error, info}; -use scribe::contract::EventWithMetadata; -use scribe::events_listener::Poller; -use scribe::metrics; -use std::net::SocketAddr; -use std::sync::Arc; -use std::{env, panic, path::PathBuf, time::Duration}; -use tokio::time::sleep; +use metrics_exporter_prometheus::PrometheusBuilder; +use metrics_process::Collector; +use scribe::{contract::EventWithMetadata, events_listener::Poller, metrics}; +use std::{env, net::SocketAddr, panic, path::PathBuf, sync::Arc, time::Duration}; +use tokio::{select, signal, task::JoinSet, time::sleep}; use tokio_util::sync::CancellationToken; use scribe::events_handler; mod wallet; - -use tokio::task::JoinSet; -use tokio::{select, signal}; - use wallet::{CustomWallet, KeystoreWallet, PrivateKeyWallet}; -use metrics_exporter_prometheus::PrometheusBuilder; -use metrics_process::Collector; - /// Cli interface for the challenger. #[derive(Parser, Debug)] #[command(author, version, about)] struct Cli { - #[arg( - short = 'a', - long, - help = "ScribeOptimistic contract addresses. Example: `0x891E368fE81cBa2aC6F6cc4b98e684c106e2EF4f`" - )] - addresses: Vec, - - #[arg(long, help = "Node HTTP RPC_URL, normally starts with https://****")] - rpc_url: String, - - #[arg( - long, - help = "Flashbot Node HTTP RPC_URL, normally starts with https://****" - )] - flashbot_rpc_url: String, - - #[arg( - long = "secret-key", - help = "Private key in format `0x******` or `*******`. If provided, no need to use --keystore" - )] - raw_secret_key: Option, - - #[arg( - long = "keystore", - env = "ETH_KEYSTORE", - help = "Keystore file (NOT FOLDER), path to key .json file. If provided, no need to use --secret-key" - )] - keystore_path: Option, - - #[arg( - long = "password", - requires = "keystore_path", - help = "Key raw password as text" - )] - raw_password: Option, - - #[arg( - long, - requires = "keystore_path", - env = "ETH_PASSWORD", - help = "Path to key password file" - )] - password_file: Option, - - #[arg( - long, - help = "If no chain_id provided binary will try to get chain_id from given RPC" - )] - chain_id: Option, + #[arg( + short = 'a', + long, + help = "ScribeOptimistic contract addresses. Example: `0x891E368fE81cBa2aC6F6cc4b98e684c106e2EF4f`" + )] + addresses: Vec, + + #[arg(long, help = "Node HTTP RPC_URL, normally starts with https://****")] + rpc_url: String, + + #[arg( + long, + help = "Flashbot Node HTTP RPC_URL, normally starts with https://****" + )] + flashbot_rpc_url: String, + + #[arg( + long = "secret-key", + help = "Private key in format `0x******` or `*******`. If provided, no need to use --keystore" + )] + raw_secret_key: Option, + + #[arg( + long = "keystore", + env = "ETH_KEYSTORE", + help = "Keystore file (NOT FOLDER), path to key .json file. If provided, no need to use --secret-key" + )] + keystore_path: Option, + + #[arg( + long = "password", + requires = "keystore_path", + help = "Key raw password as text" + )] + raw_password: Option, + + #[arg( + long, + requires = "keystore_path", + env = "ETH_PASSWORD", + help = "Path to key password file" + )] + password_file: Option, + + #[arg( + long, + help = "If no chain_id provided binary will try to get chain_id from given RPC" + )] + chain_id: Option, } impl PrivateKeyWallet for Cli { - fn raw_private_key(&self) -> Option { - self.raw_secret_key.clone() - } + fn raw_private_key(&self) -> Option { + self.raw_secret_key.clone() + } } impl KeystoreWallet for Cli { - fn keystore_path(&self) -> Option { - self.keystore_path.clone() - } + fn keystore_path(&self) -> Option { + self.keystore_path.clone() + } - fn raw_password(&self) -> Option { - self.raw_password.clone() - } + fn raw_password(&self) -> Option { + self.raw_password.clone() + } - fn password_file(&self) -> Option { - self.password_file.clone() - } + fn password_file(&self) -> Option { + self.password_file.clone() + } } impl CustomWallet for Cli {} #[tokio::main] async fn main() -> Result<()> { - // Setting default log level to info - env_logger::Builder::from_env( - Env::default().default_filter_or("info,challenger=debug,scribe=trace"), - ) - .init(); - - let args = Cli::parse(); - - log::info!("Using RPC URL: {:?}", &args.rpc_url); + // Setting default log level to info + env_logger::Builder::from_env( + Env::default().default_filter_or("info,challenger=debug,scribe=trace"), + ) + .init(); + + let args = Cli::parse(); + + log::info!("Using RPC URL: {:?}", &args.rpc_url); + + // Building tx signer for provider + let signer = args.wallet()?.unwrap(); + info!( + "Using {:?} for signing transactions.", + signer.default_signer().address() + ); + let nonce_manager = NonceFiller::::default(); + + // Create new HTTP client with retry backoff layer + let client = ClientBuilder::default() + .layer(RetryBackoffLayer::new(15, 200, 300)) + .http(args.rpc_url.parse()?); + + let provider = Arc::new( + ProviderBuilder::new() + // Add gas automatic gas field completion + .with_recommended_fillers() + // Add chain id request from rpc + .filler(ChainIdFiller::new(args.chain_id)) + .filler(nonce_manager.clone()) + // Add default signer + .wallet(signer.clone()) + .on_client(client), + ); + + // Create new HTTP client for flashbots + // TODO add correct gas handling etc. + let flashbot_client = ClientBuilder::default() + .layer(RetryBackoffLayer::new(15, 200, 300)) + .http(args.flashbot_rpc_url.parse()?); + + let flashbot_provider = Arc::new( + ProviderBuilder::new() + // Add gas automatic gas field completion + .with_recommended_fillers() + // Add chain id request from rpc + .filler(ChainIdFiller::new(args.chain_id)) + .filler(nonce_manager.clone()) + // Add default signer + .wallet(signer.clone()) + .on_client(flashbot_client), + ); + + // let signer_lock = Arc::new(Mutex::new(signer)); + + let mut set = JoinSet::new(); + let cancel_token = CancellationToken::new(); + + // Removing duplicates from list of provided addresses + let mut addresses = args.addresses; + addresses.dedup(); + let addresses: Vec
= addresses + .iter() + .map(|a| a.parse().unwrap()) + .collect::>(); + + // Register Prometheus metrics + let builder = PrometheusBuilder::new(); + + let port = env::var("HTTP_PORT") + .unwrap_or(String::from("9090")) + .parse::() + .unwrap(); + let addr = SocketAddr::from(([0, 0, 0, 0], port)); + + let _ = builder.with_http_listener(addr).install(); + + // .expect("failed to install Prometheus recorder"); + + log::info!("Starting Prometheus metrics collector on port: {}", port); + + // Add challenger metrics description + metrics::describe(); + + // Add Prometheus metrics help for process metrics + let collector = Collector::new("challenger_"); + collector.describe(); + + let (tx, rx) = tokio::sync::mpsc::channel::(100); + + // Create events listener + let mut poller = Poller::new( + addresses.clone(), + cancel_token.clone(), + provider.clone(), + tx.clone(), + 30, + ); + + // Create event distributor + let mut event_distributor = events_handler::EventDistributor::new( + addresses.clone(), + cancel_token.clone(), + provider.clone(), + flashbot_provider.clone(), + rx, + ); + + // Run events listener process + set.spawn(async move { + log::info!("Starting events listener"); + if let Err(err) = poller.start().await { + log::error!("Poller error: {:?}", err); + } + }); - // Building tx signer for provider - let signer = args.wallet()?.unwrap(); - info!( - "Using {:?} for signing transactions.", - signer.default_signer().address() - ); - let nonce_manager = NonceFiller::::default(); + // Run event distributor process + set.spawn(async move { + log::info!("Starting log handler"); + if let Err(err) = event_distributor.start().await { + log::error!("Log Handler error: {:?}", err); + } + }); + + // Run metrics collector process + let metrics_cancelation_token = cancel_token.clone(); + set.spawn(async move { + let duration = Duration::from_millis(750); + log::info!("Starting metrics collector"); + + loop { + select! { + _ = metrics_cancelation_token.cancelled() => { + log::info!("Metrics collector stopped"); + return; + }, + _ = sleep(duration) => { + collector.collect(); + } + } + } + }); + + tokio::select! { + _ = signal::ctrl_c() => { + info!("Received Ctrl-C, shutting down"); + cancel_token.cancel(); + }, + + // some process terminated, no need to wait for others + res = set.join_next() => { + match res.unwrap() { + Ok(_) => { + info!("Task terminated without error, shutting down"); + cancel_token.cancel(); + }, + Err(e) => { + error!("Task terminated with error: {:#?}", e.to_string()); + }, + } + }, + } + + // Wait for all tasks to finish + set.join_all().await; + + Ok(()) +} - // Create new HTTP client with retry backoff layer - let client = ClientBuilder::default() - .layer(RetryBackoffLayer::new(15, 200, 300)) - .http(args.rpc_url.parse()?); +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use alloy::primitives::address; + + use super::*; + + #[test] + fn builds_wallet_from_private_key() { + let cli = Cli { + addresses: vec![], + raw_secret_key: Some( + "def90b5b5cb2d68c5cd9de7b3e6d767cbb1b8d5fd8560bd6c42cbc4a4da30b16".to_string(), + ), + chain_id: None, + keystore_path: None, + raw_password: None, + password_file: None, + rpc_url: "http://localhost:8545".to_string(), + flashbot_rpc_url: "http://localhost:8545".to_string(), + }; - let provider = Arc::new( - ProviderBuilder::new() - // Add gas automatic gas field completion - .with_recommended_fillers() - // Add chain id request from rpc - .filler(ChainIdFiller::new(args.chain_id)) - .filler(nonce_manager.clone()) - // Add default signer - .wallet(signer.clone()) - .on_client(client), - ); + let wallet = cli.wallet().unwrap().unwrap(); - // Create new HTTP client for flashbots - // TODO add correct gas handling etc. - let flashbot_client = ClientBuilder::default() - .layer(RetryBackoffLayer::new(15, 200, 300)) - .http(args.flashbot_rpc_url.parse()?); - - let flashbot_provider = Arc::new( - ProviderBuilder::new() - // Add gas automatic gas field completion - .with_recommended_fillers() - // Add chain id request from rpc - .filler(ChainIdFiller::new(args.chain_id)) - .filler(nonce_manager.clone()) - // Add default signer - .wallet(signer.clone()) - .on_client(flashbot_client), + assert_eq!( + wallet.default_signer().address(), + address!("91543660a715018cb35918add3085d08d7194724") ); - // let signer_lock = Arc::new(Mutex::new(signer)); - - let mut set = JoinSet::new(); - let cancel_token = CancellationToken::new(); - - // Removing duplicates from list of provided addresses - let mut addresses = args.addresses; - addresses.dedup(); - let addresses: Vec
= addresses - .iter() - .map(|a| a.parse().unwrap()) - .collect::>(); - - // Register Prometheus metrics - let builder = PrometheusBuilder::new(); - - let port = env::var("HTTP_PORT") - .unwrap_or(String::from("9090")) - .parse::() - .unwrap(); - let addr = SocketAddr::from(([0, 0, 0, 0], port)); - - let _ = builder.with_http_listener(addr).install(); - - // .expect("failed to install Prometheus recorder"); - - log::info!("Starting Prometheus metrics collector on port: {}", port); - - // Add challenger metrics description - metrics::describe(); - - // Add Prometheus metrics help for process metrics - let collector = Collector::new("challenger_"); - collector.describe(); - - let (tx, rx) = tokio::sync::mpsc::channel::(100); + // Works with `0x` prefix + let cli = Cli { + addresses: vec![], + raw_secret_key: Some( + "0xdef90b5b5cb2d68c5cd9de7b3e6d767cbb1b8d5fd8560bd6c42cbc4a4da30b16".to_string(), + ), + chain_id: None, + keystore_path: None, + raw_password: None, + password_file: None, + rpc_url: "http://localhost:8545".to_string(), + flashbot_rpc_url: "http://localhost:8545".to_string(), + }; - // Create events listener - let mut poller = Poller::new( - addresses.clone(), - cancel_token.clone(), - provider.clone(), - tx.clone(), - 30, - ); + let wallet = cli.wallet().unwrap().unwrap(); - // Create event distributor - let mut event_distributor = events_handler::EventDistributor::new( - addresses.clone(), - cancel_token.clone(), - provider.clone(), - flashbot_provider.clone(), - rx, + assert_eq!( + wallet.default_signer().address(), + address!("91543660a715018cb35918add3085d08d7194724") ); + } + + #[test] + fn keystore_works_with_password_in_file() { + let keystore = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore"); + let keystore_file = keystore + .join("UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2"); + + let keystore_password_file = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore/password"); + + let cli = Cli { + addresses: vec![], + raw_secret_key: None, + chain_id: None, + keystore_path: Some(keystore_file), + raw_password: None, + password_file: Some(keystore_password_file), + rpc_url: "http://localhost:8545".to_string(), + flashbot_rpc_url: "http://localhost:8545".to_string(), + }; - // Run events listener process - set.spawn(async move { - log::info!("Starting events listener"); - if let Err(err) = poller.start().await { - log::error!("Poller error: {:?}", err); - } - }); - - // Run event distributor process - set.spawn(async move { - log::info!("Starting log handler"); - if let Err(err) = event_distributor.start().await { - log::error!("Log Handler error: {:?}", err); - } - }); - - // Run metrics collector process - let metrics_cancelation_token = cancel_token.clone(); - set.spawn(async move { - let duration = Duration::from_millis(750); - log::info!("Starting metrics collector"); - - loop { - select! { - _ = metrics_cancelation_token.cancelled() => { - log::info!("Metrics collector stopped"); - return; - }, - _ = sleep(duration) => { - collector.collect(); - } - } - } - }); - - tokio::select! { - _ = signal::ctrl_c() => { - info!("Received Ctrl-C, shutting down"); - cancel_token.cancel(); - }, - - // some process terminated, no need to wait for others - res = set.join_next() => { - match res.unwrap() { - Ok(_) => { - info!("Task terminated without error, shutting down"); - cancel_token.cancel(); - }, - Err(e) => { - error!("Task terminated with error: {:#?}", e.to_string()); - }, - } - }, - } - - // Wait for all tasks to finish - set.join_all().await; - - Ok(()) -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use alloy::primitives::address; - - use super::*; - - #[test] - fn builds_wallet_from_private_key() { - let cli = Cli { - addresses: vec![], - raw_secret_key: Some( - "def90b5b5cb2d68c5cd9de7b3e6d767cbb1b8d5fd8560bd6c42cbc4a4da30b16".to_string(), - ), - chain_id: None, - keystore_path: None, - raw_password: None, - password_file: None, - rpc_url: "http://localhost:8545".to_string(), - flashbot_rpc_url: "http://localhost:8545".to_string(), - }; - - let wallet = cli.wallet().unwrap().unwrap(); - - assert_eq!( - wallet.default_signer().address(), - address!("91543660a715018cb35918add3085d08d7194724") - ); + let wallet = cli.wallet().unwrap().unwrap(); - // Works with `0x` prefix - let cli = Cli { - addresses: vec![], - raw_secret_key: Some( - "0xdef90b5b5cb2d68c5cd9de7b3e6d767cbb1b8d5fd8560bd6c42cbc4a4da30b16".to_string(), - ), - chain_id: None, - keystore_path: None, - raw_password: None, - password_file: None, - rpc_url: "http://localhost:8545".to_string(), - flashbot_rpc_url: "http://localhost:8545".to_string(), - }; - - let wallet = cli.wallet().unwrap().unwrap(); - - assert_eq!( - wallet.default_signer().address(), - address!("91543660a715018cb35918add3085d08d7194724") - ); - } + assert_eq!( + wallet.default_signer().address(), + address!("ec554aeafe75601aaab43bd4621a22284db566c2") + ); + } + + #[test] + fn keystore_works_with_raw_password() { + let keystore = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore"); + let keystore_file = keystore + .join("UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2"); + + let cli = Cli { + addresses: vec![], + raw_secret_key: None, + chain_id: None, + keystore_path: Some(keystore_file), + raw_password: Some("keystorepassword".to_string()), + password_file: None, + rpc_url: "http://localhost:8545".to_string(), + flashbot_rpc_url: "http://localhost:8545".to_string(), + }; - #[test] - fn keystore_works_with_password_in_file() { - let keystore = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore"); - let keystore_file = keystore - .join("UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2"); - - let keystore_password_file = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore/password"); - - let cli = Cli { - addresses: vec![], - raw_secret_key: None, - chain_id: None, - keystore_path: Some(keystore_file), - raw_password: None, - password_file: Some(keystore_password_file), - rpc_url: "http://localhost:8545".to_string(), - flashbot_rpc_url: "http://localhost:8545".to_string(), - }; - - let wallet = cli.wallet().unwrap().unwrap(); - - assert_eq!( - wallet.default_signer().address(), - address!("ec554aeafe75601aaab43bd4621a22284db566c2") - ); - } + let wallet = cli.wallet().unwrap().unwrap(); - #[test] - fn keystore_works_with_raw_password() { - let keystore = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/keystore"); - let keystore_file = keystore - .join("UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2"); - - let cli = Cli { - addresses: vec![], - raw_secret_key: None, - chain_id: None, - keystore_path: Some(keystore_file), - raw_password: Some("keystorepassword".to_string()), - password_file: None, - rpc_url: "http://localhost:8545".to_string(), - flashbot_rpc_url: "http://localhost:8545".to_string(), - }; - - let wallet = cli.wallet().unwrap().unwrap(); - - assert_eq!( - wallet.default_signer().address(), - address!("ec554aeafe75601aaab43bd4621a22284db566c2") - ); - } + assert_eq!( + wallet.default_signer().address(), + address!("ec554aeafe75601aaab43bd4621a22284db566c2") + ); + } } #[cfg(test)] mod integration_tests { - use core::panic; - use std::cell::Cell; - use std::sync::Arc; - use std::time::Duration; - use std::vec; - - use alloy::hex; - use alloy::network::{Ethereum, EthereumWallet, Network}; - use alloy::node_bindings::{Anvil, AnvilInstance}; - use alloy::primitives::U256; - use alloy::primitives::{Address, FixedBytes}; - use alloy::providers::ext::AnvilApi; - use alloy::providers::fillers::{ + use core::panic; + use std::{cell::Cell, sync::Arc, time::Duration, vec}; + + use alloy::{ + hex, + network::{Ethereum, EthereumWallet, Network}, + node_bindings::{Anvil, AnvilInstance}, + primitives::{Address, FixedBytes, U256}, + providers::{ + ext::AnvilApi, + fillers::{ BlobGasFiller, CachedNonceManager, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller, - }; - use alloy::providers::{Identity, Provider, ProviderBuilder, RootProvider}; - use alloy::rpc::client::ClientBuilder; - use alloy::signers::local::PrivateKeySigner; - use alloy::signers::SignerSync; - use alloy::transports::http::reqwest::Url; - use alloy::transports::http::{Client, Http}; - use alloy::transports::layers::RetryBackoffLayer; - use alloy::transports::Transport; - use futures_util::future::join_all; - use scribe::contract::EventWithMetadata; - use scribe::events_handler; - use scribe::events_listener::Poller; - use scribe_optimistic::{ - IScribe, LibSecp256k1, ScribeOptimistic, ScribeOptimistic::ScribeOptimisticInstance, - }; - use tokio::task::JoinSet; - use tokio_util::sync::CancellationToken; - - // In a separate module due to problems with autoformatter - #[rustfmt::skip] + }, + Identity, Provider, ProviderBuilder, RootProvider, + }, + rpc::client::ClientBuilder, + signers::{local::PrivateKeySigner, SignerSync}, + transports::{ + http::{reqwest::Url, Client, Http}, + layers::RetryBackoffLayer, + Transport, + }, + }; + use futures_util::future::join_all; + use scribe::{contract::EventWithMetadata, events_handler, events_listener::Poller}; + use scribe_optimistic::{ + IScribe, LibSecp256k1, ScribeOptimistic, ScribeOptimistic::ScribeOptimisticInstance, + }; + use tokio::task::JoinSet; + use tokio_util::sync::CancellationToken; + + // In a separate module due to problems with autoformatter + #[rustfmt::skip] mod scribe_optimistic { use alloy::sol; sol!( @@ -447,561 +439,558 @@ mod integration_tests { ); } - type AnvilProvider = Arc< - FillProvider< + type AnvilProvider = Arc< + FillProvider< + JoinFill< + JoinFill< + JoinFill< JoinFill< - JoinFill< - JoinFill< - JoinFill< - Identity, - JoinFill< - GasFiller, - JoinFill>, - >, - >, - WalletFiller, - >, - ChainIdFiller, - >, - NonceFiller, + Identity, + JoinFill>>, >, - RootProvider>, - Http, - Ethereum, + WalletFiller, + >, + ChainIdFiller, >, - >; - - const PRIVATE_KEY: &str = "d4cf162c2e26ff75095922ea108d516ff07bdd732f050e64ced632980f11320b"; - - // -- Tests -- - - #[tokio::test] - async fn challenge_contract() { - // Test an invalid poke on multiple scribe instances in parallel are successfully challenged - const NUM_SCRIBE_INSTANCES: usize = 100; - const CHALLENGE_PERIOD: u16 = 1000; - - // ------------------------------------------------------------------------------------------------------------ - let private_key = PRIVATE_KEY; - let (anvil, anvil_provider, signer) = create_anvil_instances(private_key, 8545).await; - - // set to a low current time for now, this avoids having stale poke error later - anvil_provider - .anvil_set_time(1000) - .await - .expect("Failed to set time"); - - let mut deployments = vec![]; - let mut scribes = vec![]; - for i in 0..NUM_SCRIBE_INSTANCES { - deployments.push(deploy_scribe( - anvil_provider.clone(), - signer.clone(), - CHALLENGE_PERIOD, - )); - // Only deploy at most 20 in parallel - if i % 20 == 0 { - scribes.append(&mut join_all(deployments).await); - deployments = vec![]; - } - } + NonceFiller, + >, + RootProvider>, + Http, + Ethereum, + >, + >; + + const PRIVATE_KEY: &str = "d4cf162c2e26ff75095922ea108d516ff07bdd732f050e64ced632980f11320b"; + + // -- Tests -- + + #[tokio::test] + async fn challenge_contract() { + // Test an invalid poke on multiple scribe instances in parallel are successfully challenged + const NUM_SCRIBE_INSTANCES: usize = 100; + const CHALLENGE_PERIOD: u16 = 1000; + + // ------------------------------------------------------------------------------------------------------------ + let private_key = PRIVATE_KEY; + let (anvil, anvil_provider, signer) = create_anvil_instances(private_key, 8545).await; + + // set to a low current time for now, this avoids having stale poke error later + anvil_provider + .anvil_set_time(1000) + .await + .expect("Failed to set time"); + + let mut deployments = vec![]; + let mut scribes = vec![]; + for i in 0..NUM_SCRIBE_INSTANCES { + deployments.push(deploy_scribe( + anvil_provider.clone(), + signer.clone(), + CHALLENGE_PERIOD, + )); + // Only deploy at most 20 in parallel + if i % 20 == 0 { scribes.append(&mut join_all(deployments).await); - let mut scribe_addresses = vec![]; - - let mut balance_updates = vec![]; - for scribe_optimistic in scribes.iter().take(NUM_SCRIBE_INSTANCES) { - scribe_addresses.push(*scribe_optimistic.address()); - balance_updates.push(anvil_provider.anvil_set_balance( - *scribe_optimistic.address(), - U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), - )); - } - for balance_update in join_all(balance_updates).await { - balance_update.expect("Unable to set balance"); - } - - // Update current anvil time to be far from last scribe config update - // The more scribe instances the further back in time a the anvil block timestamp doesn't stay in sync with chrono - // TODO add challenge period variable - let current_timestamp = - (chrono::Utc::now().timestamp() as u64) - (CHALLENGE_PERIOD as u64) + 1; - anvil_provider - .anvil_set_time(current_timestamp) - .await - .expect("Failed to set time"); - - // ------------------------------------------------------------------------------------------------------------ - let cancel_token: CancellationToken = CancellationToken::new(); - - // start the event listener as a sub process - { - let signer: EthereumWallet = EthereumWallet::new(PrivateKeySigner::random()); - anvil_provider - .anvil_set_balance( - signer.default_signer().address(), - U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), - ) - .await - .expect("Unable to set balance"); - let addresses = scribe_addresses.clone(); - let cancel_token = cancel_token.clone(); - let url = anvil.endpoint_url(); - let signer = signer.clone(); - tokio::spawn(async move { - start_event_listener(url, signer, cancel_token, addresses).await; - }); - } - - // Let first poll occur on poller - tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; - - // Increase current block count to move away from poller initialisation block - anvil_provider - .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) - .await - .expect("Failed to mine"); - - // ------------------------------------------------------------------------------------------------------------ - let mut invalid_pokes = vec![]; - for i in 0..NUM_SCRIBE_INSTANCES { - // Assert that the current contract balance is not 0 - let balance = anvil_provider - .get_balance(scribe_addresses[i]) - .await - .expect("Failed to get balance"); - assert_ne!(balance, U256::from(0)); - invalid_pokes.push(make_invalid_op_poke( - current_timestamp, - private_key, - &scribes[i], - )); - // Do at most 50 at the same time - if i % 50 == 0 { - join_all(invalid_pokes).await; - invalid_pokes = vec![]; - } - } - join_all(invalid_pokes).await; + deployments = vec![]; + } + } + scribes.append(&mut join_all(deployments).await); + let mut scribe_addresses = vec![]; + + let mut balance_updates = vec![]; + for scribe_optimistic in scribes.iter().take(NUM_SCRIBE_INSTANCES) { + scribe_addresses.push(*scribe_optimistic.address()); + balance_updates.push(anvil_provider.anvil_set_balance( + *scribe_optimistic.address(), + U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), + )); + } + for balance_update in join_all(balance_updates).await { + balance_update.expect("Unable to set balance"); + } - // Mine at least one block to ensure log is processed - anvil_provider - .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) - .await - .expect("Failed to mine"); - - let result = join_all((0..NUM_SCRIBE_INSTANCES).map(|i| { - poll_balance_is_zero( - &anvil_provider, - &scribe_addresses[i], - (20 + (10 * NUM_SCRIBE_INSTANCES) / 100).try_into().unwrap(), - ) - })) + // Update current anvil time to be far from last scribe config update + // The more scribe instances the further back in time a the anvil block timestamp doesn't stay in sync with chrono + // TODO add challenge period variable + let current_timestamp = (chrono::Utc::now().timestamp() as u64) - (CHALLENGE_PERIOD as u64) + 1; + anvil_provider + .anvil_set_time(current_timestamp) + .await + .expect("Failed to set time"); + + // ------------------------------------------------------------------------------------------------------------ + let cancel_token: CancellationToken = CancellationToken::new(); + + // start the event listener as a sub process + { + let signer: EthereumWallet = EthereumWallet::new(PrivateKeySigner::random()); + anvil_provider + .anvil_set_balance( + signer.default_signer().address(), + U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), + ) .await - .iter() - .all(|&result| result); - - // Poll to check that the challenge started log is found, - // (to ensure log hasn't been changed as its non appearance is looked for in other tests) - for i in 0..5 { - let success: Cell = Cell::new(false); - testing_logger::validate(|captured_logs| { - let mut found: bool = false; - for log in captured_logs { - found |= log - .body - .to_lowercase() - .contains(&"OpPoked validation started".to_lowercase()); - } - success.set(found); - }); - if success.get() { - break; - } - tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; - if i == 4 { - panic!("Failed to find log"); - } - } - - if result { - cancel_token.cancel(); - return; - } - cancel_token.cancel(); - panic!("Failed to challenge"); + .expect("Unable to set balance"); + let addresses = scribe_addresses.clone(); + let cancel_token = cancel_token.clone(); + let url = anvil.endpoint_url(); + let signer = signer.clone(); + tokio::spawn(async move { + start_event_listener(url, signer, cancel_token, addresses).await; + }); } - #[tokio::test] - async fn dont_challenge_outside_challenge_period() { - testing_logger::setup(); - // Test an invalid poke on multiple scribe instances is successfully challenged - // ------------------------------------------------------------------------------------------------------------ - let private_key = PRIVATE_KEY; - // Use a new port for each test to avoid conflicts if tests run in parallel - let (anvil, anvil_provider, signer) = create_anvil_instances(private_key, 8546).await; - - // Set to a low current time for now, this avoids having stale poke error later - anvil_provider - .anvil_set_time(1000) - .await - .expect("Failed to set time"); - - // Deploy scribe instance - let scribe_optimistic = deploy_scribe(anvil_provider.clone(), signer.clone(), 300).await; - anvil_provider - .anvil_set_balance( - *scribe_optimistic.address(), - U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), - ) - .await - .expect("Unable to set balance"); - - // Update current anvil time to be far from last scribe config update - // Set the anvil time to be in the past to ensure the challenge period is exceeded later - let current_timestamp = (chrono::Utc::now().timestamp() as u64) - 400; - anvil_provider - .anvil_set_time(current_timestamp) - .await - .expect("Failed to set time"); - - // ------------------------------------------------------------------------------------------------------------ - let cancel_token: CancellationToken = CancellationToken::new(); - - // start the event listener as a sub process - { - let signer: EthereumWallet = EthereumWallet::new(PrivateKeySigner::random()); - anvil_provider - .anvil_set_balance( - signer.default_signer().address(), - U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), - ) - .await - .expect("Unable to set balance"); - let addresses = vec![*scribe_optimistic.address()]; - let cancel_token = cancel_token.clone(); - let url = anvil.endpoint_url(); - let signer = signer.clone(); - tokio::spawn(async move { - start_event_listener(url, signer, cancel_token, addresses).await; - }); - } - // Let first poll occur on poller - tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; - - // Increase current block count to move away from poller initialisation block - anvil_provider - .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) - .await - .expect("Failed to mine"); - - // ------------------------------------------------------------------------------------------------------------ - // Assert that the current contract balance is not 0 - let balance = anvil_provider - .get_balance(*scribe_optimistic.address()) - .await - .expect("Failed to get balance"); - assert_ne!(balance, U256::from(0)); - - // Make invalid poke, but since the anvil time is not in sync with chrono time will be in the past - let current_timestamp = chrono::Utc::now().timestamp() as u64; - make_invalid_op_poke(current_timestamp - 500, private_key, &scribe_optimistic).await; - - // Mine at least one block to ensure log is processed - anvil_provider - .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) - .await - .expect("Failed to mine"); - - // Poll till expected logs are found - // Assert challenge started log not found - // Ensure the challenge was never created - for _ in 1..5 { - let success = Cell::new(false); - testing_logger::validate(|captured_logs| { - let mut found: bool = false; - for log in captured_logs { - assert!( - !log.body - .to_lowercase() - .contains(&"Challenge started".to_lowercase()), - "Challenge started log found" - ); - found |= log - .body - .to_lowercase() - .contains(&"OpPoked received outside of challenge period".to_lowercase()); - } - success.set(found); - }); - if success.get() { - return; - } - tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + // Let first poll occur on poller + tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; + + // Increase current block count to move away from poller initialisation block + anvil_provider + .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) + .await + .expect("Failed to mine"); + + // ------------------------------------------------------------------------------------------------------------ + let mut invalid_pokes = vec![]; + for i in 0..NUM_SCRIBE_INSTANCES { + // Assert that the current contract balance is not 0 + let balance = anvil_provider + .get_balance(scribe_addresses[i]) + .await + .expect("Failed to get balance"); + assert_ne!(balance, U256::from(0)); + invalid_pokes.push(make_invalid_op_poke( + current_timestamp, + private_key, + &scribes[i], + )); + // Do at most 50 at the same time + if i % 50 == 0 { + join_all(invalid_pokes).await; + invalid_pokes = vec![]; + } + } + join_all(invalid_pokes).await; + + // Mine at least one block to ensure log is processed + anvil_provider + .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) + .await + .expect("Failed to mine"); + + let result = join_all((0..NUM_SCRIBE_INSTANCES).map(|i| { + poll_balance_is_zero( + &anvil_provider, + &scribe_addresses[i], + (20 + (10 * NUM_SCRIBE_INSTANCES) / 100).try_into().unwrap(), + ) + })) + .await + .iter() + .all(|&result| result); + + // Poll to check that the challenge started log is found, + // (to ensure log hasn't been changed as its non appearance is looked for in other tests) + for i in 0..5 { + let success: Cell = Cell::new(false); + testing_logger::validate(|captured_logs| { + let mut found: bool = false; + for log in captured_logs { + found |= log + .body + .to_lowercase() + .contains(&"OpPoked validation started".to_lowercase()); } + success.set(found); + }); + if success.get() { + break; + } + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + if i == 4 { panic!("Failed to find log"); + } } - // TODO: test dont challenge if receive op challenged - - // TODO: test flashbot used first, fallback to normal rpc - - // -- Helper functions -- - - // Search for anvil binary in the target directory if `ANVIL_BIN` is set. - // Otherwise it will try get `anvil` from system. - fn get_anvil() -> Anvil { - let anvil_bin = std::env::var("ANVIL_BIN").unwrap_or_else(|_| "anvil".to_string()); - Anvil::at(anvil_bin) + if result { + cancel_token.cancel(); + return; } - - async fn create_anvil_instances( - private_key: &str, - port: u16, - ) -> (AnvilInstance, AnvilProvider, EthereumWallet) { - let anvil: AnvilInstance = get_anvil() - .port(port) - .chain_id(31337) - .block_time_f64(0.1) - .try_spawn() - .expect("Failed to spawn anvil"); - - let signer: EthereumWallet = - EthereumWallet::new(private_key.parse::().unwrap()); - - let anvil_provider = Arc::new( - ProviderBuilder::new() - // .with_cached_nonce_management() - .with_recommended_fillers() - .wallet(signer.clone()) - .filler(ChainIdFiller::new(Some(31337))) - .filler(NonceFiller::::default()) - .on_http(anvil.endpoint_url()), - ); - - // set initial balance for deployer - anvil_provider - .anvil_set_balance( - signer.default_signer().address(), - U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), - ) - .await - .expect("Unable to set balance"); - - // configure anvil settings - anvil_provider - .anvil_set_auto_mine(true) - .await - .expect("Failed to set auto mine"); - anvil_provider - .anvil_mine(Some(U256::from(3)), Some(U256::from(3))) - .await - .expect("Failed to mine"); - anvil_provider - .anvil_impersonate_account(signer.default_signer().address()) - .await - .expect("Failed to impersonate account"); - - (anvil, anvil_provider, signer) + cancel_token.cancel(); + panic!("Failed to challenge"); + } + + #[tokio::test] + async fn dont_challenge_outside_challenge_period() { + testing_logger::setup(); + // Test an invalid poke on multiple scribe instances is successfully challenged + // ------------------------------------------------------------------------------------------------------------ + let private_key = PRIVATE_KEY; + // Use a new port for each test to avoid conflicts if tests run in parallel + let (anvil, anvil_provider, signer) = create_anvil_instances(private_key, 8546).await; + + // Set to a low current time for now, this avoids having stale poke error later + anvil_provider + .anvil_set_time(1000) + .await + .expect("Failed to set time"); + + // Deploy scribe instance + let scribe_optimistic = deploy_scribe(anvil_provider.clone(), signer.clone(), 300).await; + anvil_provider + .anvil_set_balance( + *scribe_optimistic.address(), + U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), + ) + .await + .expect("Unable to set balance"); + + // Update current anvil time to be far from last scribe config update + // Set the anvil time to be in the past to ensure the challenge period is exceeded later + let current_timestamp = (chrono::Utc::now().timestamp() as u64) - 400; + anvil_provider + .anvil_set_time(current_timestamp) + .await + .expect("Failed to set time"); + + // ------------------------------------------------------------------------------------------------------------ + let cancel_token: CancellationToken = CancellationToken::new(); + + // start the event listener as a sub process + { + let signer: EthereumWallet = EthereumWallet::new(PrivateKeySigner::random()); + anvil_provider + .anvil_set_balance( + signer.default_signer().address(), + U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), + ) + .await + .expect("Unable to set balance"); + let addresses = vec![*scribe_optimistic.address()]; + let cancel_token = cancel_token.clone(); + let url = anvil.endpoint_url(); + let signer = signer.clone(); + tokio::spawn(async move { + start_event_listener(url, signer, cancel_token, addresses).await; + }); } + // Let first poll occur on poller + tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; + + // Increase current block count to move away from poller initialisation block + anvil_provider + .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) + .await + .expect("Failed to mine"); + + // ------------------------------------------------------------------------------------------------------------ + // Assert that the current contract balance is not 0 + let balance = anvil_provider + .get_balance(*scribe_optimistic.address()) + .await + .expect("Failed to get balance"); + assert_ne!(balance, U256::from(0)); + + // Make invalid poke, but since the anvil time is not in sync with chrono time will be in the past + let current_timestamp = chrono::Utc::now().timestamp() as u64; + make_invalid_op_poke(current_timestamp - 500, private_key, &scribe_optimistic).await; + + // Mine at least one block to ensure log is processed + anvil_provider + .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) + .await + .expect("Failed to mine"); + + // Poll till expected logs are found + // Assert challenge started log not found + // Ensure the challenge was never created + for _ in 1..5 { + let success = Cell::new(false); + testing_logger::validate(|captured_logs| { + let mut found: bool = false; + for log in captured_logs { + assert!( + !log + .body + .to_lowercase() + .contains(&"Challenge started".to_lowercase()), + "Challenge started log found" + ); + found |= log + .body + .to_lowercase() + .contains(&"OpPoked received outside of challenge period".to_lowercase()); + } + success.set(found); + }); + if success.get() { + return; + } + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + } + panic!("Failed to find log"); + } + + // TODO: test dont challenge if receive op challenged + + // TODO: test flashbot used first, fallback to normal rpc + + // -- Helper functions -- + + // Search for anvil binary in the target directory if `ANVIL_BIN` is set. + // Otherwise it will try get `anvil` from system. + fn get_anvil() -> Anvil { + let anvil_bin = std::env::var("ANVIL_BIN").unwrap_or_else(|_| "anvil".to_string()); + Anvil::at(anvil_bin) + } + + async fn create_anvil_instances( + private_key: &str, + port: u16, + ) -> (AnvilInstance, AnvilProvider, EthereumWallet) { + let anvil: AnvilInstance = get_anvil() + .port(port) + .chain_id(31337) + .block_time_f64(0.1) + .try_spawn() + .expect("Failed to spawn anvil"); + + let signer: EthereumWallet = + EthereumWallet::new(private_key.parse::().unwrap()); + + let anvil_provider = Arc::new( + ProviderBuilder::new() + // .with_cached_nonce_management() + .with_recommended_fillers() + .wallet(signer.clone()) + .filler(ChainIdFiller::new(Some(31337))) + .filler(NonceFiller::::default()) + .on_http(anvil.endpoint_url()), + ); - async fn deploy_scribe, T: Clone + Transport, N: Network>( - provider: P, - signer: EthereumWallet, - challenge_period: u16, - ) -> ScribeOptimisticInstance { - // deploy scribe instance - let initial_authed = signer.default_signer().address(); - // let private_key = signer. - let wat: [u8; 32] = hex!( - " + // set initial balance for deployer + anvil_provider + .anvil_set_balance( + signer.default_signer().address(), + U256::from_str_radix("1000000000000000000000000000000000000000", 10).unwrap(), + ) + .await + .expect("Unable to set balance"); + + // configure anvil settings + anvil_provider + .anvil_set_auto_mine(true) + .await + .expect("Failed to set auto mine"); + anvil_provider + .anvil_mine(Some(U256::from(3)), Some(U256::from(3))) + .await + .expect("Failed to mine"); + anvil_provider + .anvil_impersonate_account(signer.default_signer().address()) + .await + .expect("Failed to impersonate account"); + + (anvil, anvil_provider, signer) + } + + async fn deploy_scribe, T: Clone + Transport, N: Network>( + provider: P, + signer: EthereumWallet, + challenge_period: u16, + ) -> ScribeOptimisticInstance { + // deploy scribe instance + let initial_authed = signer.default_signer().address(); + // let private_key = signer. + let wat: [u8; 32] = hex!( + " 0123456789abcdef0123456789abcdef 0123456789abcdef0123456789abcdef " - ); - let scribe_optimistic = ScribeOptimistic::deploy(provider, initial_authed, FixedBytes(wat)); - - let scribe_optimistic = scribe_optimistic.await.unwrap(); - let receipt = scribe_optimistic.setBar(1); - let receipt = receipt.send().await.expect("Failed to set bar"); - receipt - .with_timeout(Some(Duration::from_secs(15))) - .watch() - .await - .expect("Failed to set bar"); - - // TODO generate the public key and v r s from private key - // lift validator - let pub_key = LibSecp256k1::Point { - x: U256::from_str_radix( - "95726579611468854699048782904089382286224374897874075137780214269565012360365", - 10, - ) - .unwrap(), - y: U256::from_str_radix( - "95517337328947037046967076057450300670379811052080651187456799621439597083272", - 10, - ) - .unwrap(), - }; - let ecdsa_data = IScribe::ECDSAData { - v: 0x1b, - r: FixedBytes(hex!( - "0ced9fd231ad454eaac301d6e15a56b6aaa839a55d664757e3ace927e95948ec" - )), - s: FixedBytes(hex!( - "21b2813ad85945f320d7728fbfc9b83cbbb564135e67c16db16d5f4e74392119" - )), - }; - let receipt = scribe_optimistic.lift_0(pub_key, ecdsa_data); - let receipt = receipt.send().await.expect("Failed to lift validator"); - receipt - .with_timeout(Some(Duration::from_secs(15))) - .watch() - .await - .expect("Failed to lift validator"); - - // set challenge period - let receipt = scribe_optimistic.setOpChallengePeriod(challenge_period); - let receipt = receipt.send().await.expect("Failed to lift validator"); - receipt - .with_timeout(Some(Duration::from_secs(15))) - .watch() - .await - .expect("Failed to set opChallenge"); - - scribe_optimistic - } + ); + let scribe_optimistic = ScribeOptimistic::deploy(provider, initial_authed, FixedBytes(wat)); + + let scribe_optimistic = scribe_optimistic.await.unwrap(); + let receipt = scribe_optimistic.setBar(1); + let receipt = receipt.send().await.expect("Failed to set bar"); + receipt + .with_timeout(Some(Duration::from_secs(15))) + .watch() + .await + .expect("Failed to set bar"); + + // TODO generate the public key and v r s from private key + // lift validator + let pub_key = LibSecp256k1::Point { + x: U256::from_str_radix( + "95726579611468854699048782904089382286224374897874075137780214269565012360365", + 10, + ) + .unwrap(), + y: U256::from_str_radix( + "95517337328947037046967076057450300670379811052080651187456799621439597083272", + 10, + ) + .unwrap(), + }; + let ecdsa_data = IScribe::ECDSAData { + v: 0x1b, + r: FixedBytes(hex!( + "0ced9fd231ad454eaac301d6e15a56b6aaa839a55d664757e3ace927e95948ec" + )), + s: FixedBytes(hex!( + "21b2813ad85945f320d7728fbfc9b83cbbb564135e67c16db16d5f4e74392119" + )), + }; + let receipt = scribe_optimistic.lift_0(pub_key, ecdsa_data); + let receipt = receipt.send().await.expect("Failed to lift validator"); + receipt + .with_timeout(Some(Duration::from_secs(15))) + .watch() + .await + .expect("Failed to lift validator"); + + // set challenge period + let receipt = scribe_optimistic.setOpChallengePeriod(challenge_period); + let receipt = receipt.send().await.expect("Failed to lift validator"); + receipt + .with_timeout(Some(Duration::from_secs(15))) + .watch() + .await + .expect("Failed to set opChallenge"); + + scribe_optimistic + } + + async fn start_event_listener( + url: Url, + signer: EthereumWallet, + cancel_token: CancellationToken, + addresses: Vec
, + ) { + let client = ClientBuilder::default() + .layer(RetryBackoffLayer::new(15, 200, 300)) + .http(url); - async fn start_event_listener( - url: Url, - signer: EthereumWallet, - cancel_token: CancellationToken, - addresses: Vec
, - ) { - let client = ClientBuilder::default() - .layer(RetryBackoffLayer::new(15, 200, 300)) - .http(url); - - let nonce_manager = NonceFiller::::default(); - - let provider = Arc::new( - ProviderBuilder::new() - .with_recommended_fillers() - .filler(ChainIdFiller::new(Some(31337))) - .filler(nonce_manager.clone()) - .wallet(signer.clone()) - .on_client(client), - ); + let nonce_manager = NonceFiller::::default(); - let flashbot_provider = provider.clone(); + let provider = Arc::new( + ProviderBuilder::new() + .with_recommended_fillers() + .filler(ChainIdFiller::new(Some(31337))) + .filler(nonce_manager.clone()) + .wallet(signer.clone()) + .on_client(client), + ); - let mut set: JoinSet<()> = JoinSet::new(); - let (tx, rx) = tokio::sync::mpsc::channel::(100); + let flashbot_provider = provider.clone(); - // let addresses = vec![scribe_optimistic.address().clone()]; + let mut set: JoinSet<()> = JoinSet::new(); + let (tx, rx) = tokio::sync::mpsc::channel::(100); - // Create events listener - let mut poller = Poller::new( - addresses.clone(), - cancel_token.clone(), - provider.clone(), - tx.clone(), - 1, - ); + // let addresses = vec![scribe_optimistic.address().clone()]; - // Create event distributor - let mut event_distributor = events_handler::EventDistributor::new( - addresses.clone(), - cancel_token.clone(), - provider.clone(), - flashbot_provider.clone(), - rx, - ); + // Create events listener + let mut poller = Poller::new( + addresses.clone(), + cancel_token.clone(), + provider.clone(), + tx.clone(), + 1, + ); - // Run events listener process - set.spawn(async move { - log::info!("Starting events listener"); - if let Err(err) = poller.start().await { - log::error!("Poller error: {:?}", err); - } - }); - - // Run event distributor process - set.spawn(async move { - log::info!("Starting log handler"); - if let Err(err) = event_distributor.start().await { - log::error!("Log Handler error: {:?}", err); - } - }); - - while let Some(res) = set.join_next().await { - match res { - Ok(_) => log::info!("Task completed successfully"), - Err(err) => log::error!("Task failed: {:?}", err), - } - } - } + // Create event distributor + let mut event_distributor = events_handler::EventDistributor::new( + addresses.clone(), + cancel_token.clone(), + provider.clone(), + flashbot_provider.clone(), + rx, + ); - async fn poll_balance_is_zero( - anvil_provider: &AnvilProvider, - address: &Address, - timeout: u64, - ) -> bool { - let start_time = chrono::Utc::now().timestamp() as u64; - while (chrono::Utc::now().timestamp() as u64) < start_time + timeout { - let balance = anvil_provider - .get_balance(*address) - .await - .expect("Failed to get balance"); - if balance == U256::from(0) { - return true; - } - anvil_provider - .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) - .await - .expect("Failed to mine"); - tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; - } - false - } + // Run events listener process + set.spawn(async move { + log::info!("Starting events listener"); + if let Err(err) = poller.start().await { + log::error!("Poller error: {:?}", err); + } + }); - async fn make_invalid_op_poke( - age: u64, - private_key: &str, - scribe_optimistic: &ScribeOptimisticInstance, AnvilProvider, Ethereum>, - ) { - let poke_data: IScribe::PokeData = IScribe::PokeData { - val: 10, - age: age as u32, - }; - let schnorr_data = IScribe::SchnorrData { - signature: FixedBytes(hex!( - "0000000000000000000000000000000000000000000000000000000000000000" - )), - commitment: alloy::primitives::Address::ZERO, - feedIds: hex!("00").into(), - }; - let op_poke_message = scribe_optimistic - .constructOpPokeMessage(poke_data.clone(), schnorr_data.clone()) - .call() - .await - .expect("Failed to read current age"); - let op_poke_message = op_poke_message._0; - let ecdsa_signer = private_key - .parse::() - .expect("Failed to parse private key"); - let signature = ecdsa_signer - .sign_hash_sync(&op_poke_message) - .expect("Failed to sign message"); - let ecdsa_data = IScribe::ECDSAData { - v: 0x1b + (signature.v().to_u64() as u8), - r: FixedBytes(signature.r().to_be_bytes()), - s: FixedBytes(signature.s().to_be_bytes()), - }; - - // Make the invalid poke - let receipt = scribe_optimistic.opPoke(poke_data.clone(), schnorr_data.clone(), ecdsa_data); - let receipt = receipt.send().await.expect("Failed to send op poke"); - receipt.watch().await.expect("Failed to watch op poke"); + // Run event distributor process + set.spawn(async move { + log::info!("Starting log handler"); + if let Err(err) = event_distributor.start().await { + log::error!("Log Handler error: {:?}", err); + } + }); + + while let Some(res) = set.join_next().await { + match res { + Ok(_) => log::info!("Task completed successfully"), + Err(err) => log::error!("Task failed: {:?}", err), + } + } + } + + async fn poll_balance_is_zero( + anvil_provider: &AnvilProvider, + address: &Address, + timeout: u64, + ) -> bool { + let start_time = chrono::Utc::now().timestamp() as u64; + while (chrono::Utc::now().timestamp() as u64) < start_time + timeout { + let balance = anvil_provider + .get_balance(*address) + .await + .expect("Failed to get balance"); + if balance == U256::from(0) { + return true; + } + anvil_provider + .anvil_mine(Some(U256::from(1)), Some(U256::from(1))) + .await + .expect("Failed to mine"); + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; } + false + } + + async fn make_invalid_op_poke( + age: u64, + private_key: &str, + scribe_optimistic: &ScribeOptimisticInstance, AnvilProvider, Ethereum>, + ) { + let poke_data: IScribe::PokeData = IScribe::PokeData { + val: 10, + age: age as u32, + }; + let schnorr_data = IScribe::SchnorrData { + signature: FixedBytes(hex!( + "0000000000000000000000000000000000000000000000000000000000000000" + )), + commitment: alloy::primitives::Address::ZERO, + feedIds: hex!("00").into(), + }; + let op_poke_message = scribe_optimistic + .constructOpPokeMessage(poke_data.clone(), schnorr_data.clone()) + .call() + .await + .expect("Failed to read current age"); + let op_poke_message = op_poke_message._0; + let ecdsa_signer = private_key + .parse::() + .expect("Failed to parse private key"); + let signature = ecdsa_signer + .sign_hash_sync(&op_poke_message) + .expect("Failed to sign message"); + let ecdsa_data = IScribe::ECDSAData { + v: 0x1b + (signature.v() as u8), + r: FixedBytes(signature.r().to_be_bytes()), + s: FixedBytes(signature.s().to_be_bytes()), + }; + + // Make the invalid poke + let receipt = scribe_optimistic.opPoke(poke_data.clone(), schnorr_data.clone(), ecdsa_data); + let receipt = receipt.send().await.expect("Failed to send op poke"); + receipt.watch().await.expect("Failed to watch op poke"); + } } diff --git a/src/wallet.rs b/src/wallet.rs index bb92add..f22e8af 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -14,129 +14,130 @@ // along with this program. If not, see . use alloy::{ - network::EthereumWallet, - signers::local::{LocalSigner, PrivateKeySigner}, + network::EthereumWallet, + signers::local::{LocalSigner, PrivateKeySigner}, }; use eyre::{bail, Result, WrapErr}; use log::debug; use std::{ - fs, - path::{Path, PathBuf}, + fs, + path::{Path, PathBuf}, }; pub trait PrivateKeyWallet { - /// Returns the raw private key if it was provided. - fn raw_private_key(&self) -> Option; - - #[track_caller] - #[allow(clippy::wrong_self_convention)] - fn from_private_key(&self, private_key: &str) -> Result> { - debug!("Using private key from arguments"); - - let privk = private_key.trim().strip_prefix("0x").unwrap_or(private_key); - match privk.parse::() { - Ok(signer) => Ok(Some(EthereumWallet::new(signer))), - Err(err) => bail!("Failed to parse private key: {:?}", err), - } + /// Returns the raw private key if it was provided. + fn raw_private_key(&self) -> Option; + + #[track_caller] + #[allow(clippy::wrong_self_convention)] + fn from_private_key(&self, private_key: &str) -> Result> { + debug!("Using private key from arguments"); + + let privk = private_key.trim().strip_prefix("0x").unwrap_or(private_key); + match privk.parse::() { + Ok(signer) => Ok(Some(EthereumWallet::new(signer))), + Err(err) => bail!("Failed to parse private key: {:?}", err), } + } } pub trait KeystoreWallet { - /// Returns the path to the keystore file if it was provided. - fn keystore_path(&self) -> Option; - - /// Returns the raw password if it was provided. - fn raw_password(&self) -> Option; - - /// Returns the path to the password file if it was provided. - fn password_file(&self) -> Option; - - /// Ensures the path to the keystore exists. - /// - /// if the path is a directory, it bails and asks the user to specify the keystore file - /// directly. - fn find_keystore_file(&self, path: impl AsRef) -> Result { - let path = path.as_ref(); - if !path.exists() { - bail!("Keystore file `{path:?}` does not exist") - } - - if path.is_dir() { - bail!("Keystore path `{path:?}` is a directory. Please specify the keystore file directly.") - } + /// Returns the path to the keystore file if it was provided. + fn keystore_path(&self) -> Option; + + /// Returns the raw password if it was provided. + fn raw_password(&self) -> Option; + + /// Returns the path to the password file if it was provided. + fn password_file(&self) -> Option; + + /// Ensures the path to the keystore exists. + /// + /// if the path is a directory, it bails and asks the user to specify the keystore file + /// directly. + fn find_keystore_file(&self, path: impl AsRef) -> Result { + let path = path.as_ref(); + if !path.exists() { + bail!("Keystore file `{path:?}` does not exist") + } - Ok(path.to_path_buf()) + if path.is_dir() { + bail!("Keystore path `{path:?}` is a directory. Please specify the keystore file directly.") } - /// Attempts to read the keystore password from the password file. - fn password_from_file(&self, password_file: impl AsRef) -> Result { - let password_file = password_file.as_ref(); - if !password_file.is_file() { - bail!("Keystore password file `{password_file:?}` does not exist") - } + Ok(path.to_path_buf()) + } - Ok(fs::read_to_string(password_file)?.trim_end().to_string()) + /// Attempts to read the keystore password from the password file. + fn password_from_file(&self, password_file: impl AsRef) -> Result { + let password_file = password_file.as_ref(); + if !password_file.is_file() { + bail!("Keystore password file `{password_file:?}` does not exist") } - fn get_from_keystore( - &self, - keystore_path: Option<&PathBuf>, - keystore_password: Option<&String>, - keystore_password_file: Option<&PathBuf>, - ) -> Result> { - Ok( - match (keystore_path, keystore_password, keystore_password_file) { - (Some(path), Some(password), _) => { - let path = self.find_keystore_file(path)?; + Ok(fs::read_to_string(password_file)?.trim_end().to_string()) + } - debug!("Using Keystore file from `{path:?}` and raw password"); + fn get_from_keystore( + &self, + keystore_path: Option<&PathBuf>, + keystore_password: Option<&String>, + keystore_password_file: Option<&PathBuf>, + ) -> Result> { + Ok( + match (keystore_path, keystore_password, keystore_password_file) { + (Some(path), Some(password), _) => { + let path = self.find_keystore_file(path)?; - let signer = LocalSigner::decrypt_keystore(&path, password) - .wrap_err_with(|| format!("Failed to decrypt keystore {path:?}"))?; + debug!("Using Keystore file from `{path:?}` and raw password"); - Some(EthereumWallet::new(signer)) - } - (Some(path), _, Some(password_file)) => { - let path = self.find_keystore_file(path)?; + let signer = LocalSigner::decrypt_keystore(&path, password) + .wrap_err_with(|| format!("Failed to decrypt keystore {path:?}"))?; - debug!("Using Keystore file from `{path:?}` and password from file"); + Some(EthereumWallet::new(signer)) + } + (Some(path), _, Some(password_file)) => { + let path = self.find_keystore_file(path)?; - let signer = LocalSigner::decrypt_keystore(&path, self.password_from_file(password_file)?) - .wrap_err_with(|| format!("Failed to decrypt keystore {path:?} with password file {password_file:?}"))?; + debug!("Using Keystore file from `{path:?}` and password from file"); - Some(EthereumWallet::new(signer)) - } - (Some(path), None, None) => { - let path = self.find_keystore_file(path)?; + let signer = + LocalSigner::decrypt_keystore(&path, self.password_from_file(password_file)?) + .wrap_err_with(|| { + format!("Failed to decrypt keystore {path:?} with password file {password_file:?}") + })?; - debug!( - "Using Keystore file from `{path:?}` and password from interactive prompt" - ); + Some(EthereumWallet::new(signer)) + } + (Some(path), None, None) => { + let path = self.find_keystore_file(path)?; - let password = rpassword::prompt_password("Enter keystore password:")?; + debug!("Using Keystore file from `{path:?}` and password from interactive prompt"); - let signer = LocalSigner::decrypt_keystore(&path, password) - .wrap_err_with(|| format!("Failed to decrypt keystore {path:?}"))?; + let password = rpassword::prompt_password("Enter keystore password:")?; - Some(EthereumWallet::new(signer)) - } - (None, _, _) => None, - }, - ) - } + let signer = LocalSigner::decrypt_keystore(&path, password) + .wrap_err_with(|| format!("Failed to decrypt keystore {path:?}"))?; + + Some(EthereumWallet::new(signer)) + } + (None, _, _) => None, + }, + ) + } } pub trait CustomWallet: PrivateKeyWallet + KeystoreWallet { - /// Generates wallet for future sign - fn wallet(&self) -> Result> { - match (&self.raw_private_key(), &self.keystore_path()) { - (Some(secret), _) => self.from_private_key(secret), - (_, Some(key)) => self.get_from_keystore( - Some(key), - self.raw_password().as_ref(), - self.password_file().as_ref(), - ), - (_, _) => bail!("Please provide private key or keystore"), - } + /// Generates wallet for future sign + fn wallet(&self) -> Result> { + match (&self.raw_private_key(), &self.keystore_path()) { + (Some(secret), _) => self.from_private_key(secret), + (_, Some(key)) => self.get_from_keystore( + Some(key), + self.raw_password().as_ref(), + self.password_file().as_ref(), + ), + (_, _) => bail!("Please provide private key or keystore"), } + } }