diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4fbeb81866..221dd5f345 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,10 @@ updates: - "*" exclude-patterns: - "cdn-*" + - "ark-*" cdn: patterns: - "cdn-*" + ark: + patterns: + - "ark-*" diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0aacdac8ea..041e277506 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -45,11 +45,7 @@ jobs: cache-on-failure: "true" save-if: ${{ github.ref == 'refs/heads/main' && matrix.test_suites == 'test-ci-rest' }} - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - uses: taiki-e/install-action@nextest @@ -83,11 +79,7 @@ jobs: cache-on-failure: "true" save-if: ${{ github.ref == 'refs/heads/main' }} - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - name: Test examples run: | @@ -117,11 +109,7 @@ jobs: cache-on-failure: "true" save-if: ${{ github.ref == 'refs/heads/main' }} - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - name: Build examples in release mode run: just ${{ matrix.just_variants }} build_release --examples --package hotshot-examples --no-default-features diff --git a/.github/workflows/build-without-lockfile.yml b/.github/workflows/build-without-lockfile.yml new file mode 100644 index 0000000000..66fd1415c1 --- /dev/null +++ b/.github/workflows/build-without-lockfile.yml @@ -0,0 +1,40 @@ +name: Build without committed Cargo.lock + +on: + push: + branches: + - main + - release-* + tags: + # YYYYMMDD + - "20[0-9][0-9][0-1][0-9][0-3][0-9]*" + schedule: + - cron: "0 0 * * 1" + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + RUSTFLAGS: '--cfg async_executor_impl="async-std" --cfg async_channel_impl="async-std"' + +jobs: + build-ignore-lockfile: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Enable Rust Caching + uses: Swatinem/rust-cache@v2 + with: + prefix-key: v1-rust + + - name: Build without committed Cargo.lock + run: | + cargo generate-lockfile + cargo check --all-targets diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 5d4606c541..1949a79f00 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -21,11 +21,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - uses: Swatinem/rust-cache@v2 name: Enable Rust Caching diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 45de5cead7..0589b0c777 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -37,11 +37,7 @@ jobs: prefix-key: ${{ matrix.just_variants }} save-if: ${{ github.ref == 'refs/heads/main' }} - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - name: Run clippy run: | @@ -56,11 +52,7 @@ jobs: - name: Install Rust uses: mkroening/rust-toolchain-toml@main - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - name: Check rustfmt run: | diff --git a/.github/workflows/semver-check.yml b/.github/workflows/semver-check.yml index 5d5551db74..db8d67ba2a 100644 --- a/.github/workflows/semver-check.yml +++ b/.github/workflows/semver-check.yml @@ -33,11 +33,7 @@ jobs: path: baseline ref: ${{ inputs.baseline }} - - name: Install Just - run: | - wget https://github.com/casey/just/releases/download/1.14.0/just-1.14.0-x86_64-unknown-linux-musl.tar.gz - tar -vxf just-1.14.0-x86_64-unknown-linux-musl.tar.gz just - sudo cp just /usr/bin/just + - uses: taiki-e/install-action@just - name: Install Rust uses: mkroening/rust-toolchain-toml@main diff --git a/CHANGELOG.md b/CHANGELOG.md index 8522f9456d..8bcdeb6baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ Adds new type parameter, corresponding to the state type, to Message ### Features - StatefulHandler trait - Reexport traits from traits module -- State Machine + NodeImplementation +- State Machine + Node Implementation - state machine mvp megasquash - Replace tokio broadcast queue with unbounded equivalent diff --git a/Cargo.lock b/Cargo.lock index 69f0a0115e..d1f0ee3e15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aead" version = "0.3.2" @@ -126,9 +132,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -141,49 +147,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "775a8770d29db3dadcb858482cc240af7b2ffde4ac4de67d1d4955728103f0e2" dependencies = [ "derive_arbitrary", ] @@ -329,7 +335,7 @@ dependencies = [ "num-traits", "paste", "rayon", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -469,41 +475,31 @@ dependencies = [ ] [[package]] -name = "arrayref" -version = "0.3.7" +name = "arraydeque" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] -name = "arrayvec" -version = "0.7.4" +name = "arrayref" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] -name = "asn1-rs" -version = "0.5.2" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive 0.4.0", - "asn1-rs-impl 0.1.0", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time 0.3.36", -] +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ - "asn1-rs-derive 0.5.0", - "asn1-rs-impl 0.2.0", + "asn1-rs-derive", + "asn1-rs-impl", "displaydoc", "nom", "num-traits", @@ -514,39 +510,16 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "synstructure 0.13.1", ] -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "asn1-rs-impl" version = "0.2.0" @@ -555,7 +528,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -583,7 +556,7 @@ dependencies = [ "event-listener 5.3.1", "event-listener-strategy", "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -606,7 +579,7 @@ dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -641,14 +614,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", + "fastrand 2.1.1", + "futures-lite 2.4.0", "slab", ] @@ -672,10 +645,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.3", + "async-io 2.3.4", "async-lock 3.4.0", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "once_cell", "tokio", ] @@ -719,21 +692,21 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "parking", - "polling 3.7.1", - "rustix 0.38.34", + "polling 3.7.3", + "rustix 0.38.39", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -753,7 +726,7 @@ checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -792,26 +765,45 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.34", + "rustix 0.38.39", "windows-sys 0.48.0", ] +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel 2.3.1", + "async-io 2.3.4", + "async-lock 3.4.0", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.3.1", + "futures-lite 2.4.0", + "rustix 0.38.39", + "tracing", +] + [[package]] name = "async-signal" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329972aa325176e89114919f2a80fdae4f4c040f66a370b1a1159c6c0f94e7aa" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.34", + "rustix 0.38.39", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -830,27 +822,27 @@ dependencies = [ [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", - "async-process", + "async-io 2.3.4", + "async-lock 3.4.0", + "async-process 2.3.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite 2.4.0", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "pin-utils", "slab", "wasm-bindgen-futures", @@ -873,24 +865,24 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -920,7 +912,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -935,7 +927,7 @@ dependencies = [ "futures-io", "futures-util", "log", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tungstenite", ] @@ -949,7 +941,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -962,7 +954,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -993,9 +985,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "automod" @@ -1005,7 +997,7 @@ checksum = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1021,13 +1013,13 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.31", "itoa", "matchit", "memchr", "mime", "percent-encoding", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "rustversion", "serde", "sync_wrapper 0.1.2", @@ -1063,7 +1055,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -1115,16 +1107,14 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -1132,8 +1122,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.85", - "which", + "syn 2.0.87", ] [[package]] @@ -1144,9 +1133,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -1213,15 +1202,15 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "piper", ] [[package]] name = "blst" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" dependencies = [ "cc", "glob", @@ -1274,18 +1263,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] [[package]] name = "capnp" -version = "0.19.6" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de71387912cac7dd3cb7c219e09628411620a18061bba58c71453c26ae7bf66a" +checksum = "4e985a566bdaae9a428a957d12b10c318d41b2afddb54cfbb764878059df636e" dependencies = [ "embedded-io", ] @@ -1301,18 +1290,18 @@ dependencies = [ [[package]] name = "cbor4ii" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b4c883b9cc4757b061600d39001d4d0232bece4a3174696cf8f58a14db107d" +checksum = "472931dd4dfcc785075b09be910147f9c6258883fc4591d0dac6116392b2daa6" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.1.13" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "shlex", ] @@ -1389,12 +1378,12 @@ dependencies = [ "num_enum", "pem", "prometheus", - "quinn 0.11.5", + "quinn", "rand 0.8.5", "rcgen 0.13.1", "redis", "rkyv", - "rustls 0.23.7", + "rustls 0.23.16", "rustls-pki-types", "sqlx", "thiserror", @@ -1420,6 +1409,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -1481,23 +1476,23 @@ version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ "cc", ] @@ -1531,9 +1526,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -1544,7 +1539,7 @@ dependencies = [ "bytes", "futures-core", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tokio", "tokio-util", ] @@ -1578,14 +1573,13 @@ dependencies = [ [[package]] name = "config" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", "convert_case 0.6.0", "json5", - "lazy_static", "nom", "pathdiff", "ron", @@ -1593,7 +1587,7 @@ dependencies = [ "serde", "serde_json", "toml", - "yaml-rust", + "yaml-rust2", ] [[package]] @@ -1705,9 +1699,9 @@ checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1753,9 +1747,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -1768,9 +1762,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1932,7 +1926,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -1945,7 +1939,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1989,7 +1983,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2000,7 +1994,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2051,7 +2045,7 @@ checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2065,27 +2059,13 @@ dependencies = [ "zeroize", ] -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs 0.5.2", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - [[package]] name = "der-parser" version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", "displaydoc", "nom", "num-bigint", @@ -2116,13 +2096,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "d475dfebcb4854d596b17b09f477616f80f17a550517f2b3615d8c205d5c802b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2143,7 +2123,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2153,7 +2133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2165,8 +2145,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.85", + "rustc_version 0.4.1", + "syn 2.0.87", ] [[package]] @@ -2186,7 +2166,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2254,7 +2234,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2290,11 +2270,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "git+https://github.com/dtolnay/dyn-clone?tag=1.0.17#51bf8816be5a73e38b59fd4d9dda2bc18e9c2429" - [[package]] name = "ed25519" version = "2.2.3" @@ -2322,9 +2297,9 @@ dependencies = [ [[package]] name = "edit-distance" -version = "2.1.0" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b" +checksum = "e3f497e87b038c09a155dfd169faa5ec940d0644635555ef6bd464ac20e97397" [[package]] name = "either" @@ -2343,23 +2318,23 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2443,7 +2418,7 @@ checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -2454,7 +2429,7 @@ checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -2464,7 +2439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -2488,9 +2463,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fiat-crypto" @@ -2511,19 +2486,19 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -2654,21 +2629,21 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "waker-fn", ] [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] @@ -2679,17 +2654,18 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "futures-rustls" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.21.11", + "rustls 0.23.16", + "rustls-pki-types", ] [[package]] @@ -2734,7 +2710,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "pin-utils", "slab", ] @@ -2798,9 +2774,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -2820,7 +2796,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2829,9 +2805,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -2839,7 +2815,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2876,15 +2852,24 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hashlink" version = "0.9.1" @@ -2931,12 +2916,6 @@ dependencies = [ "http 0.2.12", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2949,6 +2928,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -3099,7 +3084,7 @@ dependencies = [ "anyhow", "async-broadcast", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bimap", @@ -3166,7 +3151,7 @@ dependencies = [ "anyhow", "async-broadcast", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bitvec", @@ -3179,6 +3164,7 @@ dependencies = [ "hotshot-task", "hotshot-task-impls", "hotshot-types", + "jf-vid", "rand 0.8.5", "reqwest", "serde", @@ -3199,7 +3185,7 @@ dependencies = [ "anyhow", "async-broadcast", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bimap", @@ -3248,7 +3234,7 @@ version = "0.5.79" dependencies = [ "anyhow", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-trait", "futures", "hotshot-example-types", @@ -3268,7 +3254,7 @@ dependencies = [ "derive_builder", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -3277,7 +3263,7 @@ version = "0.5.79" dependencies = [ "anyhow", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "bincode", "blake3", @@ -3342,7 +3328,7 @@ dependencies = [ "anyhow", "async-broadcast", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bincode", @@ -3357,6 +3343,7 @@ dependencies = [ "hotshot-types", "jf-signature 0.2.0", "jf-vid", + "lru 0.12.5", "rand 0.8.5", "serde", "sha2 0.10.8", @@ -3379,7 +3366,7 @@ dependencies = [ "anyhow", "async-broadcast", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "automod", @@ -3429,7 +3416,7 @@ dependencies = [ "ark-srs", "ark-std", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bincode", @@ -3442,7 +3429,7 @@ dependencies = [ "derivative", "digest 0.10.7", "displaydoc", - "dyn-clone 1.0.17 (git+https://github.com/dtolnay/dyn-clone?tag=1.0.17)", + "dyn-clone", "either", "espresso-systems-common", "ethereum-types", @@ -3506,14 +3493,14 @@ checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http 0.2.12", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", ] [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -3521,15 +3508,15 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", - "http-body 1.0.0", - "pin-project-lite 0.2.14", + "http-body 1.0.1", + "pin-project-lite 0.2.15", ] [[package]] @@ -3557,7 +3544,7 @@ dependencies = [ "cookie", "futures-lite 1.13.0", "infer", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "rand 0.7.3", "serde", "serde_json", @@ -3568,9 +3555,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3586,9 +3573,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -3600,7 +3587,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "socket2 0.5.7", "tokio", "tower-service", @@ -3610,19 +3597,19 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "itoa", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "smallvec", "tokio", "want", @@ -3630,15 +3617,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.3.1", + "hyper 1.5.0", "hyper-util", - "rustls 0.23.7", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls", @@ -3651,8 +3638,8 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.29", - "pin-project-lite 0.2.14", + "hyper 0.14.31", + "pin-project-lite 0.2.15", "tokio", "tokio-io-timeout", ] @@ -3665,7 +3652,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -3675,36 +3662,35 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", - "pin-project-lite 0.2.14", + "http-body 1.0.1", + "hyper 1.5.0", + "pin-project-lite 0.2.15", "socket2 0.5.7", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -3750,103 +3736,232 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "idna" -version = "0.4.0" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_locid_transform" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] -name = "if-addrs" -version = "0.10.2" +name = "icu_locid_transform_data" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] -name = "if-watch" -version = "3.2.0" +name = "icu_normalizer" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ - "async-io 2.3.3", - "core-foundation", - "fnv", - "futures", - "if-addrs", - "ipnet", - "log", - "rtnetlink", - "smol", - "system-configuration 0.5.1", - "tokio", - "windows", + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", ] [[package]] -name = "igd-next" -version = "0.14.3" +name = "icu_normalizer_data" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" -dependencies = [ - "async-trait", - "attohttpc", - "bytes", - "futures", - "http 0.2.12", - "hyper 0.14.29", - "log", - "rand 0.8.5", - "tokio", - "url", - "xmltree", -] +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] -name = "impl-serde" -version = "0.4.0" +name = "icu_properties" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ - "serde", + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +dependencies = [ + "async-io 2.3.4", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "smol", + "system-configuration 0.5.1", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http 0.2.12", + "hyper 0.14.31", + "log", + "rand 0.8.5", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", ] [[package]] name = "include_dir" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" dependencies = [ "proc-macro2", "quote", @@ -3871,12 +3986,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "serde", ] @@ -3910,7 +4025,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -3929,15 +4044,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -4073,7 +4188,7 @@ dependencies = [ "derivative", "displaydoc", "downcast-rs", - "dyn-clone 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dyn-clone", "hashbrown 0.14.5", "itertools 0.12.1", "jf-utils", @@ -4211,9 +4326,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -4266,23 +4381,17 @@ dependencies = [ "spin 0.9.8", ] -[[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.155" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -4290,9 +4399,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p" @@ -4375,15 +4484,14 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.41.2" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8130a8269e65a2554d55131c770bdf4bcd94d2b8d4efb24ca23699be65066c05" +checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" dependencies = [ "either", "fnv", "futures", "futures-timer", - "instant", "libp2p-identity", "multiaddr", "multihash", @@ -4400,6 +4508,7 @@ dependencies = [ "tracing", "unsigned-varint 0.8.0", "void", + "web-time", ] [[package]] @@ -4531,7 +4640,7 @@ version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49007d9a339b3e1d7eeebc4d67c05dbf23d300b7d091193ec2d3f26802d7faf2" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "async-std", "data-encoding", "futures", @@ -4572,16 +4681,18 @@ version = "0.5.79" dependencies = [ "anyhow", "async-compatibility-layer", - "async-lock 2.8.0", + "async-lock 3.4.0", "async-std", "async-trait", "bincode", "blake3", + "cbor4ii", "custom_debug", "delegate", "derive_builder", "either", "futures", + "hotshot-example-types", "hotshot-types", "lazy_static", "libp2p", @@ -4603,9 +4714,9 @@ dependencies = [ [[package]] name = "libp2p-quic" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0375cdfee57b47b313ef1f0fdb625b78aed770d33a40cf1c294a371ff5e6666" +checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" dependencies = [ "async-std", "bytes", @@ -4616,10 +4727,10 @@ dependencies = [ "libp2p-identity", "libp2p-tls", "parking_lot", - "quinn 0.10.2", + "quinn", "rand 0.8.5", - "ring 0.16.20", - "rustls 0.21.11", + "ring 0.17.8", + "rustls 0.23.16", "socket2 0.5.7", "thiserror", "tokio", @@ -4679,10 +4790,10 @@ version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5daceb9dd908417b6dfcfe8e94098bc4aac54500c282e78120b885dadc09b999" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4705,20 +4816,20 @@ dependencies = [ [[package]] name = "libp2p-tls" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ce7e3c2e7569d685d08ec795157981722ff96e9e9f9eae75df3c29d02b07a5" +checksum = "72b7b831e55ce2aa6c354e6861a85fdd4dd0a2b97d5e276fabac0e4810a71776" dependencies = [ "futures", "futures-rustls", "libp2p-core", "libp2p-identity", "rcgen 0.11.3", - "ring 0.16.20", - "rustls 0.21.11", + "ring 0.17.8", + "rustls 0.23.16", "rustls-webpki 0.101.7", "thiserror", - "x509-parser 0.15.1", + "x509-parser", "yasna", ] @@ -4744,7 +4855,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -4825,6 +4936,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "local-ip-address" version = "0.6.3" @@ -4849,9 +4966,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] @@ -4871,7 +4988,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.0", + "hashbrown 0.15.1", ] [[package]] @@ -4935,7 +5052,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4950,9 +5067,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoize" @@ -4997,9 +5114,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -5013,20 +5130,29 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -5040,9 +5166,9 @@ checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -5053,7 +5179,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -5070,13 +5196,13 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", "serde", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -5311,7 +5437,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -5333,7 +5459,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5347,27 +5473,18 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs 0.5.2", -] - -[[package]] -name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -5377,11 +5494,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -5398,7 +5515,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5409,9 +5526,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -5427,12 +5544,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" -version = "0.6.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ "dlv-list", - "hashbrown 0.13.2", + "hashbrown 0.14.5", ] [[package]] @@ -5449,9 +5566,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -5471,7 +5588,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -5484,9 +5601,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "pem" @@ -5515,9 +5632,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -5526,9 +5643,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -5536,22 +5653,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -5560,22 +5677,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5586,9 +5703,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5604,12 +5721,12 @@ checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] @@ -5636,9 +5753,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" @@ -5652,23 +5769,23 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "windows-sys 0.48.0", ] [[package]] name = "polling" -version = "3.7.1" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", - "pin-project-lite 0.2.14", - "rustix 0.38.34", + "hermit-abi 0.4.0", + "pin-project-lite 0.2.15", + "rustix 0.38.39", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5699,18 +5816,21 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5726,11 +5846,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -5788,9 +5908,9 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", @@ -5806,7 +5926,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5829,7 +5949,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5908,61 +6028,27 @@ dependencies = [ "unsigned-varint 0.8.0", ] -[[package]] -name = "quinn" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" -dependencies = [ - "async-io 1.13.0", - "async-std", - "bytes", - "futures-io", - "pin-project-lite 0.2.14", - "quinn-proto 0.10.6", - "quinn-udp 0.4.1", - "rustc-hash 1.1.0", - "rustls 0.21.11", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "quinn" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ + "async-io 2.3.4", + "async-std", "bytes", - "pin-project-lite 0.2.14", - "quinn-proto 0.11.8", - "quinn-udp 0.5.4", + "futures-io", + "pin-project-lite 0.2.15", + "quinn-proto", + "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.7", + "rustls 0.23.16", "socket2 0.5.7", "thiserror", "tokio", "tracing", ] -[[package]] -name = "quinn-proto" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" -dependencies = [ - "bytes", - "rand 0.8.5", - "ring 0.16.20", - "rustc-hash 1.1.0", - "rustls 0.21.11", - "slab", - "thiserror", - "tinyvec", - "tracing", -] - [[package]] name = "quinn-proto" version = "0.11.8" @@ -5973,7 +6059,7 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.7", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -5982,28 +6068,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" -dependencies = [ - "bytes", - "libc", - "socket2 0.5.7", - "tracing", - "windows-sys 0.48.0", -] - -[[package]] -name = "quinn-udp" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6134,7 +6208,7 @@ dependencies = [ "ring 0.17.8", "rustls-pki-types", "time 0.3.36", - "x509-parser 0.16.0", + "x509-parser", "yasna", ] @@ -6153,7 +6227,7 @@ dependencies = [ "itoa", "num-bigint", "percent-encoding", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "ryu", "tokio", "tokio-retry", @@ -6163,27 +6237,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -6192,14 +6257,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -6213,13 +6278,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] @@ -6230,9 +6295,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" @@ -6245,20 +6310,20 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.3.1", + "hyper 1.5.0", "hyper-rustls", "hyper-tls", "hyper-util", @@ -6269,13 +6334,13 @@ dependencies = [ "native-tls", "once_cell", "percent-encoding", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration 0.6.0", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tower-service", @@ -6328,9 +6393,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -6346,9 +6411,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -6362,7 +6427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.5.0", + "bitflags 2.6.0", "serde", "serde_derive", ] @@ -6421,9 +6486,9 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" dependencies = [ "cfg-if", "ordered-multimap", @@ -6464,9 +6529,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -6496,11 +6561,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.14", @@ -6516,65 +6581,39 @@ dependencies = [ "base64 0.13.1", "log", "ring 0.16.20", - "sct 0.6.1", + "sct", "webpki", ] [[package]] name = "rustls" -version = "0.21.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct 0.7.1", -] - -[[package]] -name = "rustls" -version = "0.22.4" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", - "ring 0.17.8", - "rustls-pki-types", - "rustls-webpki 0.102.3", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" -dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.3", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -6588,9 +6627,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -6599,9 +6638,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rw-stream-sink" @@ -6622,11 +6661,11 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6651,16 +6690,6 @@ dependencies = [ "untrusted 0.7.1", ] -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "seahash" version = "4.1.0" @@ -6669,11 +6698,11 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -6682,9 +6711,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -6713,9 +6742,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -6728,7 +6757,7 @@ checksum = "b3acbd21cb24261fc36f595b38d3b34d0ff4e31a6b42edd6a43387d27c5787c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -6742,13 +6771,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -6785,9 +6814,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -6806,15 +6835,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -6824,14 +6853,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -6869,9 +6898,9 @@ dependencies = [ [[package]] name = "sha1_smol" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" @@ -6974,9 +7003,9 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" @@ -7028,7 +7057,7 @@ dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", "async-net", - "async-process", + "async-process 1.8.1", "blocking", "futures-lite 1.13.0", ] @@ -7048,10 +7077,10 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -7101,20 +7130,19 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "itertools 0.12.1", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -7125,9 +7153,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "byteorder", @@ -7142,9 +7170,9 @@ dependencies = [ "futures-io", "futures-util", "hashbrown 0.14.5", - "hashlink", + "hashlink 0.9.1", "hex", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "memchr", "once_cell", @@ -7165,26 +7193,26 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "sqlx-macros-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", - "heck 0.5.0", + "heck", "hex", "once_cell", "proc-macro2", @@ -7196,7 +7224,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.85", + "syn 2.0.87", "tempfile", "tokio", "url", @@ -7204,13 +7232,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "bytes", "crc", @@ -7247,13 +7275,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "crc", "dotenvy", @@ -7286,9 +7314,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "flume", @@ -7308,6 +7336,12 @@ dependencies = [ "url", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "standback" version = "0.2.17" @@ -7391,9 +7425,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "strum_macros" @@ -7401,18 +7435,18 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "surf-disco" @@ -7435,15 +7469,15 @@ dependencies = [ [[package]] name = "sval" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53eb957fbc79a55306d5d25d87daf3627bc3800681491cda0709eef36c748bfe" +checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" [[package]] name = "sval_buffer" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96e860aef60e9cbf37888d4953a13445abf523c534640d1f6174d310917c410d" +checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" dependencies = [ "sval", "sval_ref", @@ -7451,18 +7485,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3f2b07929a1127d204ed7cb3905049381708245727680e9139dac317ed556f" +checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e188677497de274a1367c4bda15bd2296de4070d91729aac8f0a09c1abf64d" +checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" dependencies = [ "itoa", "ryu", @@ -7471,9 +7505,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f456c07dae652744781f2245d5e3b78e6a9ebad70790ac11eb15dbdbce5282" +checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" dependencies = [ "itoa", "ryu", @@ -7482,9 +7516,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886feb24709f0476baaebbf9ac10671a50163caa7e439d7a7beb7f6d81d0a6fb" +checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" dependencies = [ "sval", "sval_buffer", @@ -7493,18 +7527,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2e7fc517d778f44f8cb64140afa36010999565528d48985f55e64d45f369ce" +checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79bf66549a997ff35cd2114a27ac4b0c2843280f2cfa84b240d169ecaa0add46" +checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" dependencies = [ "serde", "sval", @@ -7524,9 +7558,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -7568,7 +7602,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -7584,11 +7618,11 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "system-configuration-sys 0.6.0", ] @@ -7647,34 +7681,35 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", - "fastrand 2.1.0", - "rustix 0.38.34", - "windows-sys 0.52.0", + "fastrand 2.1.1", + "once_cell", + "rustix 0.38.39", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -7711,7 +7746,7 @@ dependencies = [ "http-types", "kv-log-macro", "log", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "route-recognizer", "serde", "serde_json", @@ -7868,11 +7903,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -7894,7 +7939,7 @@ dependencies = [ "libc", "mio", "parking_lot", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", @@ -7908,7 +7953,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" dependencies = [ - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tokio", ] @@ -7920,7 +7965,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -7950,7 +7995,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.7", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -7962,66 +8007,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tokio", ] [[package]] name = "toml" -version = "0.8.15" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.16", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.16" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.11", + "winnow", ] [[package]] @@ -8038,7 +8072,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.31", "hyper-timeout", "percent-encoding", "pin-project", @@ -8065,7 +8099,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.31", "hyper-timeout", "percent-encoding", "pin-project", @@ -8088,7 +8122,7 @@ dependencies = [ "futures-util", "indexmap 1.9.3", "pin-project", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "rand 0.8.5", "slab", "tokio", @@ -8100,15 +8134,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -8117,7 +8151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite 0.2.14", + "pin-project-lite 0.2.15", "tracing-attributes", "tracing-core", ] @@ -8130,7 +8164,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -8255,9 +8289,9 @@ dependencies = [ [[package]] name = "typeid" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" [[package]] name = "typenum" @@ -8267,9 +8301,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -8285,51 +8319,48 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -8377,29 +8408,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.6" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "flate2", "log", "once_cell", - "rustls 0.22.4", + "rustls 0.23.16", "rustls-pki-types", - "rustls-webpki 0.102.3", "url", - "webpki-roots 0.26.2", + "webpki-roots 0.26.6", ] [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -8410,11 +8440,23 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utils" @@ -8425,9 +8467,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -8437,9 +8479,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -8447,9 +8489,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccacf50c5cb077a9abb723c5bcb5e0754c1a433f1e1de89edc328e2760b6328b" +checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" dependencies = [ "erased-serde", "serde", @@ -8458,9 +8500,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1785bae486022dfb9703915d42287dcb284c1ee37bd1080eeba78cc04721285b" +checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" dependencies = [ "sval", "sval_buffer", @@ -8500,9 +8542,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -8536,7 +8578,7 @@ dependencies = [ "futures-util", "headers", "http 0.2.12", - "hyper 0.14.29", + "hyper 0.14.31", "log", "mime", "mime_guess", @@ -8572,11 +8614,12 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "serde", "serde_json", "wasm-bindgen-macro", @@ -8584,24 +8627,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -8611,9 +8654,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8621,28 +8664,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -8669,32 +8722,20 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" 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 0.38.34", -] - [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", ] @@ -8732,7 +8773,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-core", + "windows-core 0.51.1", "windows-targets 0.48.5", ] @@ -8745,6 +8786,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-registry" version = "0.2.0" @@ -8925,18 +8975,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.11" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c52728401e1dc672a56e81e593e912aa54c78f40246869f78359a2bf24d29d" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -8951,6 +8992,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -8960,35 +9013,18 @@ dependencies = [ "tap", ] -[[package]] -name = "x509-parser" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" -dependencies = [ - "asn1-rs 0.5.2", - "data-encoding", - "der-parser 8.2.0", - "lazy_static", - "nom", - "oid-registry 0.6.1", - "rusticata-macros", - "thiserror", - "time 0.3.36", -] - [[package]] name = "x509-parser" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", "data-encoding", - "der-parser 9.0.0", + "der-parser", "lazy_static", "nom", - "oid-registry 0.7.0", + "oid-registry", "ring 0.17.8", "rusticata-macros", "thiserror", @@ -8997,9 +9033,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "xmltree" @@ -9011,12 +9047,14 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yaml-rust2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" dependencies = [ - "linked-hash-map", + "arraydeque", + "encoding_rs", + "hashlink 0.8.4", ] [[package]] @@ -9028,24 +9066,70 @@ dependencies = [ "time 0.3.36", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", ] [[package]] @@ -9065,5 +9149,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index 68292cb3fa..854fc46fd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ async-broadcast = "0.7" async-compatibility-layer = { version = "1.2.1", default-features = false, features = [ "logging-utils", ] } -async-lock = "2" +async-lock = "3" async-std = { version = "1", features = ["attributes"] } async-trait = "0.1" bincode = "1" @@ -174,3 +174,6 @@ rust_2018_idioms = { level = "warn", priority = -1 } # TODO change to deny missing_docs = "warn" warnings = "warn" +unexpected_cfgs = { level = "allow", check-cfg = [ + 'cfg(async_executor_impl, values("tokio", "async-std"))', +] } \ No newline at end of file diff --git a/crates/builder-api/api/v0_1/builder.toml b/crates/builder-api/api/v0_1/builder.toml index f16911a948..7e7ad9d853 100644 --- a/crates/builder-api/api/v0_1/builder.toml +++ b/crates/builder-api/api/v0_1/builder.toml @@ -59,6 +59,19 @@ Get the specified block candidate. Returns application-specific encoded transactions type """ +[route.claim_block_with_num_nodes] +PATH = ["claimblockwithnumnodes/:block_hash/:view_number/:sender/:signature/:num_nodes"] +":block_hash" = "TaggedBase64" +":view_number" = "Integer" +":sender" = "TaggedBase64" +":signature" = "TaggedBase64" +":num_nodes" = "Integer" +DOC = """ +Get the specified block candidate and provide the number of nodes. + +Returns application-specific encoded transactions type +""" + [route.claim_header_input] PATH = ["claimheaderinput/:block_hash/:view_number/:sender/:signature"] ":block_hash" = "TaggedBase64" diff --git a/crates/builder-api/src/v0_1/builder.rs b/crates/builder-api/src/v0_1/builder.rs index 0e1066a8ba..ee70f6b34b 100644 --- a/crates/builder-api/src/v0_1/builder.rs +++ b/crates/builder-api/src/v0_1/builder.rs @@ -158,6 +158,29 @@ where } .boxed() })? + .get("claim_block_with_num_nodes", |req, state| { + async move { + let block_hash: BuilderCommitment = req.blob_param("block_hash")?; + let view_number = req.integer_param("view_number")?; + let signature = try_extract_param(&req, "signature")?; + let sender = try_extract_param(&req, "sender")?; + let num_nodes = req.integer_param("num_nodes")?; + state + .claim_block_with_num_nodes( + &block_hash, + view_number, + sender, + &signature, + num_nodes, + ) + .await + .map_err(|source| Error::BlockClaim { + source, + resource: block_hash.to_string(), + }) + } + .boxed() + })? .get("claim_header_input", |req, state| { async move { let block_hash: BuilderCommitment = req.blob_param("block_hash")?; diff --git a/crates/builder-api/src/v0_1/data_source.rs b/crates/builder-api/src/v0_1/data_source.rs index c36b457623..1c7ee643bf 100644 --- a/crates/builder-api/src/v0_1/data_source.rs +++ b/crates/builder-api/src/v0_1/data_source.rs @@ -28,7 +28,7 @@ pub trait BuilderDataSource { signature: &::PureAssembledSignatureType, ) -> Result>, BuildError>; - /// to claim a block from the list of provided available blocks + /// To claim a block from the list of provided available blocks async fn claim_block( &self, block_hash: &BuilderCommitment, @@ -37,6 +37,17 @@ pub trait BuilderDataSource { signature: &::PureAssembledSignatureType, ) -> Result, BuildError>; + /// To claim a block from the list of provided available blocks and provide the number of nodes + /// information to the builder for VID computation. + async fn claim_block_with_num_nodes( + &self, + block_hash: &BuilderCommitment, + view_number: u64, + sender: TYPES::SignatureKey, + signature: &::PureAssembledSignatureType, + num_nodes: usize, + ) -> Result, BuildError>; + /// To claim a block header input async fn claim_block_header_input( &self, diff --git a/crates/example-types/Cargo.toml b/crates/example-types/Cargo.toml index 65dd60d288..e4ceb2e8c4 100644 --- a/crates/example-types/Cargo.toml +++ b/crates/example-types/Cargo.toml @@ -34,6 +34,7 @@ async-lock = { workspace = true } bitvec = { workspace = true } ethereum-types = { workspace = true } hotshot-task = { path = "../task" } +jf-vid = { workspace = true } vbs = { workspace = true } url = { workspace = true } reqwest = { workspace = true } @@ -42,3 +43,8 @@ reqwest = { workspace = true } tokio = { workspace = true } [target.'cfg(all(async_executor_impl = "async-std"))'.dependencies] async-std = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = [ + 'cfg(async_executor_impl, values("tokio", "async-std"))', +] } diff --git a/crates/example-types/src/node_types.rs b/crates/example-types/src/node_types.rs index 8884d3e7ce..85f9232309 100644 --- a/crates/example-types/src/node_types.rs +++ b/crates/example-types/src/node_types.rs @@ -159,7 +159,7 @@ impl NodeImplementation for CombinedImpl { } impl NodeImplementation for Libp2pImpl { - type Network = Libp2pNetwork; + type Network = Libp2pNetwork; type Storage = TestStorage; type AuctionResultsProvider = TestAuctionResultsProvider; } @@ -176,6 +176,8 @@ impl Versions for TestVersions { ]; type Marketplace = StaticVersion<0, 3>; + + type Epochs = StaticVersion<0, 4>; } #[derive(Clone, Debug, Copy)] @@ -190,6 +192,8 @@ impl Versions for MarketplaceUpgradeTestVersions { ]; type Marketplace = StaticVersion<0, 3>; + + type Epochs = StaticVersion<0, 4>; } #[derive(Clone, Debug, Copy)] @@ -204,6 +208,24 @@ impl Versions for MarketplaceTestVersions { ]; type Marketplace = StaticVersion<0, 3>; + + type Epochs = StaticVersion<0, 4>; +} + +#[derive(Clone, Debug, Copy)] +pub struct EpochsTestVersions {} + +impl Versions for EpochsTestVersions { + type Base = StaticVersion<0, 4>; + type Upgrade = StaticVersion<0, 4>; + const UPGRADE_HASH: [u8; 32] = [ + 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, + ]; + + type Marketplace = StaticVersion<0, 3>; + + type Epochs = StaticVersion<0, 4>; } #[cfg(test)] diff --git a/crates/example-types/src/storage_types.rs b/crates/example-types/src/storage_types.rs index 2a093b1f02..77b6125c52 100644 --- a/crates/example-types/src/storage_types.rs +++ b/crates/example-types/src/storage_types.rs @@ -9,6 +9,7 @@ use std::{ sync::Arc, }; +use crate::testable_delay::{DelayConfig, SupportedTraitTypesForAsyncDelay, TestableDelay}; use anyhow::{bail, Result}; use async_lock::RwLock; use async_trait::async_trait; @@ -23,10 +24,10 @@ use hotshot_types::{ storage::Storage, }, utils::View, + vid::VidSchemeType, vote::HasViewNumber, }; - -use crate::testable_delay::{DelayConfig, SupportedTraitTypesForAsyncDelay, TestableDelay}; +use jf_vid::VidScheme; type VidShares = HashMap< ::View, @@ -117,7 +118,11 @@ impl Storage for TestStorage { Ok(()) } - async fn append_da(&self, proposal: &Proposal>) -> Result<()> { + async fn append_da( + &self, + proposal: &Proposal>, + _vid_commit: ::Commit, + ) -> Result<()> { if self.should_return_err { bail!("Failed to append VID proposal to storage"); } diff --git a/crates/examples/infra/mod.rs b/crates/examples/infra/mod.rs index e85679ec12..453efe0261 100755 --- a/crates/examples/infra/mod.rs +++ b/crates/examples/infra/mod.rs @@ -62,7 +62,7 @@ use hotshot_types::{ }, HotShotConfig, PeerConfig, ValidatorConfig, }; -use libp2p_networking::network::GossipConfig; +use libp2p_networking::network::{GossipConfig, RequestResponseConfig}; use rand::{rngs::StdRng, SeedableRng}; use surf_disco::Url; use tracing::{debug, error, info, warn}; @@ -374,9 +374,7 @@ pub trait RunDa< let all_nodes = if cfg!(feature = "fixed-leader-election") { let mut vec = config.config.known_nodes_with_stake.clone(); - vec.truncate(config.config.fixed_leader_for_gpuvid); - vec } else { config.config.known_nodes_with_stake.clone() @@ -696,7 +694,7 @@ pub struct Libp2pDaRun { /// The private validator config validator_config: ValidatorConfig, /// The underlying network - network: Libp2pNetwork, + network: Libp2pNetwork, } #[async_trait] @@ -709,12 +707,12 @@ impl< >, NODE: NodeImplementation< TYPES, - Network = Libp2pNetwork, + Network = Libp2pNetwork, Storage = TestStorage, AuctionResultsProvider = TestAuctionResultsProvider, >, V: Versions, - > RunDa, NODE, V> for Libp2pDaRun + > RunDa, NODE, V> for Libp2pDaRun where ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, @@ -753,6 +751,10 @@ where .to_string() }; + // Create the qurorum membership from the list of known nodes + let all_nodes = config.config.known_nodes_with_stake.clone(); + let quorum_membership = TYPES::Membership::new(all_nodes.clone(), all_nodes, Topic::Global); + // Derive the bind address let bind_address = derive_libp2p_multiaddr(&bind_address).expect("failed to derive bind address"); @@ -760,7 +762,9 @@ where // Create the Libp2p network let libp2p_network = Libp2pNetwork::from_config( config.clone(), + quorum_membership, GossipConfig::default(), + RequestResponseConfig::default(), bind_address, public_key, private_key, @@ -779,7 +783,7 @@ where } } - fn network(&self) -> Libp2pNetwork { + fn network(&self) -> Libp2pNetwork { self.network.clone() } diff --git a/crates/examples/libp2p/types.rs b/crates/examples/libp2p/types.rs index afcfa236a1..ed8fbcda6f 100644 --- a/crates/examples/libp2p/types.rs +++ b/crates/examples/libp2p/types.rs @@ -11,7 +11,7 @@ use hotshot_example_types::{ auction_results_provider_types::TestAuctionResultsProvider, state_types::TestTypes, storage_types::TestStorage, }; -use hotshot_types::traits::node_implementation::{NodeImplementation, NodeType}; +use hotshot_types::traits::node_implementation::NodeImplementation; use serde::{Deserialize, Serialize}; use crate::infra::Libp2pDaRun; @@ -21,7 +21,7 @@ use crate::infra::Libp2pDaRun; pub struct NodeImpl {} /// Convenience type alias -pub type Network = Libp2pNetwork<::SignatureKey>; +pub type Network = Libp2pNetwork; impl NodeImplementation for NodeImpl { type Network = Network; diff --git a/crates/hotshot/src/lib.rs b/crates/hotshot/src/lib.rs index 08b1ef1548..eddf722a0b 100644 --- a/crates/hotshot/src/lib.rs +++ b/crates/hotshot/src/lib.rs @@ -325,6 +325,7 @@ impl, V: Versions> SystemContext, V: Versions> SystemContext(&mut handle).await; @@ -765,6 +767,7 @@ where SystemContextHandle, SystemContextHandle, ) { + let epoch_height = config.epoch_height; let left_system_context = SystemContext::new( public_key.clone(), private_key.clone(), @@ -832,6 +835,7 @@ where storage: Arc::clone(&left_system_context.storage), network: Arc::clone(&left_system_context.network), memberships: Arc::clone(&left_system_context.memberships), + epoch_height, }; let mut right_handle = SystemContextHandle { @@ -843,6 +847,7 @@ where storage: Arc::clone(&right_system_context.storage), network: Arc::clone(&right_system_context.network), memberships: Arc::clone(&right_system_context.memberships), + epoch_height, }; // add consensus tasks to each handle, using their individual internal event streams @@ -1024,9 +1029,9 @@ impl HotShotInitializer { /// /// # Arguments /// * `start_view` - The minimum view number that we are confident won't lead to a double vote - /// after restart. + /// after restart. /// * `validated_state` - Optional validated state that if given, will be used to construct the - /// `SystemContext`. + /// `SystemContext`. #[allow(clippy::too_many_arguments)] pub fn from_reload( anchor_leaf: Leaf, diff --git a/crates/hotshot/src/tasks/mod.rs b/crates/hotshot/src/tasks/mod.rs index cca95d3c76..5d1476673d 100644 --- a/crates/hotshot/src/tasks/mod.rs +++ b/crates/hotshot/src/tasks/mod.rs @@ -8,6 +8,7 @@ /// Provides trait to create task states from a `SystemContextHandle` pub mod task_state; +use std::collections::BTreeMap; use std::{fmt::Debug, sync::Arc, time::Duration}; use async_broadcast::{broadcast, RecvError}; @@ -118,6 +119,7 @@ pub fn add_queue_len_task, V: Vers } /// Add the network task to handle messages and publish events. +#[allow(clippy::missing_panics_doc)] pub fn add_network_message_task< TYPES: NodeType, I: NodeImplementation, @@ -200,6 +202,7 @@ pub fn add_network_event_task< storage: Arc::clone(&handle.storage()), consensus: Arc::clone(&handle.consensus()), upgrade_lock: handle.hotshot.upgrade_lock.clone(), + transmit_tasks: BTreeMap::new(), }; let task = Task::new( network_state, @@ -327,6 +330,7 @@ where storage: I::Storage, marketplace_config: MarketplaceConfig, ) -> SystemContextHandle { + let epoch_height = config.epoch_height; let hotshot = SystemContext::new( public_key, private_key, @@ -355,6 +359,7 @@ where storage: Arc::clone(&hotshot.storage), network: Arc::clone(&hotshot.network), memberships: Arc::clone(&hotshot.memberships), + epoch_height, }; add_consensus_tasks::(&mut handle).await; diff --git a/crates/hotshot/src/tasks/task_state.rs b/crates/hotshot/src/tasks/task_state.rs index ead7b745f6..1a9065692d 100644 --- a/crates/hotshot/src/tasks/task_state.rs +++ b/crates/hotshot/src/tasks/task_state.rs @@ -268,6 +268,7 @@ impl, V: Versions> CreateTaskState id: handle.hotshot.id, formed_upgrade_certificate: None, upgrade_lock: handle.hotshot.upgrade_lock.clone(), + epoch_height: handle.hotshot.config.epoch_height, } } } @@ -284,18 +285,12 @@ impl, V: Versions> CreateTaskState private_key: handle.private_key().clone(), consensus: OuterConsensus::new(consensus), cur_view: handle.cur_view().await, - cur_view_time: Utc::now().timestamp(), cur_epoch: handle.cur_epoch().await, - network: Arc::clone(&handle.hotshot.network), quorum_membership: handle.hotshot.memberships.quorum_membership.clone().into(), - timeout_membership: handle.hotshot.memberships.quorum_membership.clone().into(), - timeout_task: async_spawn(async {}), timeout: handle.hotshot.config.next_view_timeout, output_event_stream: handle.hotshot.external_event_stream.0.clone(), storage: Arc::clone(&handle.storage), - proposal_cert: None, spawned_tasks: BTreeMap::new(), - instance_state: handle.hotshot.instance_state(), id: handle.hotshot.id, upgrade_lock: handle.hotshot.upgrade_lock.clone(), } diff --git a/crates/hotshot/src/traits.rs b/crates/hotshot/src/traits.rs index 8667943189..1ff090fc06 100644 --- a/crates/hotshot/src/traits.rs +++ b/crates/hotshot/src/traits.rs @@ -20,7 +20,7 @@ pub mod implementations { combined_network::{CombinedNetworks, UnderlyingCombinedNetworks}, libp2p_network::{ derive_libp2p_keypair, derive_libp2p_multiaddr, derive_libp2p_peer_id, GossipConfig, - Libp2pMetricsValue, Libp2pNetwork, PeerInfoVec, + Libp2pMetricsValue, Libp2pNetwork, PeerInfoVec, RequestResponseConfig, }, memory_network::{MasterMap, MemoryNetwork}, push_cdn_network::{ diff --git a/crates/hotshot/src/traits/networking/combined_network.rs b/crates/hotshot/src/traits/networking/combined_network.rs index 584e4e888e..9678c54244 100644 --- a/crates/hotshot/src/traits/networking/combined_network.rs +++ b/crates/hotshot/src/traits/networking/combined_network.rs @@ -95,7 +95,7 @@ impl CombinedNetworks { #[must_use] pub fn new( primary_network: PushCdnNetwork, - secondary_network: Libp2pNetwork, + secondary_network: Libp2pNetwork, delay_duration: Option, ) -> Self { // Create networks from the ones passed in @@ -127,7 +127,7 @@ impl CombinedNetworks { /// Get a ref to the backup network #[must_use] - pub fn secondary(&self) -> &Libp2pNetwork { + pub fn secondary(&self) -> &Libp2pNetwork { &self.networks.1 } @@ -251,7 +251,7 @@ impl CombinedNetworks { #[derive(Clone)] pub struct UnderlyingCombinedNetworks( pub PushCdnNetwork, - pub Libp2pNetwork, + pub Libp2pNetwork, ); #[cfg(feature = "hotshot-testing")] @@ -273,7 +273,7 @@ impl TestableNetworkingImplementation for CombinedNetwor None, Duration::default(), ), - as TestableNetworkingImplementation>::generator( + as TestableNetworkingImplementation>::generator( expected_node_count, num_bootstrap, network_id, @@ -297,7 +297,7 @@ impl TestableNetworkingImplementation for CombinedNetwor // Combine the two let underlying_combined = UnderlyingCombinedNetworks( cdn.clone(), - Arc::>::unwrap_or_clone(p2p), + Arc::>::unwrap_or_clone(p2p), ); // We want to use the same message cache between the two networks @@ -462,11 +462,8 @@ impl ConnectedNetwork for CombinedNetworks // Calculate hash of the message let message_hash = calculate_hash_of(&message); - // Check if the hash is in the cache - if !self.message_cache.read().contains(&message_hash) { - // Add the hash to the cache - self.message_cache.write().put(message_hash, ()); - + // Check if the hash is in the cache and update the cache + if self.message_cache.write().put(message_hash, ()).is_none() { break Ok(message); } } diff --git a/crates/hotshot/src/traits/networking/libp2p_network.rs b/crates/hotshot/src/traits/networking/libp2p_network.rs index cd78a8fbc0..a8bc4ff6e4 100644 --- a/crates/hotshot/src/traits/networking/libp2p_network.rs +++ b/crates/hotshot/src/traits/networking/libp2p_network.rs @@ -59,7 +59,7 @@ use libp2p_identity::{ ed25519::{self, SecretKey}, Keypair, PeerId, }; -pub use libp2p_networking::network::GossipConfig; +pub use libp2p_networking::network::{GossipConfig, RequestResponseConfig}; use libp2p_networking::{ network::{ behaviours::dht::record::{Namespace, RecordKey, RecordValue}, @@ -132,7 +132,7 @@ pub struct Empty { byte: u8, } -impl Debug for Libp2pNetwork { +impl Debug for Libp2pNetwork { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Libp2p").field("inner", &"inner").finish() } @@ -143,17 +143,17 @@ pub type PeerInfoVec = Arc>>; /// The underlying state of the libp2p network #[derive(Debug)] -struct Libp2pNetworkInner { +struct Libp2pNetworkInner { /// this node's public key - pk: K, + pk: T::SignatureKey, /// handle to control the network - handle: Arc>, + handle: Arc>, /// Message Receiver receiver: UnboundedReceiver>, /// Sender for broadcast messages sender: UnboundedSender>, /// Sender for node lookup (relevant view number, key of node) (None for shutdown) - node_lookup_send: BoundedSender>, + node_lookup_send: BoundedSender>, /// this is really cheating to enable local tests /// hashset of (bootstrap_addr, peer_id) bootstrap_addrs: PeerInfoVec, @@ -181,15 +181,13 @@ struct Libp2pNetworkInner { /// Networking implementation that uses libp2p /// generic over `M` which is the message type #[derive(Clone)] -pub struct Libp2pNetwork { +pub struct Libp2pNetwork { /// holds the state of the libp2p network - inner: Arc>, + inner: Arc>, } #[cfg(feature = "hotshot-testing")] -impl TestableNetworkingImplementation - for Libp2pNetwork -{ +impl TestableNetworkingImplementation for Libp2pNetwork { /// Returns a boxed function `f(node_id, public_key) -> Libp2pNetwork` /// with the purpose of generating libp2p networks. /// Generates `num_bootstrap` bootstrap nodes. The remainder of nodes are normal @@ -232,12 +230,11 @@ impl TestableNetworkingImplementation Multiaddr::from_str(&format!("/ip4/127.0.0.1/udp/{port}/quic-v1")).unwrap(); // We assign node's public key and stake value rather than read from config file since it's a test - let privkey = - TYPES::SignatureKey::generated_from_seed_indexed([0u8; 32], node_id).1; - let pubkey = TYPES::SignatureKey::from_private(&privkey); + let privkey = T::SignatureKey::generated_from_seed_indexed([0u8; 32], node_id).1; + let pubkey = T::SignatureKey::from_private(&privkey); // Derive the Libp2p keypair from the private key - let libp2p_keypair = derive_libp2p_keypair::(&privkey) + let libp2p_keypair = derive_libp2p_keypair::(&privkey) .expect("Failed to derive libp2p keypair"); // Sign the lookup record @@ -383,7 +380,7 @@ pub fn derive_libp2p_multiaddr(addr: &String) -> anyhow::Result { }) } -impl Libp2pNetwork { +impl Libp2pNetwork { /// Create and return a Libp2p network from a network config file /// and various other configuration-specific values. /// @@ -392,12 +389,15 @@ impl Libp2pNetwork { /// /// # Panics /// If we are unable to calculate the replication factor + #[allow(clippy::too_many_arguments)] pub async fn from_config( - mut config: NetworkConfig, + mut config: NetworkConfig, + quorum_membership: T::Membership, gossip_config: GossipConfig, + request_response_config: RequestResponseConfig, bind_address: Multiaddr, - pub_key: &K, - priv_key: &K::PrivateKey, + pub_key: &T::SignatureKey, + priv_key: &::PrivateKey, metrics: Libp2pMetricsValue, ) -> anyhow::Result { // Try to take our Libp2p config from our broader network config @@ -407,29 +407,23 @@ impl Libp2pNetwork { .ok_or(anyhow!("Libp2p config not supplied"))?; // Derive our Libp2p keypair from our supplied private key - let keypair = derive_libp2p_keypair::(priv_key)?; + let keypair = derive_libp2p_keypair::(priv_key)?; // Build our libp2p configuration let mut config_builder = NetworkNodeConfigBuilder::default(); // Set the gossip configuration config_builder.gossip_config(gossip_config.clone()); + config_builder.request_response_config(request_response_config); - // Extrapolate the stake table from the known nodes - let stake_table: HashSet = config - .config - .known_nodes_with_stake - .iter() - .map(|node| K::public_key(&node.stake_table_entry)) - .collect(); - + // Construct the auth message let auth_message = construct_auth_message(pub_key, &keypair.public().to_peer_id(), priv_key) .with_context(|| "Failed to construct auth message")?; // Set the auth message and stake table config_builder - .stake_table(Some(stake_table)) + .stake_table(Some(quorum_membership)) .auth_message(Some(auth_message)); // The replication factor is the minimum of [the default and 2/3 the number of nodes] @@ -472,7 +466,7 @@ impl Libp2pNetwork { // Insert all known nodes into the set of all keys for node in config.config.known_nodes_with_stake { - all_keys.insert(K::public_key(&node.stake_table_entry)); + all_keys.insert(T::SignatureKey::public_key(&node.stake_table_entry)); } Ok(Libp2pNetwork::new( @@ -519,14 +513,14 @@ impl Libp2pNetwork { #[allow(clippy::too_many_arguments)] pub async fn new( metrics: Libp2pMetricsValue, - config: NetworkNodeConfig, - pk: K, - lookup_record_value: RecordValue, + config: NetworkNodeConfig, + pk: T::SignatureKey, + lookup_record_value: RecordValue, bootstrap_addrs: BootstrapAddrs, id: usize, #[cfg(feature = "hotshot-testing")] reliability_config: Option>, - ) -> Result, NetworkError> { - let (mut rx, network_handle) = spawn_network_node::(config.clone(), id) + ) -> Result, NetworkError> { + let (mut rx, network_handle) = spawn_network_node::(config.clone(), id) .await .map_err(|e| NetworkError::ConfigError(format!("failed to spawn network node: {e}")))?; @@ -584,7 +578,10 @@ impl Libp2pNetwork { /// Spawns task for looking up nodes pre-emptively #[allow(clippy::cast_sign_loss, clippy::cast_precision_loss)] - fn spawn_node_lookup(&self, mut node_lookup_recv: BoundedReceiver>) { + fn spawn_node_lookup( + &self, + mut node_lookup_recv: BoundedReceiver>, + ) { let handle = Arc::clone(&self.inner.handle); let dht_timeout = self.inner.dht_timeout; let latest_seen_view = Arc::clone(&self.inner.latest_seen_view); @@ -611,7 +608,7 @@ impl Libp2pNetwork { } /// Initiates connection to the outside world - fn spawn_connect(&mut self, id: usize, lookup_record_value: RecordValue) { + fn spawn_connect(&mut self, id: usize, lookup_record_value: RecordValue) { let pk = self.inner.pk.clone(); let bootstrap_ref = Arc::clone(&self.inner.bootstrap_addrs); let handle = Arc::clone(&self.inner.handle); @@ -763,7 +760,7 @@ impl Libp2pNetwork { } #[async_trait] -impl ConnectedNetwork for Libp2pNetwork { +impl ConnectedNetwork for Libp2pNetwork { #[instrument(name = "Libp2pNetwork::ready_blocking", skip_all)] async fn wait_for_ready(&self) { self.wait_for_ready().await; @@ -852,7 +849,7 @@ impl ConnectedNetwork for Libp2pNetwork { async fn da_broadcast_message( &self, message: Vec, - recipients: Vec, + recipients: Vec, _broadcast_delay: BroadcastDelay, ) -> Result<(), NetworkError> { // If we're not ready, return an error @@ -882,7 +879,11 @@ impl ConnectedNetwork for Libp2pNetwork { } #[instrument(name = "Libp2pNetwork::direct_message", skip_all)] - async fn direct_message(&self, message: Vec, recipient: K) -> Result<(), NetworkError> { + async fn direct_message( + &self, + message: Vec, + recipient: T::SignatureKey, + ) -> Result<(), NetworkError> { // If we're not ready, return an error if !self.is_ready() { self.inner.metrics.num_failed_messages.add(1); @@ -964,11 +965,12 @@ impl ConnectedNetwork for Libp2pNetwork { } #[instrument(name = "Libp2pNetwork::queue_node_lookup", skip_all)] + #[allow(clippy::type_complexity)] fn queue_node_lookup( &self, view_number: ViewNumber, - pk: K, - ) -> Result<(), TrySendError>> { + pk: T::SignatureKey, + ) -> Result<(), TrySendError>> { self.inner .node_lookup_send .try_send(Some((view_number, pk))) @@ -988,7 +990,7 @@ impl ConnectedNetwork for Libp2pNetwork { /// use of the future view and leader to queue the lookups. async fn update_view<'a, TYPES>(&'a self, view: u64, epoch: u64, membership: &TYPES::Membership) where - TYPES: NodeType + 'a, + TYPES: NodeType + 'a, { let future_view = ::View::new(view) + LOOK_AHEAD; let epoch = ::Epoch::new(epoch); diff --git a/crates/hotshot/src/traits/networking/push_cdn_network.rs b/crates/hotshot/src/traits/networking/push_cdn_network.rs index c0c2f5d957..a0a4799c4a 100644 --- a/crates/hotshot/src/traits/networking/push_cdn_network.rs +++ b/crates/hotshot/src/traits/networking/push_cdn_network.rs @@ -470,11 +470,15 @@ impl ConnectedNetwork for PushCdnNetwork { topic: HotShotTopic, _broadcast_delay: BroadcastDelay, ) -> Result<(), NetworkError> { + // If we're paused, don't send the message + #[cfg(feature = "hotshot-testing")] + if self.is_paused.load(Ordering::Relaxed) { + return Ok(()); + } self.broadcast_message(message, topic.into()) .await - .map_err(|e| { + .inspect_err(|_e| { self.metrics.num_failed_messages.add(1); - e }) } @@ -489,11 +493,15 @@ impl ConnectedNetwork for PushCdnNetwork { _recipients: Vec, _broadcast_delay: BroadcastDelay, ) -> Result<(), NetworkError> { + // If we're paused, don't send the message + #[cfg(feature = "hotshot-testing")] + if self.is_paused.load(Ordering::Relaxed) { + return Ok(()); + } self.broadcast_message(message, Topic::Da) .await - .map_err(|e| { + .inspect_err(|_e| { self.metrics.num_failed_messages.add(1); - e }) } @@ -535,6 +543,7 @@ impl ConnectedNetwork for PushCdnNetwork { // If we're paused, receive but don't process messages #[cfg(feature = "hotshot-testing")] if self.is_paused.load(Ordering::Relaxed) { + async_sleep(Duration::from_millis(100)).await; return Ok(vec![]); } diff --git a/crates/hotshot/src/types/handle.rs b/crates/hotshot/src/types/handle.rs index 735c219420..2ab7874b8f 100644 --- a/crates/hotshot/src/types/handle.rs +++ b/crates/hotshot/src/types/handle.rs @@ -70,6 +70,9 @@ pub struct SystemContextHandle, V: /// Memberships used by consensus pub memberships: Arc>, + + /// Number of blocks in an epoch, zero means there are no epochs + pub epoch_height: u64, } impl + 'static, V: Versions> @@ -222,6 +225,7 @@ impl + 'static, V: Versions> /// there are two cleaner solutions: /// - make the stream generic and in nodetypes or nodeimpelmentation /// - type wrapper + /// /// NOTE: this is only used for sanity checks in our tests #[must_use] pub fn internal_event_stream_receiver_known_impl(&self) -> Receiver>> { diff --git a/crates/libp2p-networking/Cargo.toml b/crates/libp2p-networking/Cargo.toml index ecf4aa20fb..16ada4dcfa 100644 --- a/crates/libp2p-networking/Cargo.toml +++ b/crates/libp2p-networking/Cargo.toml @@ -11,6 +11,9 @@ authors = { workspace = true } default = ["webui"] webui = [] +[dev-dependencies] +hotshot-example-types = { path = "../example-types" } + [dependencies] anyhow = { workspace = true } async-compatibility-layer = { workspace = true } @@ -39,6 +42,7 @@ void = "1" lazy_static = { workspace = true } pin-project = "1" portpicker.workspace = true +cbor4ii = "0.3" [target.'cfg(all(async_executor_impl = "tokio"))'.dependencies] libp2p = { workspace = true, features = ["tokio"] } diff --git a/crates/libp2p-networking/README.md b/crates/libp2p-networking/README.md index 62a190398b..51afee2c44 100644 --- a/crates/libp2p-networking/README.md +++ b/crates/libp2p-networking/README.md @@ -55,11 +55,11 @@ ulimit -n 4096 In these tests, there are three types of nodes. `Regular` nodes that limit the number of incoming connections, `Bootstrap` nodes that allow all connections, and `Conductor` nodes that all nodes (bootstrap and regular) connect to and periodically ping with their state. This "conductor" node instructs nodes in the swarm to increment their state either via broadcast or direct messages in the same fashion as the single machine tests. -In the direct message case, the conductor will increment the state of a randomly chosen node, `i`. Then the conductor will direct message all other nodes to request node `i`'s counter and increment their counter to the value in `i`'s node. In the broadcast case, the conductor will increment the state of a randomly chose node, `i`, and tell `i` to broadcast this incremented state. +In the direct message case, the conductor will increment the state of a randomly chosen node, `i`. Then the conductor will direct message all other nodes to request node `i`'s counter and increment their counter to the value in `i`'s node. In the broadcast case, the conductor will increment the state of a randomly chosen node, `i`, and tell `i` to broadcast this incremented state. In both cases, the test terminates as successful when the conductor receives the incremented state from all other nodes. Then, the conductor sends a special "kill" message to all known nodes and waits for them to disconnect. -Metadata about the toplogy is currently read from an `identity_mapping.json` file that manually labels the type of node (bootstrap, regular, conductor). The conductor uses this to figure out information about all nodes in the network. The regular nodes use this to learn about their ip address and the addresses necessary to bootstrap onto the network. The boostrap nodes only use this to learn about their ip addresses. +Metadata about the topology is currently read from an `identity_mapping.json` file that manually labels the type of node (bootstrap, regular, conductor). The conductor uses this to figure out information about all nodes in the network. The regular nodes use this to learn about their ip address and the addresses necessary to bootstrap onto the network. The bootstrap nodes only use this to learn about their ip addresses. ### Running counter multi-machine tests @@ -75,7 +75,7 @@ nix develop -c cargo run --features webui,async-std-executor --release --example ``` ### Network Emulation -One may introduce simulated network latency via the network emulationn queueing discipline. This is implemented in two ways: on what is assumed to be a AWS EC2 instance, and in a docker container. Example usage on AWS EC2 instance: +One may introduce simulated network latency via the network emulation queueing discipline. This is implemented in two ways: on what is assumed to be a AWS EC2 instance, and in a docker container. Example usage on AWS EC2 instance: ```bash # run each line in a separate AWS instance diff --git a/crates/libp2p-networking/src/network/cbor.rs b/crates/libp2p-networking/src/network/cbor.rs new file mode 100644 index 0000000000..4a5685624b --- /dev/null +++ b/crates/libp2p-networking/src/network/cbor.rs @@ -0,0 +1,146 @@ +use std::{collections::TryReserveError, convert::Infallible, io, marker::PhantomData}; + +use async_trait::async_trait; +use cbor4ii::core::error::DecodeError; +use futures::prelude::*; +use libp2p::{ + request_response::{self, Codec}, + StreamProtocol, +}; +use serde::{de::DeserializeOwned, Serialize}; + +/// `Behaviour` type alias for the `Cbor` codec +pub type Behaviour = request_response::Behaviour>; + +/// Forked `cbor` codec with altered request/response sizes +pub struct Cbor { + /// Phantom data + phantom: PhantomData<(Req, Resp)>, + /// Maximum request size in bytes + request_size_maximum: u64, + /// Maximum response size in bytes + response_size_maximum: u64, +} + +impl Default for Cbor { + fn default() -> Self { + Cbor { + phantom: PhantomData, + request_size_maximum: 20 * 1024 * 1024, + response_size_maximum: 20 * 1024 * 1024, + } + } +} + +impl Cbor { + /// Create a new `Cbor` codec with the given request and response sizes + #[must_use] + pub fn new(request_size_maximum: u64, response_size_maximum: u64) -> Self { + Cbor { + phantom: PhantomData, + request_size_maximum, + response_size_maximum, + } + } +} + +impl Clone for Cbor { + fn clone(&self) -> Self { + Self::default() + } +} + +#[async_trait] +impl Codec for Cbor +where + Req: Send + Serialize + DeserializeOwned, + Resp: Send + Serialize + DeserializeOwned, +{ + type Protocol = StreamProtocol; + type Request = Req; + type Response = Resp; + + async fn read_request(&mut self, _: &Self::Protocol, io: &mut T) -> io::Result + where + T: AsyncRead + Unpin + Send, + { + let mut vec = Vec::new(); + + io.take(self.request_size_maximum) + .read_to_end(&mut vec) + .await?; + + cbor4ii::serde::from_slice(vec.as_slice()).map_err(decode_into_io_error) + } + + async fn read_response(&mut self, _: &Self::Protocol, io: &mut T) -> io::Result + where + T: AsyncRead + Unpin + Send, + { + let mut vec = Vec::new(); + + io.take(self.response_size_maximum) + .read_to_end(&mut vec) + .await?; + + cbor4ii::serde::from_slice(vec.as_slice()).map_err(decode_into_io_error) + } + + async fn write_request( + &mut self, + _: &Self::Protocol, + io: &mut T, + req: Self::Request, + ) -> io::Result<()> + where + T: AsyncWrite + Unpin + Send, + { + let data: Vec = + cbor4ii::serde::to_vec(Vec::new(), &req).map_err(encode_into_io_error)?; + + io.write_all(data.as_ref()).await?; + + Ok(()) + } + + async fn write_response( + &mut self, + _: &Self::Protocol, + io: &mut T, + resp: Self::Response, + ) -> io::Result<()> + where + T: AsyncWrite + Unpin + Send, + { + let data: Vec = + cbor4ii::serde::to_vec(Vec::new(), &resp).map_err(encode_into_io_error)?; + + io.write_all(data.as_ref()).await?; + + Ok(()) + } +} + +/// Convert a `cbor4ii::serde::DecodeError` into an `io::Error` +fn decode_into_io_error(err: cbor4ii::serde::DecodeError) -> io::Error { + match err { + cbor4ii::serde::DecodeError::Core(DecodeError::Read(e)) => { + io::Error::new(io::ErrorKind::Other, e) + } + cbor4ii::serde::DecodeError::Core(e @ DecodeError::Unsupported { .. }) => { + io::Error::new(io::ErrorKind::Unsupported, e) + } + cbor4ii::serde::DecodeError::Core(e @ DecodeError::Eof { .. }) => { + io::Error::new(io::ErrorKind::UnexpectedEof, e) + } + cbor4ii::serde::DecodeError::Core(e) => io::Error::new(io::ErrorKind::InvalidData, e), + cbor4ii::serde::DecodeError::Custom(e) => { + io::Error::new(io::ErrorKind::Other, e.to_string()) + } + } +} + +/// Convert a `cbor4ii::serde::EncodeError` into an `io::Error` +fn encode_into_io_error(err: cbor4ii::serde::EncodeError) -> io::Error { + io::Error::new(io::ErrorKind::Other, err) +} diff --git a/crates/libp2p-networking/src/network/def.rs b/crates/libp2p-networking/src/network/def.rs index 39d6bdd1b2..ca0045dcb0 100644 --- a/crates/libp2p-networking/src/network/def.rs +++ b/crates/libp2p-networking/src/network/def.rs @@ -10,14 +10,14 @@ use libp2p::{ gossipsub::{Behaviour as GossipBehaviour, Event as GossipEvent, IdentTopic}, identify::{Behaviour as IdentifyBehaviour, Event as IdentifyEvent}, kad::store::MemoryStore, - request_response::{cbor, OutboundRequestId, ResponseChannel}, + request_response::{OutboundRequestId, ResponseChannel}, Multiaddr, }; use libp2p_identity::PeerId; use libp2p_swarm_derive::NetworkBehaviour; use tracing::{debug, error}; -use super::{behaviours::dht::store::ValidatedStore, NetworkEventInternal}; +use super::{behaviours::dht::store::ValidatedStore, cbor, NetworkEventInternal}; /// Overarching network behaviour performing: /// - network topology discovoery @@ -45,7 +45,7 @@ pub struct NetworkDef { /// purpose: directly messaging peer #[debug(skip)] - pub direct_message: libp2p::request_response::cbor::Behaviour, Vec>, + pub direct_message: cbor::Behaviour, Vec>, /// Auto NAT behaviour to determine if we are publically reachable and /// by which address @@ -60,7 +60,7 @@ impl NetworkDef { gossipsub: GossipBehaviour, dht: libp2p::kad::Behaviour>, identify: IdentifyBehaviour, - direct_message: cbor::Behaviour, Vec>, + direct_message: super::cbor::Behaviour, Vec>, autonat: autonat::Behaviour, ) -> NetworkDef { Self { diff --git a/crates/libp2p-networking/src/network/mod.rs b/crates/libp2p-networking/src/network/mod.rs index 693ef1e292..a23c74fbd3 100644 --- a/crates/libp2p-networking/src/network/mod.rs +++ b/crates/libp2p-networking/src/network/mod.rs @@ -13,10 +13,13 @@ mod node; /// Alternative Libp2p transport implementations pub mod transport; +/// Forked `cbor` codec with altered request/response sizes +pub mod cbor; + use std::{collections::HashSet, fmt::Debug}; use futures::channel::oneshot::Sender; -use hotshot_types::traits::{network::NetworkError, signature_key::SignatureKey}; +use hotshot_types::traits::{network::NetworkError, node_implementation::NodeType}; #[cfg(async_executor_impl = "async-std")] use libp2p::dns::async_std::Transport as DnsTransport; #[cfg(async_executor_impl = "tokio")] @@ -44,7 +47,7 @@ pub use self::{ node::{ spawn_network_node, GossipConfig, NetworkNode, NetworkNodeConfig, NetworkNodeConfigBuilder, NetworkNodeConfigBuilderError, NetworkNodeHandle, NetworkNodeReceiver, - DEFAULT_REPLICATION_FACTOR, + RequestResponseConfig, DEFAULT_REPLICATION_FACTOR, }, }; #[cfg(not(any(async_executor_impl = "async-std", async_executor_impl = "tokio")))] @@ -162,9 +165,9 @@ type BoxedTransport = Boxed<(PeerId, StreamMuxerBox)>; /// # Errors /// If we could not create a DNS transport #[instrument(skip(identity))] -pub async fn gen_transport( +pub async fn gen_transport( identity: Keypair, - stake_table: Option>, + stake_table: Option, auth_message: Option>, ) -> Result { // Create the initial `Quic` transport @@ -175,7 +178,8 @@ pub async fn gen_transport( }; // Require authentication against the stake table - let transport = StakeTableAuthentication::new(transport, stake_table, auth_message); + let transport: StakeTableAuthentication<_, T, _> = + StakeTableAuthentication::new(transport, stake_table, auth_message); // Support DNS resolution let transport = { diff --git a/crates/libp2p-networking/src/network/node.rs b/crates/libp2p-networking/src/network/node.rs index 08e896d785..8e3b7888f0 100644 --- a/crates/libp2p-networking/src/network/node.rs +++ b/crates/libp2p-networking/src/network/node.rs @@ -14,7 +14,6 @@ mod handle; use std::{ collections::{HashMap, HashSet}, iter, - marker::PhantomData, num::{NonZeroU32, NonZeroUsize}, time::Duration, }; @@ -25,7 +24,7 @@ use async_compatibility_layer::{ }; use futures::{channel::mpsc, select, FutureExt, SinkExt, StreamExt}; use hotshot_types::{ - constants::KAD_DEFAULT_REPUB_INTERVAL_SEC, traits::signature_key::SignatureKey, + constants::KAD_DEFAULT_REPUB_INTERVAL_SEC, traits::node_implementation::NodeType, }; use libp2p::{ autonat, @@ -41,7 +40,7 @@ use libp2p::{ identity::Keypair, kad::{store::MemoryStore, Behaviour, Config, Mode, Record}, request_response::{ - Behaviour as RequestResponse, Config as RequestResponseConfig, ProtocolSupport, + Behaviour as RequestResponse, Config as Libp2pRequestResponseConfig, ProtocolSupport, }, swarm::SwarmEvent, Multiaddr, StreamProtocol, Swarm, SwarmBuilder, @@ -53,7 +52,7 @@ use tracing::{debug, error, info, info_span, instrument, warn, Instrument}; pub use self::{ config::{ GossipConfig, NetworkNodeConfig, NetworkNodeConfigBuilder, NetworkNodeConfigBuilderError, - DEFAULT_REPLICATION_FACTOR, + RequestResponseConfig, DEFAULT_REPLICATION_FACTOR, }, handle::{spawn_network_node, NetworkNodeHandle, NetworkNodeReceiver}, }; @@ -62,6 +61,7 @@ use super::{ bootstrap::{self, DHTBootstrapTask, InputEvent}, store::ValidatedStore, }, + cbor::Cbor, gen_transport, BoxedTransport, ClientRequest, NetworkDef, NetworkError, NetworkEvent, NetworkEventInternal, }; @@ -82,32 +82,29 @@ pub const ESTABLISHED_LIMIT_UNWR: u32 = 10; /// Network definition #[derive(custom_debug::Debug)] -pub struct NetworkNode { +pub struct NetworkNode { /// The keypair for the node keypair: Keypair, /// peer id of network node peer_id: PeerId, /// the swarm of networkbehaviours #[debug(skip)] - swarm: Swarm>, + swarm: Swarm>, /// the configuration parameters of the netework - config: NetworkNodeConfig, + config: NetworkNodeConfig, /// the listener id we are listening on, if it exists listener_id: Option, /// Handler for direct messages direct_message_state: DMBehaviour, /// Handler for DHT Events - dht_handler: DHTBehaviour, + dht_handler: DHTBehaviour, /// Channel to resend requests, set to Some when we call `spawn_listeners` resend_tx: Option>, /// Send to the bootstrap task to tell it to start a bootstrap bootstrap_tx: Option>, - - /// Phantom data to hold the key type - pd: PhantomData, } -impl NetworkNode { +impl NetworkNode { /// Returns number of peers this node is connected to pub fn num_connected(&self) -> usize { self.swarm.connected_peers().count() @@ -167,7 +164,7 @@ impl NetworkNode { /// * Generates a connection to the "broadcast" topic /// * Creates a swarm to manage peers and events #[instrument] - pub async fn new(config: NetworkNodeConfig) -> Result { + pub async fn new(config: NetworkNodeConfig) -> Result { // Generate a random `KeyPair` if one is not specified let keypair = config .keypair @@ -178,7 +175,7 @@ impl NetworkNode { let peer_id = PeerId::from(keypair.public()); // Generate the transport from the keypair, stake table, and auth message - let transport: BoxedTransport = gen_transport::( + let transport: BoxedTransport = gen_transport::( keypair.clone(), config.stake_table.clone(), config.auth_message.clone(), @@ -186,7 +183,7 @@ impl NetworkNode { .await?; // Generate the swarm - let mut swarm: Swarm> = { + let mut swarm: Swarm> = { // Use the `Blake3` hash of the message's contents as the ID let message_id_fn = |message: &GossipsubMessage| { let hash = blake3::hash(&message.data); @@ -269,10 +266,17 @@ impl NetworkNode { ); kadem.set_mode(Some(Mode::Server)); - let rrconfig = RequestResponseConfig::default(); + let rrconfig = Libp2pRequestResponseConfig::default(); + + // Create a new `cbor` codec with the given request and response sizes + let cbor = Cbor::new( + config.request_response_config.request_size_maximum, + config.request_response_config.response_size_maximum, + ); - let direct_message: libp2p::request_response::cbor::Behaviour, Vec> = - RequestResponse::new( + let direct_message: super::cbor::Behaviour, Vec> = + RequestResponse::with_codec( + cbor, [( StreamProtocol::new("/HotShot/direct_message/1.0"), ProtocolSupport::Full, @@ -329,7 +333,6 @@ impl NetworkNode { ), resend_tx: None, bootstrap_tx: None, - pd: PhantomData, }) } diff --git a/crates/libp2p-networking/src/network/node/config.rs b/crates/libp2p-networking/src/network/node/config.rs index c51fc281ea..2dfaaa3639 100644 --- a/crates/libp2p-networking/src/network/node/config.rs +++ b/crates/libp2p-networking/src/network/node/config.rs @@ -6,7 +6,7 @@ use std::{collections::HashSet, num::NonZeroUsize, time::Duration}; -use hotshot_types::traits::signature_key::SignatureKey; +use hotshot_types::traits::node_implementation::NodeType; use libp2p::{identity::Keypair, Multiaddr}; use libp2p_identity::PeerId; @@ -17,7 +17,7 @@ pub const DEFAULT_REPLICATION_FACTOR: Option = NonZeroUsize::new(1 /// describe the configuration of the network #[derive(Clone, Default, derive_builder::Builder, custom_debug::Debug)] -pub struct NetworkNodeConfig { +pub struct NetworkNodeConfig { /// The keypair for the node #[builder(setter(into, strip_option), default)] #[debug(skip)] @@ -33,6 +33,10 @@ pub struct NetworkNodeConfig { /// Configuration for `GossipSub` pub gossip_config: GossipConfig, + #[builder(default)] + /// Configuration for `RequestResponse` + pub request_response_config: RequestResponseConfig, + /// list of addresses to connect to at initialization pub to_connect_addrs: HashSet<(PeerId, Multiaddr)>, /// republication interval in DHT, must be much less than `ttl` @@ -45,7 +49,7 @@ pub struct NetworkNodeConfig { /// The stake table. Used for authenticating other nodes. If not supplied /// we will not check other nodes against the stake table #[builder(default)] - pub stake_table: Option>, + pub stake_table: Option, /// The signed authentication message sent to the remote peer /// If not supplied we will not send an authentication message during the handshake @@ -151,3 +155,21 @@ impl Default for GossipConfig { } } } + +/// Configuration for Libp2p's request-response +#[derive(Clone, Debug)] +pub struct RequestResponseConfig { + /// The maximum request size in bytes + pub request_size_maximum: u64, + /// The maximum response size in bytes + pub response_size_maximum: u64, +} + +impl Default for RequestResponseConfig { + fn default() -> Self { + Self { + request_size_maximum: 20 * 1024 * 1024, + response_size_maximum: 20 * 1024 * 1024, + } + } +} diff --git a/crates/libp2p-networking/src/network/node/handle.rs b/crates/libp2p-networking/src/network/node/handle.rs index 3ec68665f2..f9317e7aa1 100644 --- a/crates/libp2p-networking/src/network/node/handle.rs +++ b/crates/libp2p-networking/src/network/node/handle.rs @@ -4,13 +4,13 @@ // You should have received a copy of the MIT License // along with the HotShot repository. If not, see . -use std::{collections::HashSet, fmt::Debug, marker::PhantomData, time::Duration}; +use std::{collections::HashSet, fmt::Debug, time::Duration}; use async_compatibility_layer::{ art::{async_sleep, async_timeout}, channel::{Receiver, UnboundedReceiver, UnboundedSender}, }; -use hotshot_types::traits::{network::NetworkError, signature_key::SignatureKey}; +use hotshot_types::traits::{network::NetworkError, node_implementation::NodeType}; use libp2p::{request_response::ResponseChannel, Multiaddr}; use libp2p_identity::PeerId; use tracing::{debug, info, instrument}; @@ -24,9 +24,9 @@ use crate::network::{ /// - A reference to the state /// - Controls for the swarm #[derive(Debug, Clone)] -pub struct NetworkNodeHandle { +pub struct NetworkNodeHandle { /// network configuration - network_config: NetworkNodeConfig, + network_config: NetworkNodeConfig, /// send an action to the networkbehaviour send_network: UnboundedSender, @@ -39,9 +39,6 @@ pub struct NetworkNodeHandle { /// human readable id id: usize, - - /// Phantom data to hold the key type - pd: PhantomData, } /// internal network node receiver @@ -78,10 +75,10 @@ impl NetworkNodeReceiver { /// Spawn a network node task task and return the handle and the receiver for it /// # Errors /// Errors if spawning the task fails -pub async fn spawn_network_node( - config: NetworkNodeConfig, +pub async fn spawn_network_node( + config: NetworkNodeConfig, id: usize, -) -> Result<(NetworkNodeReceiver, NetworkNodeHandle), NetworkError> { +) -> Result<(NetworkNodeReceiver, NetworkNodeHandle), NetworkError> { let mut network = NetworkNode::new(config.clone()) .await .map_err(|e| NetworkError::ConfigError(format!("failed to create network node: {e}")))?; @@ -104,18 +101,17 @@ pub async fn spawn_network_node( recv_kill: None, }; - let handle = NetworkNodeHandle:: { + let handle = NetworkNodeHandle:: { network_config: config, send_network: send_chan, listen_addr, peer_id, id, - pd: PhantomData, }; Ok((receiver, handle)) } -impl NetworkNodeHandle { +impl NetworkNodeHandle { /// Cleanly shuts down a swarm node /// This is done by sending a message to /// the swarm itself to spin down @@ -217,7 +213,7 @@ impl NetworkNodeHandle { pub async fn put_record( &self, key: RecordKey, - value: RecordValue, + value: RecordValue, ) -> Result<(), NetworkError> { // Serialize the key let key = key.to_bytes(); @@ -263,7 +259,7 @@ impl NetworkNodeHandle { let result = r.await.map_err(|_| NetworkError::RequestCancelled)?; // Deserialize the record's value - let record: RecordValue = bincode::deserialize(&result) + let record: RecordValue = bincode::deserialize(&result) .map_err(|e| NetworkError::FailedToDeserialize(e.to_string()))?; Ok(record.value().to_vec()) @@ -292,7 +288,7 @@ impl NetworkNodeHandle { pub async fn put_record_timeout( &self, key: RecordKey, - value: RecordValue, + value: RecordValue, timeout: Duration, ) -> Result<(), NetworkError> { async_timeout(timeout, self.put_record(key, value)) @@ -467,7 +463,7 @@ impl NetworkNodeHandle { /// Return a reference to the network config #[must_use] - pub fn config(&self) -> &NetworkNodeConfig { + pub fn config(&self) -> &NetworkNodeConfig { &self.network_config } } diff --git a/crates/libp2p-networking/src/network/transport.rs b/crates/libp2p-networking/src/network/transport.rs index ea58db2001..969fed495d 100644 --- a/crates/libp2p-networking/src/network/transport.rs +++ b/crates/libp2p-networking/src/network/transport.rs @@ -1,7 +1,5 @@ use std::{ - collections::HashSet, future::Future, - hash::BuildHasher, io::{Error as IoError, ErrorKind as IoErrorKind}, pin::Pin, sync::Arc, @@ -11,7 +9,11 @@ use std::{ use anyhow::{ensure, Context, Result as AnyhowResult}; use async_compatibility_layer::art::async_timeout; use futures::{future::poll_fn, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use hotshot_types::traits::signature_key::SignatureKey; +use hotshot_types::traits::{ + election::Membership, + node_implementation::{ConsensusTime, NodeType}, + signature_key::SignatureKey, +}; use libp2p::{ core::{muxing::StreamMuxerExt, transport::TransportEvent, StreamMuxer}, identity::PeerId, @@ -34,14 +36,13 @@ const AUTH_HANDSHAKE_TIMEOUT: std::time::Duration = std::time::Duration::from_se /// by performing a handshake that checks if the remote peer is present in the /// stake table. #[pin_project] -pub struct StakeTableAuthentication -{ +pub struct StakeTableAuthentication { #[pin] /// The underlying transport we are wrapping pub inner: T, /// The stake table we check against to authenticate connections - pub stake_table: Arc>>, + pub stake_table: Arc>, /// A pre-signed message that we send to the remote peer for authentication pub auth_message: Arc>>, @@ -54,10 +55,14 @@ pub struct StakeTableAuthentication = Pin::Output, ::Error>> + Send>>; -impl StakeTableAuthentication { +impl StakeTableAuthentication { /// Create a new `StakeTableAuthentication` transport that wraps the given transport /// and authenticates connections against the stake table. - pub fn new(inner: T, stake_table: Option>, auth_message: Option>) -> Self { + pub fn new( + inner: T, + stake_table: Option, + auth_message: Option>, + ) -> Self { Self { inner, stake_table: Arc::from(stake_table), @@ -98,9 +103,9 @@ impl StakeTableAuthentica /// - The message is invalid /// - The peer is not in the stake table /// - The signature is invalid - pub async fn verify_peer_authentication( + pub async fn verify_peer_authentication( stream: &mut R, - stake_table: Arc>>, + stake_table: Arc>, required_peer_id: &PeerId, ) -> AnyhowResult<()> { // If we have a stake table, check if the remote peer is in it @@ -109,7 +114,7 @@ impl StakeTableAuthentica let message = read_length_delimited(stream, MAX_AUTH_MESSAGE_SIZE).await?; // Deserialize the authentication message - let auth_message: AuthMessage = bincode::deserialize(&message) + let auth_message: AuthMessage = bincode::deserialize(&message) .with_context(|| "Failed to deserialize auth message")?; // Verify the signature on the public keys @@ -127,7 +132,7 @@ impl StakeTableAuthentica } // Check if the public key is in the stake table - if !stake_table.contains(&public_key) { + if !stake_table.has_stake(&public_key, Types::Epoch::new(0)) { return Err(anyhow::anyhow!("Peer not in stake table")); } } @@ -142,7 +147,7 @@ impl StakeTableAuthentica fn gen_handshake> + Send + 'static>( original_future: F, outgoing: bool, - stake_table: Arc>>, + stake_table: Arc>, auth_message: Arc>>, ) -> UpgradeFuture where @@ -286,8 +291,8 @@ pub fn construct_auth_message( bincode::serialize(&auth_message).with_context(|| "Failed to serialize auth message") } -impl Transport - for StakeTableAuthentication +impl Transport + for StakeTableAuthentication where T::Dial: Future> + Send + 'static, T::ListenerUpgrade: Send + 'static, @@ -513,16 +518,22 @@ pub async fn write_length_delimited( #[cfg(test)] mod test { - use std::{collections::HashSet, sync::Arc}; - - use hotshot_types::{signature_key::BLSPubKey, traits::signature_key::SignatureKey}; + use std::sync::Arc; + + use hotshot_example_types::node_types::TestTypes; + use hotshot_types::{ + light_client::StateVerKey, + signature_key::BLSPubKey, + traits::{network::Topic, signature_key::SignatureKey}, + PeerConfig, + }; use libp2p::{core::transport::dummy::DummyTransport, quic::Connection}; use rand::Rng; use super::*; /// A mock type to help with readability - type MockStakeTableAuth = StakeTableAuthentication; + type MockStakeTableAuth = StakeTableAuthentication; // Helper macro for generating a new identity and authentication message macro_rules! new_identity { @@ -629,8 +640,15 @@ mod test { let mut stream = cursor_from!(auth_message); // Create a stake table with the key - let mut stake_table = std::collections::HashSet::new(); - stake_table.insert(keypair.0); + let peer_config = PeerConfig { + stake_table_entry: keypair.0.stake_table_entry(1), + state_ver_key: StateVerKey::default(), + }; + let stake_table = ::Membership::new( + vec![peer_config.clone()], + vec![peer_config], + Topic::Global, + ); // Verify the authentication message let result = MockStakeTableAuth::verify_peer_authentication( @@ -656,7 +674,7 @@ mod test { let mut stream = cursor_from!(auth_message); // Create an empty stake table - let stake_table: HashSet = std::collections::HashSet::new(); + let stake_table = ::Membership::new(vec![], vec![], Topic::Global); // Verify the authentication message let result = MockStakeTableAuth::verify_peer_authentication( @@ -689,8 +707,15 @@ mod test { let mut stream = cursor_from!(auth_message); // Create a stake table with the key - let mut stake_table: HashSet = std::collections::HashSet::new(); - stake_table.insert(keypair.0); + let peer_config = PeerConfig { + stake_table_entry: keypair.0.stake_table_entry(1), + state_ver_key: StateVerKey::default(), + }; + let stake_table = ::Membership::new( + vec![peer_config.clone()], + vec![peer_config], + Topic::Global, + ); // Check against the malicious peer ID let result = MockStakeTableAuth::verify_peer_authentication( diff --git a/crates/libp2p-networking/tests/common/mod.rs b/crates/libp2p-networking/tests/common/mod.rs index c4620baf9e..9e61786f5a 100644 --- a/crates/libp2p-networking/tests/common/mod.rs +++ b/crates/libp2p-networking/tests/common/mod.rs @@ -20,7 +20,7 @@ use async_compatibility_layer::{ logging::{setup_backtrace, setup_logging}, }; use futures::{future::join_all, Future, FutureExt}; -use hotshot_types::traits::{network::NetworkError, signature_key::SignatureKey}; +use hotshot_types::traits::{network::NetworkError, node_implementation::NodeType}; use libp2p::Multiaddr; use libp2p_identity::PeerId; use libp2p_networking::network::{ @@ -31,8 +31,8 @@ use thiserror::Error; use tracing::{instrument, warn}; #[derive(Clone, Debug)] -pub(crate) struct HandleWithState { - pub(crate) handle: Arc>, +pub(crate) struct HandleWithState { + pub(crate) handle: Arc>, pub(crate) state: Arc>, } @@ -41,13 +41,13 @@ pub(crate) struct HandleWithState( - handle_and_state: HandleWithState, +pub fn spawn_handler( + handle_and_state: HandleWithState, mut receiver: NetworkNodeReceiver, cb: F, ) -> impl Future where - F: Fn(NetworkEvent, HandleWithState) -> RET + Sync + Send + 'static, + F: Fn(NetworkEvent, HandleWithState) -> RET + Sync + Send + 'static, RET: Future> + Send + 'static, S: Debug + Default + Send + Clone + 'static, { @@ -97,14 +97,7 @@ where /// - Initialize network nodes /// - Kill network nodes /// - A test assertion fails -pub async fn test_bed< - S: 'static + Send + Default + Debug + Clone, - F, - FutF, - G, - FutG, - K: SignatureKey + 'static, ->( +pub async fn test_bed( run_test: F, client_handler: G, num_nodes: usize, @@ -112,8 +105,8 @@ pub async fn test_bed< ) where FutF: Future, FutG: Future> + 'static + Send + Sync, - F: FnOnce(Vec>, Duration) -> FutF, - G: Fn(NetworkEvent, HandleWithState) -> FutG + 'static + Send + Sync + Clone, + F: FnOnce(Vec>, Duration) -> FutF, + G: Fn(NetworkEvent, HandleWithState) -> FutG + 'static + Send + Sync + Clone, { setup_logging(); setup_backtrace(); @@ -121,7 +114,7 @@ pub async fn test_bed< let mut kill_switches = Vec::new(); // NOTE we want this to panic if we can't spin up the swarms. // that amounts to a failed test. - let handles_and_receivers = spin_up_swarms::(num_nodes, timeout).await.unwrap(); + let handles_and_receivers = spin_up_swarms::(num_nodes, timeout).await.unwrap(); let (handles, receivers): (Vec<_>, Vec<_>) = handles_and_receivers.into_iter().unzip(); let mut handler_futures = Vec::new(); @@ -149,9 +142,7 @@ pub async fn test_bed< } } -fn gen_peerid_map( - handles: &[Arc>], -) -> HashMap { +fn gen_peerid_map(handles: &[Arc>]) -> HashMap { let mut r_val = HashMap::new(); for handle in handles { r_val.insert(handle.peer_id(), handle.id()); @@ -161,7 +152,7 @@ fn gen_peerid_map( /// print the connections for each handle in `handles` /// useful for debugging -pub async fn print_connections(handles: &[Arc>]) { +pub async fn print_connections(handles: &[Arc>]) { let m = gen_peerid_map(handles); warn!("PRINTING CONNECTION STATES"); for handle in handles { @@ -183,10 +174,10 @@ pub async fn print_connections(handles: &[Arc( +pub async fn spin_up_swarms( num_of_nodes: usize, timeout_len: Duration, -) -> Result, NetworkNodeReceiver)>, TestError> { +) -> Result, NetworkNodeReceiver)>, TestError> { let mut handles = Vec::new(); let mut node_addrs = Vec::<(PeerId, Multiaddr)>::new(); let mut connecting_futs = Vec::new(); diff --git a/crates/libp2p-networking/tests/counter.rs b/crates/libp2p-networking/tests/counter.rs index 6e1214c547..f207ec4414 100644 --- a/crates/libp2p-networking/tests/counter.rs +++ b/crates/libp2p-networking/tests/counter.rs @@ -14,9 +14,9 @@ use async_lock::RwLock; #[cfg(async_executor_impl = "async-std")] use async_std::prelude::StreamExt; use common::{test_bed, HandleWithState, TestError}; -use hotshot_types::{ - signature_key::BLSPubKey, - traits::{network::NetworkError, signature_key::SignatureKey}, +use hotshot_example_types::node_types::TestTypes; +use hotshot_types::traits::{ + network::NetworkError, node_implementation::NodeType, signature_key::SignatureKey, }; use libp2p_networking::network::{ behaviours::dht::record::{Namespace, RecordKey, RecordValue}, @@ -63,10 +63,10 @@ pub enum CounterMessage { /// chooses one /// # Panics /// panics if handles is of length 0 -fn random_handle( - handles: &[HandleWithState], +fn random_handle( + handles: &[HandleWithState], rng: &mut dyn rand::RngCore, -) -> HandleWithState { +) -> HandleWithState { handles.iter().choose(rng).unwrap().clone() } @@ -74,9 +74,9 @@ fn random_handle( /// - updates state based on events received /// - replies to direct messages #[instrument] -pub async fn counter_handle_network_event( +pub async fn counter_handle_network_event( event: NetworkEvent, - handle: HandleWithState, + handle: HandleWithState, ) -> Result<(), NetworkError> { use CounterMessage::*; use NetworkEvent::*; @@ -166,9 +166,9 @@ pub async fn counter_handle_network_event( /// # Panics /// on error #[allow(clippy::similar_names)] -async fn run_request_response_increment<'a, K: SignatureKey + 'static>( - requester_handle: HandleWithState, - requestee_handle: HandleWithState, +async fn run_request_response_increment<'a, T: NodeType>( + requester_handle: HandleWithState, + requestee_handle: HandleWithState, timeout: Duration, ) -> Result<(), TestError> { async move { @@ -218,8 +218,8 @@ async fn run_request_response_increment<'a, K: SignatureKey + 'static>( /// broadcasts `msg` from a randomly chosen handle /// then asserts that all nodes match `new_state` -async fn run_gossip_round( - handles: &[HandleWithState], +async fn run_gossip_round( + handles: &[HandleWithState], msg: CounterMessage, new_state: CounterState, timeout_duration: Duration, @@ -293,8 +293,8 @@ async fn run_gossip_round( Ok(()) } -async fn run_intersperse_many_rounds( - handles: Vec>, +async fn run_intersperse_many_rounds( + handles: Vec>, timeout: Duration, ) { for i in 0..u32::try_from(NUM_ROUNDS).unwrap() { @@ -309,22 +309,22 @@ async fn run_intersperse_many_rounds( } } -async fn run_dht_many_rounds( - handles: Vec>, +async fn run_dht_many_rounds( + handles: Vec>, timeout: Duration, ) { run_dht_rounds(&handles, timeout, 0, NUM_ROUNDS).await; } -async fn run_dht_one_round( - handles: Vec>, +async fn run_dht_one_round( + handles: Vec>, timeout: Duration, ) { run_dht_rounds(&handles, timeout, 0, 1).await; } -async fn run_request_response_many_rounds( - handles: Vec>, +async fn run_request_response_many_rounds( + handles: Vec>, timeout: Duration, ) { for _i in 0..NUM_ROUNDS { @@ -338,8 +338,8 @@ async fn run_request_response_many_rounds( /// runs one round of request response /// # Panics /// on error -async fn run_request_response_one_round( - handles: Vec>, +async fn run_request_response_one_round( + handles: Vec>, timeout: Duration, ) { run_request_response_increment_all(&handles, timeout).await; @@ -351,8 +351,8 @@ async fn run_request_response_one_round( /// runs multiple rounds of gossip /// # Panics /// on error -async fn run_gossip_many_rounds( - handles: Vec>, +async fn run_gossip_many_rounds( + handles: Vec>, timeout: Duration, ) { run_gossip_rounds(&handles, NUM_ROUNDS, 0, timeout).await; @@ -361,8 +361,8 @@ async fn run_gossip_many_rounds( /// runs one round of gossip /// # Panics /// on error -async fn run_gossip_one_round( - handles: Vec>, +async fn run_gossip_one_round( + handles: Vec>, timeout: Duration, ) { run_gossip_rounds(&handles, 1, 0, timeout).await; @@ -371,8 +371,8 @@ async fn run_gossip_one_round( /// runs many rounds of dht /// # Panics /// on error -async fn run_dht_rounds( - handles: &[HandleWithState], +async fn run_dht_rounds( + handles: &[HandleWithState], timeout: Duration, _starting_val: usize, num_rounds: usize, @@ -384,7 +384,11 @@ async fn run_dht_rounds( // Create a random keypair let mut rng = StdRng::from_entropy(); - let (public_key, private_key) = K::generated_from_seed_indexed([1; 32], rng.gen::()); + let (public_key, private_key) = + ::generated_from_seed_indexed( + [1; 32], + rng.gen::(), + ); // Create a random value to sign let value = (0..DHT_KV_PADDING) @@ -422,8 +426,8 @@ async fn run_dht_rounds( } /// runs `num_rounds` of message broadcast, incrementing the state of all nodes each broadcast -async fn run_gossip_rounds( - handles: &[HandleWithState], +async fn run_gossip_rounds( + handles: &[HandleWithState], num_rounds: usize, starting_state: CounterState, timeout: Duration, @@ -448,8 +452,8 @@ async fn run_gossip_rounds( /// then has all other peers request its state /// and update their state to the recv'ed state #[allow(clippy::similar_names)] -async fn run_request_response_increment_all( - handles: &[HandleWithState], +async fn run_request_response_increment_all( + handles: &[HandleWithState], timeout: Duration, ) { let mut rng = rand::thread_rng(); @@ -524,7 +528,7 @@ async fn run_request_response_increment_all( #[instrument] async fn test_coverage_request_response_one_round() { Box::pin(test_bed( - run_request_response_one_round::, + run_request_response_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -538,7 +542,7 @@ async fn test_coverage_request_response_one_round() { #[instrument] async fn test_coverage_request_response_many_rounds() { Box::pin(test_bed( - run_request_response_many_rounds::, + run_request_response_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -552,7 +556,7 @@ async fn test_coverage_request_response_many_rounds() { #[instrument] async fn test_coverage_intersperse_many_rounds() { Box::pin(test_bed( - run_intersperse_many_rounds::, + run_intersperse_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -566,7 +570,7 @@ async fn test_coverage_intersperse_many_rounds() { #[instrument] async fn test_coverage_gossip_many_rounds() { Box::pin(test_bed( - run_gossip_many_rounds::, + run_gossip_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -580,7 +584,7 @@ async fn test_coverage_gossip_many_rounds() { #[instrument] async fn test_coverage_gossip_one_round() { Box::pin(test_bed( - run_gossip_one_round::, + run_gossip_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -595,7 +599,7 @@ async fn test_coverage_gossip_one_round() { #[ignore] async fn test_stress_request_response_one_round() { Box::pin(test_bed( - run_request_response_one_round::, + run_request_response_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -610,7 +614,7 @@ async fn test_stress_request_response_one_round() { #[ignore] async fn test_stress_request_response_many_rounds() { Box::pin(test_bed( - run_request_response_many_rounds::, + run_request_response_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -625,7 +629,7 @@ async fn test_stress_request_response_many_rounds() { #[ignore] async fn test_stress_intersperse_many_rounds() { Box::pin(test_bed( - run_intersperse_many_rounds::, + run_intersperse_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -640,7 +644,7 @@ async fn test_stress_intersperse_many_rounds() { #[ignore] async fn test_stress_gossip_many_rounds() { Box::pin(test_bed( - run_gossip_many_rounds::, + run_gossip_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -655,7 +659,7 @@ async fn test_stress_gossip_many_rounds() { #[ignore] async fn test_stress_gossip_one_round() { Box::pin(test_bed( - run_gossip_one_round::, + run_gossip_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -670,7 +674,7 @@ async fn test_stress_gossip_one_round() { #[ignore] async fn test_stress_dht_one_round() { Box::pin(test_bed( - run_dht_one_round::, + run_dht_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -685,7 +689,7 @@ async fn test_stress_dht_one_round() { #[ignore] async fn test_stress_dht_many_rounds() { Box::pin(test_bed( - run_dht_many_rounds::, + run_dht_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_STRESS, TIMEOUT_STRESS, @@ -699,7 +703,7 @@ async fn test_stress_dht_many_rounds() { #[instrument] async fn test_coverage_dht_one_round() { Box::pin(test_bed( - run_dht_one_round::, + run_dht_one_round::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, @@ -713,7 +717,7 @@ async fn test_coverage_dht_one_round() { #[instrument] async fn test_coverage_dht_many_rounds() { Box::pin(test_bed( - run_dht_many_rounds::, + run_dht_many_rounds::, counter_handle_network_event, TOTAL_NUM_PEERS_COVERAGE, TIMEOUT_COVERAGE, diff --git a/crates/task-impls/Cargo.toml b/crates/task-impls/Cargo.toml index c9a67c0c6a..e187a96a26 100644 --- a/crates/task-impls/Cargo.toml +++ b/crates/task-impls/Cargo.toml @@ -29,6 +29,7 @@ hotshot-types = { path = "../types" } hotshot-builder-api = { path = "../builder-api" } jf-signature = { workspace = true } jf-vid = { workspace = true } +lru.workspace = true rand = { workspace = true } serde = { workspace = true } sha2 = { workspace = true } diff --git a/crates/task-impls/src/builder.rs b/crates/task-impls/src/builder.rs index fba215217b..1762c91680 100644 --- a/crates/task-impls/src/builder.rs +++ b/crates/task-impls/src/builder.rs @@ -185,6 +185,30 @@ pub mod v0_1 { .await .map_err(Into::into) } + + /// Claim block and provide the number of nodes information to the builder for VID + /// computation. + /// + /// # Errors + /// - [`BuilderClientError::BlockNotFound`] if block isn't available + /// - [`BuilderClientError::Api`] if API isn't responding or responds incorrectly + pub async fn claim_block_with_num_nodes( + &self, + block_hash: BuilderCommitment, + view_number: u64, + sender: TYPES::SignatureKey, + signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, + num_nodes: usize, + ) -> Result, BuilderClientError> { + let encoded_signature: TaggedBase64 = signature.clone().into(); + self.client + .get(&format!( + "{LEGACY_BUILDER_MODULE}/claimblockwithnumnodes/{block_hash}/{view_number}/{sender}/{encoded_signature}/{num_nodes}" + )) + .send() + .await + .map_err(Into::into) + } } } diff --git a/crates/task-impls/src/consensus/handlers.rs b/crates/task-impls/src/consensus/handlers.rs index c1edf60bc7..02e65ba161 100644 --- a/crates/task-impls/src/consensus/handlers.rs +++ b/crates/task-impls/src/consensus/handlers.rs @@ -126,9 +126,18 @@ pub(crate) async fn handle_view_change< let old_view_number = task_state.cur_view; tracing::debug!("Updating view from {old_view_number:?} to {new_view_number:?}"); + if *old_view_number / 100 != *new_view_number / 100 { + tracing::info!("Progress: entered view {:>6}", *new_view_number); + } // Move this node to the next view task_state.cur_view = new_view_number; + task_state + .consensus + .write() + .await + .update_view(new_view_number)?; + // If we have a decided upgrade certificate, the protocol version may also have been upgraded. let decided_upgrade_certificate_read = task_state .upgrade_lock @@ -149,9 +158,7 @@ pub(crate) async fn handle_view_change< let timeout = task_state.timeout; let new_timeout_task = async_spawn({ let stream = sender.clone(); - // Nuance: We timeout on the view + 1 here because that means that we have - // not seen evidence to transition to this new view - let view_number = new_view_number + 1; + let view_number = new_view_number; async move { async_sleep(Duration::from_millis(timeout)).await; broadcast_event( @@ -223,7 +230,7 @@ pub(crate) async fn handle_timeout task_state: &mut ConsensusTaskState, ) -> Result<()> { ensure!( - task_state.cur_view < view_number, + task_state.cur_view <= view_number, "Timeout event is for an old view" ); @@ -255,7 +262,7 @@ pub(crate) async fn handle_timeout ) .await; - tracing::debug!( + tracing::error!( "We did not receive evidence for view {} in time, sending timeout vote for that view!", *view_number ); diff --git a/crates/task-impls/src/consensus/mod.rs b/crates/task-impls/src/consensus/mod.rs index edff8f6078..fad629079b 100644 --- a/crates/task-impls/src/consensus/mod.rs +++ b/crates/task-impls/src/consensus/mod.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use async_broadcast::{Receiver, Sender}; +use async_compatibility_layer::art::async_spawn; use async_lock::RwLock; #[cfg(async_executor_impl = "async-std")] use async_std::task::JoinHandle; @@ -31,7 +32,7 @@ use utils::anytrace::Result; use self::handlers::{ handle_quorum_vote_recv, handle_timeout, handle_timeout_vote_recv, handle_view_change, }; -use crate::{events::HotShotEvent, vote_collection::VoteCollectorsMap}; +use crate::{events::HotShotEvent, helpers::cancel_task, vote_collection::VoteCollectorsMap}; /// Event handlers for use in the `handle` method. mod handlers; @@ -170,5 +171,12 @@ impl, V: Versions> TaskState } /// Joins all subtasks. - async fn cancel_subtasks(&mut self) {} + async fn cancel_subtasks(&mut self) { + // Cancel the old timeout task + cancel_task(std::mem::replace( + &mut self.timeout_task, + async_spawn(async {}), + )) + .await; + } } diff --git a/crates/task-impls/src/da.rs b/crates/task-impls/src/da.rs index bada6f4ddf..d96efcfb3d 100644 --- a/crates/task-impls/src/da.rs +++ b/crates/task-impls/src/da.rs @@ -7,13 +7,14 @@ use std::{marker::PhantomData, sync::Arc}; use async_broadcast::{Receiver, Sender}; +use async_compatibility_layer::art::async_spawn; use async_lock::RwLock; #[cfg(async_executor_impl = "async-std")] use async_std::task::spawn_blocking; use async_trait::async_trait; use hotshot_task::task::TaskState; use hotshot_types::{ - consensus::{OuterConsensus, View}, + consensus::{Consensus, OuterConsensus, View}, data::{DaProposal, PackedBundle}, event::{Event, EventType}, message::{Proposal, UpgradeLock}, @@ -22,6 +23,7 @@ use hotshot_types::{ traits::{ block_contents::vid_commitment, election::Membership, + network::ConnectedNetwork, node_implementation::{NodeImplementation, NodeType, Versions}, signature_key::SignatureKey, storage::Storage, @@ -181,21 +183,19 @@ impl, V: Versions> DaTaskState, V: Versions> DaTaskState { tracing::debug!("DA vote recv, Main Task {:?}", vote.view_number()); @@ -271,15 +307,6 @@ impl, V: Versions> DaTaskState { let PackedBundle:: { diff --git a/crates/task-impls/src/harness.rs b/crates/task-impls/src/harness.rs index 16e8a273b8..63d864392b 100644 --- a/crates/task-impls/src/harness.rs +++ b/crates/task-impls/src/harness.rs @@ -27,7 +27,7 @@ pub struct TestHarnessState { /// # Arguments /// * `event_stream` - if given, will be used to register the task builder. /// * `allow_extra_output` - whether to allow an extra output after we've seen all expected -/// outputs. Should be `false` in most cases. +/// outputs. Should be `false` in most cases. /// /// # Panics /// Panics if any state the test expects is not set. Panicking causes a test failure @@ -82,7 +82,7 @@ pub async fn run_harness> + Send /// /// # Arguments /// * `allow_extra_output` - whether to allow an extra output after we've seen all expected -/// outputs. Should be `false` in most cases. +/// outputs. Should be `false` in most cases. /// /// # Panics /// Will panic to fail the test when it receives and unexpected event diff --git a/crates/task-impls/src/helpers.rs b/crates/task-impls/src/helpers.rs index 28d59b2038..26aca6543f 100644 --- a/crates/task-impls/src/helpers.rs +++ b/crates/task-impls/src/helpers.rs @@ -4,22 +4,20 @@ // You should have received a copy of the MIT License // along with the HotShot repository. If not, see . -use core::time::Duration; use std::{ collections::{HashMap, HashSet}, sync::Arc, }; use async_broadcast::{InactiveReceiver, Receiver, SendError, Sender}; -use async_compatibility_layer::art::{async_sleep, async_spawn, async_timeout}; +use async_compatibility_layer::art::async_timeout; use async_lock::RwLock; #[cfg(async_executor_impl = "async-std")] use async_std::task::JoinHandle; -use chrono::Utc; use committable::{Commitment, Committable}; use hotshot_task::dependency::{Dependency, EventDependency}; use hotshot_types::{ - consensus::{ConsensusUpgradableReadLockGuard, OuterConsensus}, + consensus::OuterConsensus, data::{Leaf, QuorumProposal, ViewChangeEvidence}, event::{Event, EventType, LeafInfo}, message::{Proposal, UpgradeLock}, @@ -28,7 +26,7 @@ use hotshot_types::{ traits::{ block_contents::BlockHeader, election::Membership, - node_implementation::{ConsensusTime, NodeImplementation, NodeType, Versions}, + node_implementation::{NodeImplementation, NodeType, Versions}, signature_key::SignatureKey, BlockPayload, ValidatedState, }, @@ -40,10 +38,7 @@ use tokio::task::JoinHandle; use tracing::instrument; use utils::anytrace::*; -use crate::{ - events::HotShotEvent, quorum_proposal_recv::QuorumProposalRecvTaskState, - request::REQUEST_TIMEOUT, -}; +use crate::{events::HotShotEvent, quorum_proposal_recv::ValidationInfo, request::REQUEST_TIMEOUT}; /// Trigger a request to the network for a proposal for a view and wait for the response or timeout. #[instrument(skip_all)] @@ -57,7 +52,7 @@ pub(crate) async fn fetch_proposal( sender_public_key: TYPES::SignatureKey, sender_private_key: ::PrivateKey, upgrade_lock: &UpgradeLock, -) -> Result> { +) -> Result<(Leaf, View)> { // We need to be able to sign this request before submitting it to the network. Compute the // payload first. let signed_proposal_request = ProposalRequestPayload { @@ -123,7 +118,6 @@ pub(crate) async fn fetch_proposal( return None; } } - proposal }) .await @@ -162,11 +156,11 @@ pub(crate) async fn fetch_proposal( .await; broadcast_event( - HotShotEvent::ValidatedStateUpdated(view_number, view).into(), + HotShotEvent::ValidatedStateUpdated(view_number, view.clone()).into(), &event_sender, ) .await; - Ok(leaf) + Ok((leaf, view)) } /// Helper type to give names and to the output values of the leaf chain traversal operation. @@ -218,9 +212,9 @@ impl Default for LeafChainTraversalOutcome { /// [HotStuff](https://arxiv.org/pdf/1803.05069) section 5: /// /// > When a node b* carries a QC that refers to a direct parent, i.e., b*.justify.node = b*.parent, -/// we say that it forms a One-Chain. Denote by b'' = b*.justify.node. Node b* forms a Two-Chain, -/// if in addition to forming a One-Chain, b''.justify.node = b''.parent. -/// It forms a Three-Chain, if b'' forms a Two-Chain. +/// > we say that it forms a One-Chain. Denote by b'' = b*.justify.node. Node b* forms a Two-Chain, +/// > if in addition to forming a One-Chain, b''.justify.node = b''.parent. +/// > It forms a Three-Chain, if b'' forms a Two-Chain. /// /// We follow this exact logic to determine if we are able to reach a commit and a decide. A commit /// is reached when we have a two chain, and a decide is reached when we have a three chain. @@ -371,6 +365,7 @@ pub(crate) async fn parent_leaf_and_state( private_key: ::PrivateKey, consensus: OuterConsensus, upgrade_lock: &UpgradeLock, + parent_view_number: TYPES::View, ) -> Result<(Leaf, Arc<::ValidatedState>)> { let consensus_reader = consensus.read().await; let cur_epoch = consensus_reader.cur_epoch(); @@ -381,7 +376,6 @@ pub(crate) async fn parent_leaf_and_state( next_proposal_view_number ) ); - let parent_view_number = consensus_reader.high_qc().view_number(); let vsm_contains_parent_view = consensus_reader .validated_state_map() .contains_key(&parent_view_number); @@ -403,7 +397,7 @@ pub(crate) async fn parent_leaf_and_state( } let consensus_reader = consensus.read().await; - let parent_view_number = consensus_reader.high_qc().view_number(); + //let parent_view_number = consensus_reader.high_qc().view_number(); let parent_view = consensus_reader.validated_state_map().get(&parent_view_number).context( debug!("Couldn't find parent view in state map, waiting for replica to see proposal; parent_view_number: {}", *parent_view_number) )?; @@ -436,7 +430,7 @@ pub(crate) async fn parent_leaf_and_state( /// # Errors /// If any validation or state update fails. #[allow(clippy::too_many_lines)] -#[instrument(skip_all, fields(id = task_state.id, view = *proposal.data.view_number()))] +#[instrument(skip_all, fields(id = validation_info.id, view = *proposal.data.view_number()))] pub async fn validate_proposal_safety_and_liveness< TYPES: NodeType, I: NodeImplementation, @@ -444,7 +438,7 @@ pub async fn validate_proposal_safety_and_liveness< >( proposal: Proposal>, parent_leaf: Leaf, - task_state: &mut QuorumProposalRecvTaskState, + validation_info: &ValidationInfo, event_stream: Sender>>, sender: TYPES::SignatureKey, ) -> Result<()> { @@ -452,7 +446,8 @@ pub async fn validate_proposal_safety_and_liveness< let proposed_leaf = Leaf::from_quorum_proposal(&proposal.data); ensure!( - proposed_leaf.parent_commitment() == parent_leaf.commit(&task_state.upgrade_lock).await, + proposed_leaf.parent_commitment() + == parent_leaf.commit(&validation_info.upgrade_lock).await, "Proposed leaf does not extend the parent leaf." ); @@ -461,19 +456,19 @@ pub async fn validate_proposal_safety_and_liveness< ); let view = View { view_inner: ViewInner::Leaf { - leaf: proposed_leaf.commit(&task_state.upgrade_lock).await, + leaf: proposed_leaf.commit(&validation_info.upgrade_lock).await, state, delta: None, // May be updated to `Some` in the vote task. }, }; { - let mut consensus_writer = task_state.consensus.write().await; + let mut consensus_writer = validation_info.consensus.write().await; if let Err(e) = consensus_writer.update_validated_state_map(view_number, view.clone()) { tracing::trace!("{e:?}"); } consensus_writer - .update_saved_leaves(proposed_leaf.clone(), &task_state.upgrade_lock) + .update_saved_leaves(proposed_leaf.clone(), &validation_info.upgrade_lock) .await; // Update our internal storage of the proposal. The proposal is valid, so @@ -490,12 +485,12 @@ pub async fn validate_proposal_safety_and_liveness< ) .await; - let cur_epoch = task_state.cur_epoch; + let cur_epoch = validation_info.cur_epoch; UpgradeCertificate::validate( &proposal.data.upgrade_certificate, - &task_state.quorum_membership, + &validation_info.quorum_membership, cur_epoch, - &task_state.upgrade_lock, + &validation_info.upgrade_lock, ) .await?; @@ -503,7 +498,7 @@ pub async fn validate_proposal_safety_and_liveness< proposed_leaf .extends_upgrade( &parent_leaf, - &task_state.upgrade_lock.decided_upgrade_certificate, + &validation_info.upgrade_lock.decided_upgrade_certificate, ) .await?; @@ -513,7 +508,7 @@ pub async fn validate_proposal_safety_and_liveness< // Liveness check. { - let consensus_reader = task_state.consensus.read().await; + let consensus_reader = validation_info.consensus.read().await; let liveness_check = justify_qc.view_number() > consensus_reader.locked_view(); // Safety check. @@ -537,7 +532,7 @@ pub async fn validate_proposal_safety_and_liveness< view_number, event: EventType::Error { error: Arc::new(e) }, }, - &task_state.output_event_stream, + &validation_info.output_event_stream, ) .await; } @@ -555,7 +550,7 @@ pub async fn validate_proposal_safety_and_liveness< sender, }, }, - &task_state.output_event_stream, + &validation_info.output_event_stream, ) .await; @@ -578,17 +573,17 @@ pub async fn validate_proposal_safety_and_liveness< /// /// # Errors /// If any validation or view number check fails. -pub async fn validate_proposal_view_and_certs< +pub(crate) async fn validate_proposal_view_and_certs< TYPES: NodeType, I: NodeImplementation, V: Versions, >( proposal: &Proposal>, - task_state: &mut QuorumProposalRecvTaskState, + validation_info: &ValidationInfo, ) -> Result<()> { let view_number = proposal.data.view_number(); ensure!( - view_number >= task_state.cur_view, + view_number >= validation_info.consensus.read().await.cur_view(), "Proposal is from an older view {:?}", proposal.data.clone() ); @@ -596,9 +591,9 @@ pub async fn validate_proposal_view_and_certs< // Validate the proposal's signature. This should also catch if the leaf_commitment does not equal our calculated parent commitment proposal .validate_signature( - &task_state.quorum_membership, - task_state.cur_epoch, - &task_state.upgrade_lock, + &validation_info.quorum_membership, + validation_info.cur_epoch, + &validation_info.upgrade_lock, ) .await?; @@ -620,9 +615,9 @@ pub async fn validate_proposal_view_and_certs< ensure!( timeout_cert .is_valid_cert( - task_state.timeout_membership.as_ref(), - task_state.cur_epoch, - &task_state.upgrade_lock + validation_info.quorum_membership.as_ref(), + validation_info.cur_epoch, + &validation_info.upgrade_lock ) .await, "Timeout certificate for view {} was invalid", @@ -641,9 +636,9 @@ pub async fn validate_proposal_view_and_certs< ensure!( view_sync_cert .is_valid_cert( - task_state.quorum_membership.as_ref(), - task_state.cur_epoch, - &task_state.upgrade_lock + validation_info.quorum_membership.as_ref(), + validation_info.cur_epoch, + &validation_info.upgrade_lock ) .await, "Invalid view sync finalize cert provided" @@ -656,121 +651,15 @@ pub async fn validate_proposal_view_and_certs< // Note that we don't do anything with the certificate directly if this passes; it eventually gets stored as part of the leaf if nothing goes wrong. UpgradeCertificate::validate( &proposal.data.upgrade_certificate, - &task_state.quorum_membership, - task_state.cur_epoch, - &task_state.upgrade_lock, + &validation_info.quorum_membership, + validation_info.cur_epoch, + &validation_info.upgrade_lock, ) .await?; Ok(()) } -/// Update the view if it actually changed, takes a mutable reference to the `cur_view` and the -/// `timeout_task` which are updated during the operation of the function. -/// -/// # Errors -/// Returns an [`utils::anytrace::Error`] when the new view is not greater than the current view. -pub(crate) async fn update_view, V: Versions>( - new_view: TYPES::View, - event_stream: &Sender>>, - task_state: &mut QuorumProposalRecvTaskState, -) -> Result<()> { - ensure!( - new_view > task_state.cur_view, - "New view is not greater than our current view" - ); - - let is_old_view_leader = task_state - .quorum_membership - .leader(task_state.cur_view, task_state.cur_epoch)? - == task_state.public_key; - let old_view = task_state.cur_view; - - tracing::debug!("Updating view from {} to {}", *old_view, *new_view); - - if *old_view / 100 != *new_view / 100 { - tracing::info!("Progress: entered view {:>6}", *new_view); - } - - task_state.cur_view = new_view; - - // The next view is just the current view + 1 - let next_view = task_state.cur_view + 1; - - futures::join! { - broadcast_event(Arc::new(HotShotEvent::ViewChange(new_view)), event_stream), - broadcast_event( - Event { - view_number: old_view, - event: EventType::ViewFinished { - view_number: old_view, - }, - }, - &task_state.output_event_stream, - ) - }; - - // Spawn a timeout task if we did actually update view - let new_timeout_task = async_spawn({ - let stream = event_stream.clone(); - // Nuance: We timeout on the view + 1 here because that means that we have - // not seen evidence to transition to this new view - let view_number = next_view; - let timeout = Duration::from_millis(task_state.timeout); - async move { - async_sleep(timeout).await; - broadcast_event( - Arc::new(HotShotEvent::Timeout(TYPES::View::new(*view_number))), - &stream, - ) - .await; - } - }); - - // cancel the old timeout task - cancel_task(std::mem::replace( - &mut task_state.timeout_task, - new_timeout_task, - )) - .await; - - let consensus_reader = task_state.consensus.upgradable_read().await; - consensus_reader - .metrics - .current_view - .set(usize::try_from(task_state.cur_view.u64()).unwrap()); - let new_view_time = Utc::now().timestamp(); - if is_old_view_leader { - #[allow(clippy::cast_precision_loss)] - consensus_reader - .metrics - .view_duration_as_leader - .add_point((new_view_time - task_state.cur_view_time) as f64); - } - task_state.cur_view_time = new_view_time; - - // Do the comparison before the subtraction to avoid potential overflow, since - // `last_decided_view` may be greater than `cur_view` if the node is catching up. - if usize::try_from(task_state.cur_view.u64()).unwrap() - > usize::try_from(consensus_reader.last_decided_view().u64()).unwrap() - { - consensus_reader - .metrics - .number_of_views_since_last_decide - .set( - usize::try_from(task_state.cur_view.u64()).unwrap() - - usize::try_from(consensus_reader.last_decided_view().u64()).unwrap(), - ); - } - let mut consensus_writer = ConsensusUpgradableReadLockGuard::upgrade(consensus_reader).await; - if let Err(e) = consensus_writer.update_view(new_view) { - tracing::trace!("{e:?}"); - } - tracing::trace!("View updated successfully"); - - Ok(()) -} - /// Cancel a task pub async fn cancel_task(task: JoinHandle) { #[cfg(async_executor_impl = "async-std")] diff --git a/crates/task-impls/src/network.rs b/crates/task-impls/src/network.rs index f9cbcff865..7fffadfb11 100644 --- a/crates/task-impls/src/network.rs +++ b/crates/task-impls/src/network.rs @@ -4,12 +4,22 @@ // You should have received a copy of the MIT License // along with the HotShot repository. If not, see . -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; +use crate::{ + events::{HotShotEvent, HotShotTaskCompleted}, + helpers::{broadcast_event, cancel_task}, +}; use async_broadcast::{Receiver, Sender}; use async_compatibility_layer::art::async_spawn; use async_lock::RwLock; +#[cfg(async_executor_impl = "async-std")] +use async_std::task::JoinHandle; use async_trait::async_trait; +use futures::future::join_all; use hotshot_task::task::TaskState; use hotshot_types::{ consensus::Consensus, @@ -30,14 +40,11 @@ use hotshot_types::{ }, vote::{HasViewNumber, Vote}, }; +#[cfg(async_executor_impl = "tokio")] +use tokio::task::JoinHandle; use tracing::instrument; use utils::anytrace::*; -use crate::{ - events::{HotShotEvent, HotShotTaskCompleted}, - helpers::broadcast_event, -}; - /// the network message task state #[derive(Clone)] pub struct NetworkMessageTaskState { @@ -203,6 +210,8 @@ pub struct NetworkEventTaskState< pub consensus: Arc>>, /// Lock for a decided upgrade pub upgrade_lock: UpgradeLock, + /// map view number to transmit tasks + pub transmit_tasks: BTreeMap>>, } #[async_trait] @@ -331,6 +340,18 @@ impl< } } + /// Cancel all tasks for previous views + pub fn cancel_tasks(&mut self, view: TYPES::View) { + let keep = self.transmit_tasks.split_off(&view); + let mut cancel = Vec::new(); + while let Some((_, tasks)) = self.transmit_tasks.pop_first() { + let mut to_cancel = tasks.into_iter().map(cancel_task).collect(); + cancel.append(&mut to_cancel); + } + self.transmit_tasks = keep; + async_spawn(async move { join_all(cancel).await }); + } + /// Parses a `HotShotEvent` and returns a tuple of: (sender's public key, `MessageKind`, `TransmitType`) /// which will be used to create a message and transmit on the wire. /// Returns `None` if the parsing result should not be sent on the wire. @@ -584,13 +605,14 @@ impl< } HotShotEvent::ViewChange(view) => { self.view = view; - self.network - .update_view::( - self.view.u64(), - self.epoch.u64(), - &self.quorum_membership, - ) - .await; + self.cancel_tasks(view); + let net = Arc::clone(&self.network); + let epoch = self.epoch.u64(); + let mem = self.quorum_membership.clone(); + async_spawn(async move { + net.update_view::(view.saturating_sub(1), epoch, &mem) + .await; + }); None } HotShotEvent::VidRequestSend(req, sender, to) => Some(( @@ -614,7 +636,7 @@ impl< /// Creates a network message and spawns a task that transmits it on the wire. fn spawn_transmit_task( - &self, + &mut self, message_kind: MessageKind, maybe_action: Option, transmit: TransmitType, @@ -640,7 +662,7 @@ impl< let storage = Arc::clone(&self.storage); let consensus = Arc::clone(&self.consensus); let upgrade_lock = self.upgrade_lock.clone(); - async_spawn(async move { + let handle = async_spawn(async move { if NetworkEventTaskState::::maybe_record_action( maybe_action, Arc::clone(&storage), @@ -694,6 +716,10 @@ impl< Err(e) => tracing::warn!("Failed to send message task: {:?}", e), } }); + self.transmit_tasks + .entry(view_number) + .or_default() + .push(handle); } } diff --git a/crates/task-impls/src/quorum_proposal/handlers.rs b/crates/task-impls/src/quorum_proposal/handlers.rs index ffad0f5d1e..1add742a7a 100644 --- a/crates/task-impls/src/quorum_proposal/handlers.rs +++ b/crates/task-impls/src/quorum_proposal/handlers.rs @@ -9,13 +9,10 @@ use std::{marker::PhantomData, sync::Arc}; +use anyhow::{ensure, Context, Result}; use async_broadcast::{InactiveReceiver, Sender}; -use async_compatibility_layer::art::async_spawn; use async_lock::RwLock; -use hotshot_task::{ - dependency::{Dependency, EventDependency}, - dependency_task::HandleDepOutput, -}; +use hotshot_task::dependency_task::HandleDepOutput; use hotshot_types::{ consensus::{CommitmentAndMetadata, OuterConsensus}, data::{Leaf, QuorumProposal, VidDisperse, ViewChangeEvidence}, @@ -24,6 +21,7 @@ use hotshot_types::{ traits::{ block_contents::BlockHeader, node_implementation::NodeType, signature_key::SignatureKey, }, + vote::HasViewNumber, }; use tracing::instrument; use utils::anytrace::*; @@ -31,7 +29,7 @@ use vbs::version::StaticVersionType; use crate::{ events::HotShotEvent, - helpers::{broadcast_event, fetch_proposal, parent_leaf_and_state}, + helpers::{broadcast_event, parent_leaf_and_state}, quorum_proposal::{UpgradeLock, Versions}, }; @@ -105,7 +103,7 @@ impl ProposalDependencyHandle { /// Publishes a proposal given the [`CommitmentAndMetadata`], [`VidDisperse`] /// and high qc [`hotshot_types::simple_certificate::QuorumCertificate`], /// with optional [`ViewChangeEvidence`]. - #[instrument(skip_all, target = "ProposalDependencyHandle", fields(id = self.id, view_number = *self.view_number, latest_proposed_view = *self.latest_proposed_view))] + #[instrument(skip_all, fields(id = self.id, view_number = *self.view_number, latest_proposed_view = *self.latest_proposed_view))] async fn publish_proposal( &self, commitment_and_metadata: CommitmentAndMetadata, @@ -113,6 +111,7 @@ impl ProposalDependencyHandle { view_change_evidence: Option>, formed_upgrade_certificate: Option>, decided_upgrade_certificate: Arc>>>, + parent_view_number: TYPES::View, ) -> Result<()> { let (parent_leaf, state) = parent_leaf_and_state( self.view_number, @@ -123,6 +122,7 @@ impl ProposalDependencyHandle { self.private_key.clone(), OuterConsensus::new(Arc::clone(&self.consensus.inner_consensus)), &self.upgrade_lock, + parent_view_number, ) .await?; @@ -166,14 +166,29 @@ impl ProposalDependencyHandle { let version = self.upgrade_lock.version(self.view_number).await?; - let block_header = if version < V::Marketplace::VERSION { + let high_qc = self.consensus.read().await.high_qc().clone(); + + let builder_commitment = commitment_and_metadata.builder_commitment.clone(); + let metadata = commitment_and_metadata.metadata.clone(); + + let block_header = if version >= V::Epochs::VERSION + && self.consensus.read().await.is_high_qc_forming_eqc() + { + tracing::info!("Reached end of epoch. Proposing the same block again to form an eQC."); + let block_header = parent_leaf.block_header().clone(); + tracing::debug!( + "Proposing block no. {} to form the eQC.", + block_header.block_number() + ); + block_header + } else if version < V::Marketplace::VERSION { TYPES::BlockHeader::new_legacy( state.as_ref(), self.instance_state.as_ref(), &parent_leaf, commitment_and_metadata.commitment, - commitment_and_metadata.builder_commitment, - commitment_and_metadata.metadata, + builder_commitment, + metadata, commitment_and_metadata.fees.first().clone(), vid_share.data.common.clone(), version, @@ -202,7 +217,7 @@ impl ProposalDependencyHandle { let proposal = QuorumProposal { block_header, view_number: self.view_number, - justify_qc: self.consensus.read().await.high_qc().clone(), + justify_qc: high_qc, upgrade_certificate, proposal_certificate, }; @@ -242,61 +257,17 @@ impl ProposalDependencyHandle { Ok(()) } } + impl HandleDepOutput for ProposalDependencyHandle { type Output = Vec>>>>; #[allow(clippy::no_effect_underscore_binding, clippy::too_many_lines)] async fn handle_dep_result(self, res: Self::Output) { - let high_qc_view_number = self.consensus.read().await.high_qc().view_number; - let event_receiver = self.receiver.activate_cloned(); - if !self - .consensus - .read() - .await - .validated_state_map() - .contains_key(&high_qc_view_number) - { - // The proposal for the high qc view is missing, try to get it asynchronously - let membership = Arc::clone(&self.quorum_membership); - let event_sender = self.sender.clone(); - let sender_public_key = self.public_key.clone(); - let sender_private_key = self.private_key.clone(); - let consensus = OuterConsensus::new(Arc::clone(&self.consensus.inner_consensus)); - let upgrade_lock = self.upgrade_lock.clone(); - let rx = event_receiver.clone(); - async_spawn(async move { - fetch_proposal( - high_qc_view_number, - event_sender, - rx, - membership, - consensus, - sender_public_key, - sender_private_key, - &upgrade_lock, - ) - .await - }); - // Block on receiving the event from the event stream. - EventDependency::new( - event_receiver, - Box::new(move |event| { - let event = event.as_ref(); - if let HotShotEvent::ValidatedStateUpdated(view_number, _) = event { - *view_number == high_qc_view_number - } else { - false - } - }), - ) - .completed() - .await; - } - let mut commit_and_metadata: Option> = None; let mut timeout_certificate = None; let mut view_sync_finalize_cert = None; let mut vid_share = None; + let mut parent_view_number = None; for event in res.iter().flatten().flatten() { match event.as_ref() { HotShotEvent::SendPayloadCommitmentAndMetadata( @@ -320,8 +291,9 @@ impl HandleDepOutput for ProposalDependencyHandle< either::Right(timeout) => { timeout_certificate = Some(timeout.clone()); } - either::Left(_) => { + either::Left(qc) => { // Handled by the UpdateHighQc event. + parent_view_number = Some(qc.view_number()); } }, HotShotEvent::ViewSyncFinalizeCertificate2Recv(cert) => { @@ -334,6 +306,9 @@ impl HandleDepOutput for ProposalDependencyHandle< } } + let parent_view_number = + parent_view_number.unwrap_or(self.consensus.read().await.high_qc().view_number()); + if commit_and_metadata.is_none() { tracing::error!( "Somehow completed the proposal dependency task without a commitment and metadata" @@ -359,6 +334,7 @@ impl HandleDepOutput for ProposalDependencyHandle< proposal_cert, self.formed_upgrade_certificate.clone(), Arc::clone(&self.upgrade_lock.decided_upgrade_certificate), + parent_view_number, ) .await { diff --git a/crates/task-impls/src/quorum_proposal/mod.rs b/crates/task-impls/src/quorum_proposal/mod.rs index 5d33e16664..1ac07e6abc 100644 --- a/crates/task-impls/src/quorum_proposal/mod.rs +++ b/crates/task-impls/src/quorum_proposal/mod.rs @@ -95,6 +95,9 @@ pub struct QuorumProposalTaskState /// Lock for a decided upgrade pub upgrade_lock: UpgradeLock, + + /// Number of blocks in an epoch, zero means there are no epochs + pub epoch_height: u64, } impl, V: Versions> @@ -375,7 +378,6 @@ impl, V: Versions> "Upgrade certificate received for view {}!", *cert.view_number ); - // Update our current upgrade_cert as long as we still have a chance of reaching a decide on it in time. if cert.data.decide_by >= self.latest_proposed_view + 3 { tracing::debug!("Updating current formed_upgrade_certificate"); @@ -387,7 +389,6 @@ impl, V: Versions> either::Right(timeout_cert) => { let view_number = timeout_cert.view_number + 1; let epoch_number = self.consensus.read().await.cur_epoch(); - self.create_dependency_task_if_new( view_number, epoch_number, @@ -458,7 +459,6 @@ impl, V: Versions> } HotShotEvent::QuorumProposalPreliminarilyValidated(proposal) => { let view_number = proposal.data.view_number(); - // All nodes get the latest proposed view as a proxy of `cur_view` of old. if !self.update_latest_proposed_view(view_number).await { tracing::trace!("Failed to update latest proposed view"); @@ -484,7 +484,6 @@ impl, V: Versions> HotShotEvent::VidDisperseSend(vid_share, _) => { let view_number = vid_share.data.view_number(); let epoch_number = self.consensus.read().await.cur_epoch(); - self.create_dependency_task_if_new( view_number, epoch_number, diff --git a/crates/task-impls/src/quorum_proposal_recv/handlers.rs b/crates/task-impls/src/quorum_proposal_recv/handlers.rs index 488854e95d..d1fbac8a30 100644 --- a/crates/task-impls/src/quorum_proposal_recv/handlers.rs +++ b/crates/task-impls/src/quorum_proposal_recv/handlers.rs @@ -30,11 +30,11 @@ use hotshot_types::{ use tracing::instrument; use utils::anytrace::*; -use super::QuorumProposalRecvTaskState; +use super::{QuorumProposalRecvTaskState, ValidationInfo}; use crate::{ events::HotShotEvent, helpers::{ - broadcast_event, fetch_proposal, update_view, validate_proposal_safety_and_liveness, + broadcast_event, fetch_proposal, validate_proposal_safety_and_liveness, validate_proposal_view_and_certs, }, quorum_proposal_recv::{UpgradeLock, Versions}, @@ -45,10 +45,10 @@ use crate::{ async fn validate_proposal_liveness, V: Versions>( proposal: &Proposal>, event_sender: &Sender>>, - task_state: &mut QuorumProposalRecvTaskState, + validation_info: &ValidationInfo, ) -> Result<()> { let view_number = proposal.data.view_number(); - let mut consensus_writer = task_state.consensus.write().await; + let mut consensus_writer = validation_info.consensus.write().await; let leaf = Leaf::from_quorum_proposal(&proposal.data); @@ -57,7 +57,7 @@ async fn validate_proposal_liveness(view_number, event_sender, task_state).await { - tracing::debug!("Liveness Branch - Failed to update view; error = {e:#}"); - } - if !liveness_check { bail!("Quorum Proposal failed the liveness check"); } @@ -153,11 +149,11 @@ pub(crate) async fn handle_quorum_proposal_recv< quorum_proposal_sender_key: &TYPES::SignatureKey, event_sender: &Sender>>, event_receiver: &Receiver>>, - task_state: &mut QuorumProposalRecvTaskState, + validation_info: ValidationInfo, ) -> Result<()> { let quorum_proposal_sender_key = quorum_proposal_sender_key.clone(); - validate_proposal_view_and_certs(proposal, task_state) + validate_proposal_view_and_certs(proposal, &validation_info) .await .context(warn!("Failed to validate proposal view or attached certs"))?; @@ -166,13 +162,13 @@ pub(crate) async fn handle_quorum_proposal_recv< if !justify_qc .is_valid_cert( - task_state.quorum_membership.as_ref(), - task_state.cur_epoch, - &task_state.upgrade_lock, + validation_info.quorum_membership.as_ref(), + validation_info.cur_epoch, + &validation_info.upgrade_lock, ) .await { - let consensus_reader = task_state.consensus.read().await; + let consensus_reader = validation_info.consensus.read().await; consensus_reader.metrics.invalid_qc.update(1); bail!("Invalid justify_qc in proposal for view {}", *view_number); } @@ -186,7 +182,7 @@ pub(crate) async fn handle_quorum_proposal_recv< .await; // Get the parent leaf and state. - let parent_leaf = task_state + let parent_leaf = validation_info .consensus .read() .await @@ -199,17 +195,17 @@ pub(crate) async fn handle_quorum_proposal_recv< justify_qc.view_number(), event_sender.clone(), event_receiver.clone(), - Arc::clone(&task_state.quorum_membership), - OuterConsensus::new(Arc::clone(&task_state.consensus.inner_consensus)), + Arc::clone(&validation_info.quorum_membership), + OuterConsensus::new(Arc::clone(&validation_info.consensus.inner_consensus)), // Note that we explicitly use the node key here instead of the provided key in the signature. // This is because the key that we receive is for the prior leader, so the payload would be routed // incorrectly. - task_state.public_key.clone(), - task_state.private_key.clone(), - task_state.upgrade_lock.clone(), + validation_info.public_key.clone(), + validation_info.private_key.clone(), + validation_info.upgrade_lock.clone(), ); } - let consensus_reader = task_state.consensus.read().await; + let consensus_reader = validation_info.consensus.read().await; let parent = match parent_leaf { Some(leaf) => { @@ -223,7 +219,7 @@ pub(crate) async fn handle_quorum_proposal_recv< }; if justify_qc.view_number() > consensus_reader.high_qc().view_number { - if let Err(e) = task_state + if let Err(e) = validation_info .storage .write() .await @@ -235,7 +231,7 @@ pub(crate) async fn handle_quorum_proposal_recv< } drop(consensus_reader); - let mut consensus_writer = task_state.consensus.write().await; + let mut consensus_writer = validation_info.consensus.write().await; if let Err(e) = consensus_writer.update_high_qc(justify_qc.clone()) { tracing::trace!("{e:?}"); } @@ -252,23 +248,29 @@ pub(crate) async fn handle_quorum_proposal_recv< "Proposal's parent missing from storage with commitment: {:?}", justify_qc.data.leaf_commit ); - return validate_proposal_liveness(proposal, event_sender, task_state).await; + validate_proposal_liveness(proposal, event_sender, &validation_info).await?; + broadcast_event( + Arc::new(HotShotEvent::ViewChange(view_number)), + event_sender, + ) + .await; + return Ok(()); }; // Validate the proposal validate_proposal_safety_and_liveness::( proposal.clone(), parent_leaf, - task_state, + &validation_info, event_sender.clone(), quorum_proposal_sender_key, ) .await?; - - // NOTE: We could update our view with a valid TC but invalid QC, but that is not what we do here - if let Err(e) = update_view::(view_number, event_sender, task_state).await { - tracing::debug!("Full Branch - Failed to update view; error = {e:#}"); - } + broadcast_event( + Arc::new(HotShotEvent::ViewChange(view_number)), + event_sender, + ) + .await; Ok(()) } diff --git a/crates/task-impls/src/quorum_proposal_recv/mod.rs b/crates/task-impls/src/quorum_proposal_recv/mod.rs index 030dc1295c..1cff840bf2 100644 --- a/crates/task-impls/src/quorum_proposal_recv/mod.rs +++ b/crates/task-impls/src/quorum_proposal_recv/mod.rs @@ -9,6 +9,7 @@ use std::{collections::BTreeMap, sync::Arc}; use async_broadcast::{broadcast, Receiver, Sender}; +use async_compatibility_layer::art::async_spawn; use async_lock::RwLock; #[cfg(async_executor_impl = "async-std")] use async_std::task::JoinHandle; @@ -38,7 +39,7 @@ use crate::{ events::{HotShotEvent, ProposalMissing}, helpers::{broadcast_event, cancel_task, parent_leaf_and_state}, }; - +use hotshot_types::traits::node_implementation::ConsensusTime; /// Event handlers for this task. mod handlers; @@ -57,24 +58,12 @@ pub struct QuorumProposalRecvTaskState, - /// Membership for Quorum Certs/votes pub quorum_membership: Arc, - /// Membership for Timeout votes/certs - pub timeout_membership: Arc, - - /// timeout task handle - pub timeout_task: JoinHandle<()>, - /// View timeout from config. pub timeout: u64, @@ -84,16 +73,10 @@ pub struct QuorumProposalRecvTaskState>, - /// last View Sync Certificate or Timeout Certificate this node formed. - pub proposal_cert: Option>, - /// Spawned tasks related to a specific view, so we can cancel them when /// they are stale pub spawned_tasks: BTreeMap>>, - /// Immutable instance state - pub instance_state: Arc, - /// The node's id pub id: u64, @@ -101,11 +84,34 @@ pub struct QuorumProposalRecvTaskState, } +/// all the info we need to validate a proposal. This makes it easy to spawn an effemeral task to +/// do all the proposal validation without blocking the long running one +pub(crate) struct ValidationInfo, V: Versions> { + /// The node's id + pub id: u64, + /// Our public key + pub(crate) public_key: TYPES::SignatureKey, + /// Our Private Key + pub(crate) private_key: ::PrivateKey, + /// Epoch number this node is executing in. + pub cur_epoch: TYPES::Epoch, + /// Reference to consensus. The replica will require a write lock on this. + pub(crate) consensus: OuterConsensus, + /// Membership for Quorum Certs/votes + pub quorum_membership: Arc, + /// Output events to application + pub output_event_stream: async_broadcast::Sender>, + /// This node's storage ref + pub(crate) storage: Arc>, + /// Lock for a decided upgrade + pub(crate) upgrade_lock: UpgradeLock, +} + impl, V: Versions> QuorumProposalRecvTaskState { /// Cancel all tasks the consensus tasks has spawned before the given view - pub async fn cancel_tasks(&mut self, view: TYPES::View) { + pub fn cancel_tasks(&mut self, view: TYPES::View) { let keep = self.spawned_tasks.split_off(&view); let mut cancel = Vec::new(); while let Some((_, tasks)) = self.spawned_tasks.pop_first() { @@ -113,7 +119,7 @@ impl, V: Versions> cancel.append(&mut to_cancel); } self.spawned_tasks = keep; - join_all(cancel).await; + async_spawn(async move { join_all(cancel).await }); } /// Handles all consensus events relating to propose and vote-enabling events. @@ -125,21 +131,51 @@ impl, V: Versions> event_sender: Sender>>, event_receiver: Receiver>>, ) { - if let HotShotEvent::QuorumProposalRecv(proposal, sender) = event.as_ref() { - match handle_quorum_proposal_recv( - proposal, - sender, - &event_sender, - &event_receiver, - self, - ) - .await - { - Ok(()) => { - self.cancel_tasks(proposal.data.view_number()).await; + match event.as_ref() { + HotShotEvent::QuorumProposalRecv(proposal, sender) => { + if self.consensus.read().await.cur_view() > proposal.data.view_number() + || self.cur_view > proposal.data.view_number() + { + tracing::error!("Throwing away old proposal"); + return; + } + let validation_info = ValidationInfo:: { + id: self.id, + public_key: self.public_key.clone(), + private_key: self.private_key.clone(), + cur_epoch: self.cur_epoch, + consensus: self.consensus.clone(), + quorum_membership: Arc::clone(&self.quorum_membership), + output_event_stream: self.output_event_stream.clone(), + storage: Arc::clone(&self.storage), + upgrade_lock: self.upgrade_lock.clone(), + }; + match handle_quorum_proposal_recv( + proposal, + sender, + &event_sender, + &event_receiver, + validation_info, + ) + .await + { + Ok(()) => {} + Err(e) => debug!(?e, "Failed to validate the proposal"), + } + } + HotShotEvent::ViewChange(view) => { + if self.cur_view >= *view { + return; } - Err(e) => debug!(?e, "Failed to validate the proposal"), + self.cur_view = *view; + // cancel task for any view 2 views prior or more. The view here is the oldest + // view we want to KEEP tasks for. We keep the view prior to this because + // we might still be processing the proposal from view V which caused us + // to enter view V + 1. + let oldest_view_to_keep = TYPES::View::new(view.saturating_sub(1)); + self.cancel_tasks(oldest_view_to_keep); } + _ => {} } } } diff --git a/crates/task-impls/src/quorum_vote/handlers.rs b/crates/task-impls/src/quorum_vote/handlers.rs index 656737524f..bec3bc6201 100644 --- a/crates/task-impls/src/quorum_vote/handlers.rs +++ b/crates/task-impls/src/quorum_vote/handlers.rs @@ -6,16 +6,23 @@ use std::sync::Arc; -use async_broadcast::Sender; +use async_broadcast::{InactiveReceiver, Sender}; +use async_lock::RwLock; use chrono::Utc; use hotshot_types::{ consensus::OuterConsensus, - data::QuorumProposal, + data::{Leaf, QuorumProposal, VidDisperseShare}, event::{Event, EventType}, + message::{Proposal, UpgradeLock}, + simple_vote::{QuorumData, QuorumVote}, traits::{ + election::Membership, node_implementation::{ConsensusTime, NodeImplementation, NodeType}, + signature_key::SignatureKey, storage::Storage, + ValidatedState, }, + utils::{View, ViewInner}, vote::HasViewNumber, }; use tracing::instrument; @@ -24,12 +31,12 @@ use utils::anytrace::*; use super::QuorumVoteTaskState; use crate::{ events::HotShotEvent, - helpers::{broadcast_event, decide_from_proposal, LeafChainTraversalOutcome}, + helpers::{broadcast_event, decide_from_proposal, fetch_proposal, LeafChainTraversalOutcome}, quorum_vote::Versions, }; /// Handles the `QuorumProposalValidated` event. -#[instrument(skip_all)] +#[instrument(skip_all, fields(id = task_state.id, view = *proposal.view_number))] pub(crate) async fn handle_quorum_proposal_validated< TYPES: NodeType, I: NodeImplementation, @@ -144,3 +151,201 @@ pub(crate) async fn handle_quorum_proposal_validated< Ok(()) } + +/// Updates the shared consensus state with the new voting data. +#[instrument(skip_all, target = "VoteDependencyHandle", fields(view = *view_number))] +#[allow(clippy::too_many_arguments)] +pub(crate) async fn update_shared_state< + TYPES: NodeType, + I: NodeImplementation, + V: Versions, +>( + consensus: OuterConsensus, + sender: Sender>>, + receiver: InactiveReceiver>>, + quorum_membership: Arc, + public_key: TYPES::SignatureKey, + private_key: ::PrivateKey, + upgrade_lock: UpgradeLock, + view_number: TYPES::View, + instance_state: Arc, + storage: Arc>, + proposed_leaf: &Leaf, + vid_share: &Proposal>, + parent_view_number: Option, +) -> Result<()> { + let justify_qc = &proposed_leaf.justify_qc(); + + let consensus_reader = consensus.read().await; + // Try to find the validated vview within the validasted state map. This will be present + // if we have the saved leaf, but if not we'll get it when we fetch_proposal. + let mut maybe_validated_view = parent_view_number.and_then(|view_number| { + consensus_reader + .validated_state_map() + .get(&view_number) + .cloned() + }); + + // Justify qc's leaf commitment should be the same as the parent's leaf commitment. + let mut maybe_parent = consensus_reader + .saved_leaves() + .get(&justify_qc.data.leaf_commit) + .cloned(); + + drop(consensus_reader); + + maybe_parent = match maybe_parent { + Some(p) => Some(p), + None => { + match fetch_proposal( + justify_qc.view_number(), + sender.clone(), + receiver.activate_cloned(), + Arc::clone(&quorum_membership), + OuterConsensus::new(Arc::clone(&consensus.inner_consensus)), + public_key.clone(), + private_key.clone(), + &upgrade_lock, + ) + .await + .ok() + { + Some((leaf, view)) => { + maybe_validated_view = Some(view); + Some(leaf) + } + None => None, + } + } + }; + + let parent = maybe_parent.context(info!( + "Proposal's parent missing from storage with commitment: {:?}, proposal view {:?}", + justify_qc.data.leaf_commit, + proposed_leaf.view_number(), + ))?; + + let Some(validated_view) = maybe_validated_view else { + bail!( + "Failed to fetch view for parent, parent view {:?}", + parent_view_number + ); + }; + + let (Some(parent_state), _) = validated_view.state_and_delta() else { + bail!("Parent state not found! Consensus internally inconsistent"); + }; + + let version = upgrade_lock.version(view_number).await?; + + let (validated_state, state_delta) = parent_state + .validate_and_apply_header( + &instance_state, + &parent, + &proposed_leaf.block_header().clone(), + vid_share.data.common.clone(), + version, + ) + .await + .wrap() + .context(warn!("Block header doesn't extend the proposal!"))?; + + let state = Arc::new(validated_state); + let delta = Arc::new(state_delta); + + // Now that we've rounded everyone up, we need to update the shared state and broadcast our events. + // We will defer broadcast until all states are updated to avoid holding onto the lock during a network call. + let mut consensus_writer = consensus.write().await; + + let view = View { + view_inner: ViewInner::Leaf { + leaf: proposed_leaf.commit(&upgrade_lock).await, + state: Arc::clone(&state), + delta: Some(Arc::clone(&delta)), + }, + }; + if let Err(e) = + consensus_writer.update_validated_state_map(proposed_leaf.view_number(), view.clone()) + { + tracing::trace!("{e:?}"); + } + consensus_writer + .update_saved_leaves(proposed_leaf.clone(), &upgrade_lock) + .await; + + // Kick back our updated structures for downstream usage. + let new_leaves = consensus_writer.saved_leaves().clone(); + let new_state = consensus_writer.validated_state_map().clone(); + drop(consensus_writer); + + // Broadcast now that the lock is dropped. + broadcast_event( + HotShotEvent::ValidatedStateUpdated(proposed_leaf.view_number(), view).into(), + &sender, + ) + .await; + + // Send the new state up to the sequencer. + storage + .write() + .await + .update_undecided_state(new_leaves, new_state) + .await + .wrap() + .context(error!("Failed to update undecided state"))?; + + Ok(()) +} + +/// Submits the `QuorumVoteSend` event if all the dependencies are met. +#[instrument(skip_all, fields(name = "Submit quorum vote", level = "error"))] +#[allow(clippy::too_many_arguments)] +pub(crate) async fn submit_vote, V: Versions>( + sender: Sender>>, + quorum_membership: Arc, + public_key: TYPES::SignatureKey, + private_key: ::PrivateKey, + upgrade_lock: UpgradeLock, + view_number: TYPES::View, + epoch_number: TYPES::Epoch, + storage: Arc>, + leaf: Leaf, + vid_share: Proposal>, +) -> Result<()> { + ensure!( + quorum_membership.has_stake(&public_key, epoch_number), + info!( + "We were not chosen for quorum committee on {:?}", + view_number + ) + ); + + // Create and send the vote. + let vote = QuorumVote::::create_signed_vote( + QuorumData { + leaf_commit: leaf.commit(&upgrade_lock).await, + }, + view_number, + &public_key, + &private_key, + &upgrade_lock, + ) + .await + .wrap() + .context(error!("Failed to sign vote. This should never happen."))?; + tracing::debug!( + "sending vote to next quorum leader {:?}", + vote.view_number() + 1 + ); + // Add to the storage. + storage + .write() + .await + .append_vid(&vid_share) + .await + .wrap() + .context(error!("Failed to store VID share"))?; + broadcast_event(Arc::new(HotShotEvent::QuorumVoteSend(vote)), &sender).await; + + Ok(()) +} diff --git a/crates/task-impls/src/quorum_vote/mod.rs b/crates/task-impls/src/quorum_vote/mod.rs index 3f78573d50..a3a58e3874 100644 --- a/crates/task-impls/src/quorum_vote/mod.rs +++ b/crates/task-impls/src/quorum_vote/mod.rs @@ -12,25 +12,22 @@ use async_lock::RwLock; use async_std::task::JoinHandle; use async_trait::async_trait; use hotshot_task::{ - dependency::{AndDependency, Dependency, EventDependency}, + dependency::{AndDependency, EventDependency}, dependency_task::{DependencyTask, HandleDepOutput}, task::TaskState, }; use hotshot_types::{ consensus::OuterConsensus, - data::{Leaf, VidDisperseShare, ViewNumber}, + data::{Leaf, QuorumProposal}, event::Event, message::{Proposal, UpgradeLock}, - simple_vote::{QuorumData, QuorumVote}, traits::{ block_contents::BlockHeader, election::Membership, node_implementation::{ConsensusTime, NodeImplementation, NodeType, Versions}, signature_key::SignatureKey, storage::Storage, - ValidatedState, }, - utils::{View, ViewInner}, vid::vid_scheme, vote::{Certificate, HasViewNumber}, }; @@ -39,11 +36,12 @@ use jf_vid::VidScheme; use tokio::task::JoinHandle; use tracing::instrument; use utils::anytrace::*; +use vbs::version::StaticVersionType; use crate::{ events::HotShotEvent, - helpers::{broadcast_event, cancel_task, fetch_proposal}, - quorum_vote::handlers::handle_quorum_proposal_validated, + helpers::{broadcast_event, cancel_task}, + quorum_vote::handlers::{handle_quorum_proposal_validated, submit_vote, update_shared_state}, }; /// Event handlers for `QuorumProposalValidated`. @@ -88,205 +86,43 @@ pub struct VoteDependencyHandle, V pub id: u64, } -impl + 'static, V: Versions> - VoteDependencyHandle -{ - /// Updates the shared consensus state with the new voting data. - #[instrument(skip_all, target = "VoteDependencyHandle", fields(id = self.id, view = *self.view_number))] - async fn update_shared_state( - &self, - proposed_leaf: &Leaf, - vid_share: &Proposal>, - ) -> Result<()> { - let justify_qc = &proposed_leaf.justify_qc(); - - // Justify qc's leaf commitment should be the same as the parent's leaf commitment. - let mut maybe_parent = self - .consensus - .read() - .await - .saved_leaves() - .get(&justify_qc.data().leaf_commit) - .cloned(); - maybe_parent = match maybe_parent { - Some(p) => Some(p), - None => fetch_proposal( - justify_qc.view_number(), - self.sender.clone(), - self.receiver.activate_cloned(), - Arc::clone(&self.quorum_membership), - OuterConsensus::new(Arc::clone(&self.consensus.inner_consensus)), - self.public_key.clone(), - self.private_key.clone(), - &self.upgrade_lock, - ) - .await - .ok(), - }; - let parent = maybe_parent.context(info!( - "Proposal's parent missing from storage with commitment: {:?}, proposal view {:?}", - justify_qc.data().leaf_commit, - proposed_leaf.view_number(), - ))?; - let consensus_reader = self.consensus.read().await; - - let (Some(parent_state), _) = consensus_reader.state_and_delta(parent.view_number()) else { - bail!("Parent state not found! Consensus internally inconsistent"); - }; - - drop(consensus_reader); - - let version = self.upgrade_lock.version(self.view_number).await?; - - let (validated_state, state_delta) = parent_state - .validate_and_apply_header( - &self.instance_state, - &parent, - &proposed_leaf.block_header().clone(), - vid_share.data.common.clone(), - version, - ) - .await - .wrap() - .context(warn!("Block header doesn't extend the proposal!"))?; - - let state = Arc::new(validated_state); - let delta = Arc::new(state_delta); - - // Now that we've rounded everyone up, we need to update the shared state and broadcast our events. - // We will defer broadcast until all states are updated to avoid holding onto the lock during a network call. - let mut consensus_writer = self.consensus.write().await; - - let view = View { - view_inner: ViewInner::Leaf { - leaf: proposed_leaf.commit(&self.upgrade_lock).await, - state: Arc::clone(&state), - delta: Some(Arc::clone(&delta)), - }, - }; - if let Err(e) = - consensus_writer.update_validated_state_map(proposed_leaf.view_number(), view.clone()) - { - tracing::trace!("{e:?}"); - } - consensus_writer - .update_saved_leaves(proposed_leaf.clone(), &self.upgrade_lock) - .await; - - // Kick back our updated structures for downstream usage. - let new_leaves = consensus_writer.saved_leaves().clone(); - let new_state = consensus_writer.validated_state_map().clone(); - drop(consensus_writer); - - // Broadcast now that the lock is dropped. - broadcast_event( - HotShotEvent::ValidatedStateUpdated(proposed_leaf.view_number(), view).into(), - &self.sender, - ) - .await; - - // Send the new state up to the sequencer. - self.storage - .write() - .await - .update_undecided_state(new_leaves, new_state) - .await - .wrap() - .context(error!("Failed to update undecided state"))?; - - Ok(()) - } - - /// Submits the `QuorumVoteSend` event if all the dependencies are met. - #[instrument(skip_all, fields(id = self.id, name = "Submit quorum vote", level = "error"))] - async fn submit_vote( - &self, - leaf: Leaf, - vid_share: Proposal>, - ) -> Result<()> { - ensure!( - self.quorum_membership - .has_stake(&self.public_key, self.epoch_number), - info!( - "We were not chosen for quorum committee on {:?}", - self.view_number - ) - ); - - // Create and send the vote. - let vote = QuorumVote::::create_signed_vote( - QuorumData { - leaf_commit: leaf.commit(&self.upgrade_lock).await, - }, - self.view_number, - &self.public_key, - &self.private_key, - &self.upgrade_lock, - ) - .await - .wrap() - .context(error!("Failed to sign vote. This should never happen."))?; - tracing::debug!( - "sending vote to next quorum leader {:?}", - vote.view_number() + 1 - ); - // Add to the storage. - self.storage - .write() - .await - .append_vid(&vid_share) - .await - .wrap() - .context(error!("Failed to store VID share"))?; - broadcast_event(Arc::new(HotShotEvent::QuorumVoteSend(vote)), &self.sender).await; - - Ok(()) - } -} - impl + 'static, V: Versions> HandleDepOutput for VoteDependencyHandle { type Output = Vec>>; #[allow(clippy::too_many_lines)] + #[instrument(skip_all, fields(id = self.id, view = *self.view_number))] async fn handle_dep_result(self, res: Self::Output) { - let high_qc_view_number = self.consensus.read().await.high_qc().view_number; - - // The validated state of a non-genesis high QC should exist in the state map. - if *high_qc_view_number != *ViewNumber::genesis() - && !self - .consensus - .read() - .await - .validated_state_map() - .contains_key(&high_qc_view_number) - { - // Block on receiving the event from the event stream. - EventDependency::new( - self.receiver.activate_cloned(), - Box::new(move |event| { - let event = event.as_ref(); - if let HotShotEvent::ValidatedStateUpdated(view_number, _) = event { - *view_number == high_qc_view_number - } else { - false - } - }), - ) - .completed() - .await; - } - let mut payload_commitment = None; let mut leaf = None; let mut vid_share = None; + let mut parent_view_number = None; for event in res { match event.as_ref() { #[allow(unused_assignments)] HotShotEvent::QuorumProposalValidated(proposal, parent_leaf) => { + let version = match self.upgrade_lock.version(self.view_number).await { + Ok(version) => version, + Err(e) => { + tracing::error!("{e:#}"); + return; + } + }; let proposal_payload_comm = proposal.data.block_header.payload_commitment(); - if let Some(ref comm) = payload_commitment { + let parent_commitment = parent_leaf.commit(&self.upgrade_lock).await; + let proposed_leaf = Leaf::from_quorum_proposal(&proposal.data); + + if version >= V::Epochs::VERSION + && self + .consensus + .read() + .await + .is_qc_forming_eqc(&proposal.data.justify_qc) + { + tracing::debug!("Do not vote here. Voting for this case is handled in QuorumVoteTaskState"); + return; + } else if let Some(ref comm) = payload_commitment { if proposal_payload_comm != *comm { tracing::error!("Quorum proposal has inconsistent payload commitment with DAC or VID."); return; @@ -294,19 +130,19 @@ impl + 'static, V: Versions> Handl } else { payload_commitment = Some(proposal_payload_comm); } - let parent_commitment = parent_leaf.commit(&self.upgrade_lock).await; - let proposed_leaf = Leaf::from_quorum_proposal(&proposal.data); + if proposed_leaf.parent_commitment() != parent_commitment { tracing::warn!("Proposed leaf parent commitment does not match parent leaf payload commitment. Aborting vote."); return; } - // Update our persistent storage of the proposal. If we cannot store the proposal reutrn + // Update our persistent storage of the proposal. If we cannot store the proposal return // and error so we don't vote if let Err(e) = self.storage.write().await.append_proposal(proposal).await { tracing::error!("failed to store proposal, not voting. error = {e:#}"); return; } leaf = Some(proposed_leaf); + parent_view_number = Some(parent_leaf.view_number()); } HotShotEvent::DaCertificateValidated(cert) => { let cert_payload_comm = &cert.data().payload_commit; @@ -334,6 +170,7 @@ impl + 'static, V: Versions> Handl _ => {} } } + broadcast_event( Arc::new(HotShotEvent::QuorumVoteDependenciesValidated( self.view_number, @@ -341,7 +178,11 @@ impl + 'static, V: Versions> Handl &self.sender, ) .await; - + broadcast_event( + Arc::new(HotShotEvent::ViewChange(self.view_number + 1)), + &self.sender, + ) + .await; let Some(vid_share) = vid_share else { tracing::error!( "We don't have the VID share for this view {:?}, but we should, because the vote dependencies have completed.", @@ -359,12 +200,41 @@ impl + 'static, V: Versions> Handl }; // Update internal state - if let Err(e) = self.update_shared_state(&leaf, &vid_share).await { + if let Err(e) = update_shared_state::( + OuterConsensus::new(Arc::clone(&self.consensus.inner_consensus)), + self.sender.clone(), + self.receiver.clone(), + Arc::clone(&self.quorum_membership), + self.public_key.clone(), + self.private_key.clone(), + self.upgrade_lock.clone(), + self.view_number, + Arc::clone(&self.instance_state), + Arc::clone(&self.storage), + &leaf, + &vid_share, + parent_view_number, + ) + .await + { tracing::error!("Failed to update shared consensus state; error = {e:#}"); return; } - if let Err(e) = self.submit_vote(leaf, vid_share).await { + if let Err(e) = submit_vote::( + self.sender.clone(), + Arc::clone(&self.quorum_membership), + self.public_key.clone(), + self.private_key.clone(), + self.upgrade_lock.clone(), + self.view_number, + self.epoch_number, + Arc::clone(&self.storage), + leaf, + vid_share, + ) + .await + { tracing::debug!("Failed to vote; error = {e:#}"); } } @@ -470,11 +340,6 @@ impl, V: Versions> QuorumVoteTaskS event_sender: &Sender>>, event: Option>>, ) { - if view_number <= self.latest_voted_view { - tracing::trace!("We have already voted for this view"); - return; - } - if self.vote_dependencies.contains_key(&view_number) { return; } @@ -496,6 +361,7 @@ impl, V: Versions> QuorumVoteTaskS } let deps = vec![quorum_proposal_dependency, dac_dependency, vid_dependency]; + let dependency_chain = AndDependency::from_deps(deps); let dependency_task = DependencyTask::new( @@ -553,8 +419,7 @@ impl, V: Versions> QuorumVoteTaskS event_sender: Sender>>, ) -> Result<()> { match event.as_ref() { - HotShotEvent::QuorumProposalValidated(proposal, _leaf) => { - let cur_epoch = self.consensus.read().await.cur_epoch(); + HotShotEvent::QuorumProposalValidated(proposal, parent_leaf) => { tracing::trace!( "Received Proposal for view {}", *proposal.data.view_number() @@ -569,13 +434,40 @@ impl, V: Versions> QuorumVoteTaskS ); } - self.create_dependency_task_if_new( - proposal.data.view_number, - cur_epoch, - event_receiver, - &event_sender, - Some(Arc::clone(&event)), + ensure!( + proposal.data.view_number() > self.latest_voted_view, + "We have already voted for this view" ); + + let version = self + .upgrade_lock + .version(proposal.data.view_number()) + .await?; + + let consensus_reader = self.consensus.read().await; + let cur_epoch = consensus_reader.cur_epoch(); + let is_qc_forming_eqc = + consensus_reader.is_qc_forming_eqc(&proposal.data.justify_qc); + drop(consensus_reader); + + if version >= V::Epochs::VERSION && is_qc_forming_eqc { + self.handle_eqc_voting( + proposal, + parent_leaf, + event_sender, + event_receiver, + cur_epoch, + ) + .await; + } else { + self.create_dependency_task_if_new( + proposal.data.view_number, + cur_epoch, + event_receiver, + &event_sender, + Some(Arc::clone(&event)), + ); + } } HotShotEvent::DaCertificateRecv(cert) => { let view = cert.view_number; @@ -685,8 +577,9 @@ impl, V: Versions> QuorumVoteTaskS } } HotShotEvent::Timeout(view) => { + let view = TYPES::View::new(view.saturating_sub(1)); // cancel old tasks - let current_tasks = self.vote_dependencies.split_off(view); + let current_tasks = self.vote_dependencies.split_off(&view); while let Some((_, task)) = self.vote_dependencies.pop_last() { cancel_task(task).await; } @@ -705,6 +598,114 @@ impl, V: Versions> QuorumVoteTaskS } Ok(()) } + + /// Handles voting for the last block in the epoch to form the Extended QC. + async fn handle_eqc_voting( + &self, + proposal: &Proposal>, + parent_leaf: &Leaf, + event_sender: Sender>>, + event_receiver: Receiver>>, + epoch_number: TYPES::Epoch, + ) { + tracing::info!("Reached end of epoch. Justify QC is for the last block in the epoch."); + let proposed_leaf = Leaf::from_quorum_proposal(&proposal.data); + let parent_commitment = parent_leaf.commit(&self.upgrade_lock).await; + if proposed_leaf.height() != parent_leaf.height() + || proposed_leaf.payload_commitment() != parent_leaf.payload_commitment() + { + tracing::error!("Justify QC is for the last block but it's not extended and a new block is proposed. Not voting!"); + return; + } + + tracing::info!( + "Reached end of epoch. Proposed leaf has the same height and payload as its parent." + ); + + let mut consensus_writer = self.consensus.write().await; + let Some(vid_shares) = consensus_writer + .vid_shares() + .get(&parent_leaf.view_number()) + else { + tracing::warn!( + "Proposed leaf is the same as its parent but we don't have our VID for it" + ); + return; + }; + let Some(vid) = vid_shares.get(&self.public_key) else { + tracing::warn!( + "Proposed leaf is the same as its parent but we don't have our VID for it" + ); + return; + }; + let mut updated_vid = vid.clone(); + updated_vid.data.view_number = proposal.data.view_number; + consensus_writer.update_vid_shares(updated_vid.data.view_number, updated_vid.clone()); + drop(consensus_writer); + + if proposed_leaf.parent_commitment() != parent_commitment { + tracing::warn!("Proposed leaf parent commitment does not match parent leaf payload commitment. Aborting vote."); + return; + } + // Update our persistent storage of the proposal. If we cannot store the proposal return + // and error so we don't vote + if let Err(e) = self.storage.write().await.append_proposal(proposal).await { + tracing::error!("failed to store proposal, not voting. error = {e:#}"); + return; + } + + broadcast_event( + Arc::new(HotShotEvent::QuorumVoteDependenciesValidated( + proposal.data.view_number(), + )), + &event_sender, + ) + .await; + broadcast_event( + Arc::new(HotShotEvent::ViewChange(proposal.data.view_number() + 1)), + &event_sender, + ) + .await; + + // Update internal state + if let Err(e) = update_shared_state::( + OuterConsensus::new(Arc::clone(&self.consensus.inner_consensus)), + event_sender.clone(), + event_receiver.clone().deactivate(), + Arc::clone(&self.quorum_membership), + self.public_key.clone(), + self.private_key.clone(), + self.upgrade_lock.clone(), + proposal.data.view_number(), + Arc::clone(&self.instance_state), + Arc::clone(&self.storage), + &proposed_leaf, + &updated_vid, + Some(parent_leaf.view_number()), + ) + .await + { + tracing::error!("Failed to update shared consensus state; error = {e:#}"); + return; + } + + if let Err(e) = submit_vote::( + event_sender.clone(), + Arc::clone(&self.quorum_membership), + self.public_key.clone(), + self.private_key.clone(), + self.upgrade_lock.clone(), + proposal.data.view_number(), + epoch_number, + Arc::clone(&self.storage), + proposed_leaf, + updated_vid, + ) + .await + { + tracing::debug!("Failed to vote; error = {e:#}"); + } + } } #[async_trait] diff --git a/crates/task-impls/src/request.rs b/crates/task-impls/src/request.rs index 6964e38cd7..abacf32ffd 100644 --- a/crates/task-impls/src/request.rs +++ b/crates/task-impls/src/request.rs @@ -180,9 +180,14 @@ impl> NetworkRequestState = self .da_membership @@ -205,7 +210,7 @@ impl> NetworkRequestState, V: Versions> TransactionTask None } + /// epochs view change handler + #[instrument(skip_all, fields(id = self.id, view_number = *self.cur_view))] + pub async fn handle_view_change_epochs( + &mut self, + event_stream: &Sender>>, + block_view: TYPES::View, + ) -> Option { + if self.consensus.read().await.is_high_qc_forming_eqc() { + tracing::info!("Reached end of epoch. Not getting a new block until we form an eQC."); + None + } else { + self.handle_view_change_marketplace(event_stream, block_view) + .await + } + } + /// main task event handler #[instrument(skip_all, fields(id = self.id, view = *self.cur_view), name = "Transaction task", level = "error", target = "TransactionTaskState")] pub async fn handle( @@ -454,41 +470,17 @@ impl, V: Versions> TransactionTask .await; } HotShotEvent::ViewChange(view) => { - let view = *view; - - tracing::debug!("view change in transactions to view {:?}", view); + let view = TYPES::View::new(std::cmp::max(1, **view)); ensure!( - *view > *self.cur_view || *self.cur_view == 0, - debug!( - "Received a view change to an older view: tried to change view to {:?} though we are at view {:?}", view, self.cur_view - ) - ); - - let mut make_block = false; - if *view - *self.cur_view > 1 { - tracing::info!("View changed by more than 1 going to view {:?}", view); - make_block = self.membership.leader(view, self.cur_epoch)? == self.public_key; - } - self.cur_view = view; - - let next_view = self.cur_view + 1; - let next_leader = - self.membership.leader(next_view, self.cur_epoch)? == self.public_key; - - ensure!( - make_block || next_leader, + *view > *self.cur_view, debug!( - "Not making the block because we are not leader for view {:?}", - self.cur_view + "Received a view change to an older view: tried to change view to {:?} though we are at view {:?}", view, self.cur_view ) ); - - if make_block { - self.handle_view_change(&event_stream, self.cur_view).await; - } - - if next_leader { - self.handle_view_change(&event_stream, next_view).await; + self.cur_view = view; + if self.membership.leader(view, self.cur_epoch)? == self.public_key { + self.handle_view_change(&event_stream, view).await; + return Ok(()); } } _ => {} @@ -732,7 +724,7 @@ impl, V: Versions> TransactionTask ) { Ok(request_signature) => request_signature, Err(err) => { - tracing::warn!(%err, "Failed to sign block hash"); + tracing::error!(%err, "Failed to sign block hash"); continue; } }; diff --git a/crates/task-impls/src/upgrade.rs b/crates/task-impls/src/upgrade.rs index fb4f4de7f4..56107613cd 100644 --- a/crates/task-impls/src/upgrade.rs +++ b/crates/task-impls/src/upgrade.rs @@ -37,7 +37,7 @@ use crate::{ vote_collection::{handle_vote, VoteCollectorsMap}, }; -/// Tracks state of a DA task +/// Tracks state of an upgrade task pub struct UpgradeTaskState, V: Versions> { /// Output events to application pub output_event_stream: async_broadcast::Sender>, @@ -50,6 +50,7 @@ pub struct UpgradeTaskState, V: Ve /// Membership for Quorum Certs/votes pub quorum_membership: Arc, + /// The underlying network pub network: Arc, diff --git a/crates/task-impls/src/view_sync.rs b/crates/task-impls/src/view_sync.rs index 28dfe9d935..2172d00d41 100644 --- a/crates/task-impls/src/view_sync.rs +++ b/crates/task-impls/src/view_sync.rs @@ -439,7 +439,6 @@ impl, V: Versions> ViewSyncTaskSta // Garbage collect old tasks // We could put this into a separate async task, but that would require making several fields on ViewSyncTaskState thread-safe and harm readability. In the common case this will have zero tasks to clean up. - // cancel poll for votes // run GC for i in *self.last_garbage_collected_view..*self.cur_view { self.replica_task_map @@ -466,7 +465,7 @@ impl, V: Versions> ViewSyncTaskSta &HotShotEvent::Timeout(view_number) => { // This is an old timeout and we can ignore it ensure!( - view_number > self.cur_view, + view_number >= self.cur_view, debug!("Discarding old timeout vote.") ); @@ -495,7 +494,7 @@ impl, V: Versions> ViewSyncTaskSta .await; } else { // If this is the first timeout we've seen advance to the next view - self.cur_view = view_number; + self.cur_view = view_number + 1; broadcast_event( Arc::new(HotShotEvent::ViewChange(TYPES::View::new(*self.cur_view))), &event_stream, diff --git a/crates/testing/Cargo.toml b/crates/testing/Cargo.toml index 82473f3d34..79a11a7502 100644 --- a/crates/testing/Cargo.toml +++ b/crates/testing/Cargo.toml @@ -57,3 +57,8 @@ tokio = { workspace = true } [target.'cfg(all(async_executor_impl = "async-std"))'.dependencies] async-std = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = [ + 'cfg(async_executor_impl, values("tokio", "async-std"))', +] } \ No newline at end of file diff --git a/crates/testing/src/block_builder/random.rs b/crates/testing/src/block_builder/random.rs index cea9e40328..0d6d767ff4 100644 --- a/crates/testing/src/block_builder/random.rs +++ b/crates/testing/src/block_builder/random.rs @@ -304,6 +304,18 @@ impl BuilderDataSource for RandomBuilderSource { Ok(payload) } + async fn claim_block_with_num_nodes( + &self, + block_hash: &BuilderCommitment, + view_number: u64, + sender: TYPES::SignatureKey, + signature: &::PureAssembledSignatureType, + _num_nodes: usize, + ) -> Result, BuildError> { + self.claim_block(block_hash, view_number, sender, signature) + .await + } + async fn claim_block_header_input( &self, block_hash: &BuilderCommitment, diff --git a/crates/testing/src/block_builder/simple.rs b/crates/testing/src/block_builder/simple.rs index e1207a4fc2..63a28d854c 100644 --- a/crates/testing/src/block_builder/simple.rs +++ b/crates/testing/src/block_builder/simple.rs @@ -297,6 +297,18 @@ where Ok(payload) } + async fn claim_block_with_num_nodes( + &self, + block_hash: &BuilderCommitment, + view_number: u64, + sender: TYPES::SignatureKey, + signature: &::PureAssembledSignatureType, + _num_nodes: usize, + ) -> Result, BuildError> { + self.claim_block(block_hash, view_number, sender, signature) + .await + } + async fn claim_block_header_input( &self, block_hash: &BuilderCommitment, diff --git a/crates/testing/src/byzantine/byzantine_behaviour.rs b/crates/testing/src/byzantine/byzantine_behaviour.rs index 30233dd269..e21580a3a5 100644 --- a/crates/testing/src/byzantine/byzantine_behaviour.rs +++ b/crates/testing/src/byzantine/byzantine_behaviour.rs @@ -1,5 +1,5 @@ use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, sync::Arc, }; @@ -351,6 +351,7 @@ impl + std::fmt::Debug, V: Version storage: Arc::clone(&handle.storage()), consensus: Arc::clone(&handle.consensus()), upgrade_lock: handle.hotshot.upgrade_lock.clone(), + transmit_tasks: BTreeMap::new(), }; let modified_network_state = NetworkEventTaskStateModifier { network_event_task_state: network_state, diff --git a/crates/testing/src/lib.rs b/crates/testing/src/lib.rs index 43861fcbf2..20d513dc2a 100644 --- a/crates/testing/src/lib.rs +++ b/crates/testing/src/lib.rs @@ -8,7 +8,7 @@ #![cfg_attr( // hotshot_example option is set manually in justfile when running examples - not(any(test, debug_assertions, hotshot_example)), + not(any(test, debug_assertions)), deprecated = "suspicious usage of testing/demo implementations in non-test/non-debug build" )] diff --git a/crates/testing/src/overall_safety_task.rs b/crates/testing/src/overall_safety_task.rs index 979c2c2a04..ba7136c90f 100644 --- a/crates/testing/src/overall_safety_task.rs +++ b/crates/testing/src/overall_safety_task.rs @@ -498,6 +498,7 @@ impl RoundResult { } if let Some((n_txn, _)) = self.num_txns_map.iter().last() { if *n_txn < transaction_threshold { + tracing::error!("not enough transactions for view {:?}", key.view_number()); self.status = ViewStatus::Failed; return; } diff --git a/crates/testing/src/test_builder.rs b/crates/testing/src/test_builder.rs index 064e6ddf39..4773e597e0 100644 --- a/crates/testing/src/test_builder.rs +++ b/crates/testing/src/test_builder.rs @@ -98,6 +98,8 @@ pub struct TestDescription, V: Ver pub start_solver: bool, /// boxed closure used to validate the resulting transactions pub validate_transactions: TransactionValidator, + /// Number of blocks in an epoch, zero means there are no epochs + pub epoch_height: u64, } pub fn nonempty_block_threshold(threshold: (u64, u64)) -> TransactionValidator { @@ -415,6 +417,7 @@ impl, V: Versions> Default upgrade_view: None, start_solver: true, validate_transactions: Arc::new(|_| Ok(())), + epoch_height: 0, } } } @@ -452,6 +455,7 @@ where timing_data, da_staked_committee_size, unreliable_network, + epoch_height, .. } = self.clone(); @@ -508,7 +512,7 @@ where stop_proposing_time: 0, start_voting_time: u64::MAX, stop_voting_time: 0, - epoch_height: 0, + epoch_height, }; let TimingData { next_view_timeout, diff --git a/crates/testing/src/txn_task.rs b/crates/testing/src/txn_task.rs index 8f363847d0..03fa0be103 100644 --- a/crates/testing/src/txn_task.rs +++ b/crates/testing/src/txn_task.rs @@ -38,7 +38,6 @@ pub struct TxnTask, V: Ver impl, V: Versions> TxnTask { pub fn run(mut self) -> JoinHandle<()> { async_spawn(async move { - async_sleep(Duration::from_millis(100)).await; loop { async_sleep(self.duration).await; if let Ok(TestEvent::Shutdown) = self.shutdown_chan.try_recv() { diff --git a/crates/testing/tests/tests_1/network_task.rs b/crates/testing/tests/tests_1/network_task.rs index a2f550ec25..26367ab7b4 100644 --- a/crates/testing/tests/tests_1/network_task.rs +++ b/crates/testing/tests/tests_1/network_task.rs @@ -33,6 +33,8 @@ use hotshot_types::{ #[cfg_attr(async_executor_impl = "async-std", async_std::test)] #[allow(clippy::too_many_lines)] async fn test_network_task() { + use std::collections::BTreeMap; + use futures::StreamExt; use hotshot_types::traits::network::Topic; @@ -70,6 +72,7 @@ async fn test_network_task() { upgrade_lock: upgrade_lock.clone(), storage, consensus, + transmit_tasks: BTreeMap::new(), }; let (tx, rx) = async_broadcast::broadcast(10); let mut task_reg = ConsensusTaskRegistry::new(); @@ -215,6 +218,8 @@ async fn test_network_external_mnessages() { #[cfg_attr(async_executor_impl = "tokio", tokio::test(flavor = "multi_thread"))] #[cfg_attr(async_executor_impl = "async-std", async_std::test)] async fn test_network_storage_fail() { + use std::collections::BTreeMap; + use futures::StreamExt; use hotshot_types::traits::network::Topic; @@ -252,6 +257,7 @@ async fn test_network_storage_fail() { upgrade_lock: upgrade_lock.clone(), storage, consensus, + transmit_tasks: BTreeMap::new(), }; let (tx, rx) = async_broadcast::broadcast(10); let mut task_reg = ConsensusTaskRegistry::new(); diff --git a/crates/testing/tests/tests_1/quorum_vote_task.rs b/crates/testing/tests/tests_1/quorum_vote_task.rs index 3030a1aea2..b167910684 100644 --- a/crates/testing/tests/tests_1/quorum_vote_task.rs +++ b/crates/testing/tests/tests_1/quorum_vote_task.rs @@ -84,6 +84,7 @@ async fn test_quorum_vote_task_success() { exact(DaCertificateValidated(dacs[1].clone())), exact(VidShareValidated(vids[1].0[0].clone())), exact(QuorumVoteDependenciesValidated(ViewNumber::new(2))), + exact(ViewChange(ViewNumber::new(3))), validated_state_updated(), quorum_vote_send(), ])]; diff --git a/crates/testing/tests/tests_1/test_success.rs b/crates/testing/tests/tests_1/test_success.rs index 853f823278..588c718a83 100644 --- a/crates/testing/tests/tests_1/test_success.rs +++ b/crates/testing/tests/tests_1/test_success.rs @@ -8,8 +8,8 @@ use std::time::Duration; use hotshot_example_types::{ node_types::{ - Libp2pImpl, MemoryImpl, PushCdnImpl, TestConsecutiveLeaderTypes, TestTypes, - TestTypesRandomizedLeader, TestVersions, + EpochsTestVersions, Libp2pImpl, MemoryImpl, PushCdnImpl, TestConsecutiveLeaderTypes, + TestTypes, TestTypesRandomizedLeader, TestVersions, }, testable_delay::{DelayConfig, DelayOptions, DelaySettings, SupportedTraitTypesForAsyncDelay}, }; @@ -132,3 +132,22 @@ cross_tests!( metadata } ); + +cross_tests!( + TestName: test_epoch_end, + Impls: [MemoryImpl], + Types: [TestTypes], + Versions: [EpochsTestVersions], + Ignore: false, + Metadata: { + TestDescription { + completion_task_description: CompletionTaskDescription::TimeBasedCompletionTaskBuilder( + TimeBasedCompletionTaskDescription { + duration: Duration::from_millis(100000), + }, + ), + epoch_height: 10, + ..TestDescription::default() + } + }, +); diff --git a/crates/testing/tests/tests_1/transaction_task.rs b/crates/testing/tests/tests_1/transaction_task.rs index 04cd0d528e..b9834b98c8 100644 --- a/crates/testing/tests/tests_1/transaction_task.rs +++ b/crates/testing/tests/tests_1/transaction_task.rs @@ -36,6 +36,7 @@ async fn test_transaction_task_leader_two_views_in_a_row() { let current_view = ViewNumber::new(4); input.push(HotShotEvent::ViewChange(current_view)); + input.push(HotShotEvent::ViewChange(current_view + 1)); input.push(HotShotEvent::Shutdown); let quorum_membership = handle.hotshot.memberships.quorum_membership.clone(); diff --git a/crates/testing/tests/tests_1/upgrade_task_with_vote.rs b/crates/testing/tests/tests_1/upgrade_task_with_vote.rs index 212ca114bb..658a10c386 100644 --- a/crates/testing/tests/tests_1/upgrade_task_with_vote.rs +++ b/crates/testing/tests/tests_1/upgrade_task_with_vote.rs @@ -138,6 +138,7 @@ async fn test_upgrade_task_with_vote() { exact(DaCertificateValidated(dacs[1].clone())), exact(VidShareValidated(vids[1].0[0].clone())), exact(QuorumVoteDependenciesValidated(ViewNumber::new(2))), + exact(ViewChange(ViewNumber::new(3))), validated_state_updated(), quorum_vote_send(), ]), @@ -147,6 +148,7 @@ async fn test_upgrade_task_with_vote() { exact(DaCertificateValidated(dacs[2].clone())), exact(VidShareValidated(vids[2].0[0].clone())), exact(QuorumVoteDependenciesValidated(ViewNumber::new(3))), + exact(ViewChange(ViewNumber::new(4))), validated_state_updated(), quorum_vote_send(), ], @@ -160,6 +162,7 @@ async fn test_upgrade_task_with_vote() { exact(DaCertificateValidated(dacs[3].clone())), exact(VidShareValidated(vids[3].0[0].clone())), exact(QuorumVoteDependenciesValidated(ViewNumber::new(4))), + exact(ViewChange(ViewNumber::new(5))), validated_state_updated(), quorum_vote_send(), ], @@ -173,6 +176,7 @@ async fn test_upgrade_task_with_vote() { exact(DaCertificateValidated(dacs[4].clone())), exact(VidShareValidated(vids[4].0[0].clone())), exact(QuorumVoteDependenciesValidated(ViewNumber::new(5))), + exact(ViewChange(ViewNumber::new(6))), validated_state_updated(), quorum_vote_send(), ], diff --git a/crates/testing/tests/tests_1/view_sync_task.rs b/crates/testing/tests/tests_1/view_sync_task.rs index 5b2a9bf2d3..145885a657 100644 --- a/crates/testing/tests/tests_1/view_sync_task.rs +++ b/crates/testing/tests/tests_1/view_sync_task.rs @@ -51,7 +51,7 @@ async fn test_view_sync_task() { input.push(HotShotEvent::Shutdown); - output.push(HotShotEvent::ViewChange(ViewNumber::new(2))); + output.push(HotShotEvent::ViewChange(ViewNumber::new(3))); output.push(HotShotEvent::ViewSyncPreCommitVoteSend(vote.clone())); let view_sync_state = diff --git a/crates/testing/tests/tests_1/vote_dependency_handle.rs b/crates/testing/tests/tests_1/vote_dependency_handle.rs index 085e37862a..742ba10f53 100644 --- a/crates/testing/tests/tests_1/vote_dependency_handle.rs +++ b/crates/testing/tests/tests_1/vote_dependency_handle.rs @@ -80,6 +80,7 @@ async fn test_vote_dependency_handle() { // The outputs are static here, but we re-make them since we use `into_iter` below let outputs = vec![ exact(QuorumVoteDependenciesValidated(ViewNumber::new(2))), + exact(ViewChange(ViewNumber::new(3))), validated_state_updated(), quorum_vote_send(), ]; diff --git a/crates/testing/tests/tests_4/byzantine_tests.rs b/crates/testing/tests/tests_4/byzantine_tests.rs index 8b460a5665..7d89d6c870 100644 --- a/crates/testing/tests/tests_4/byzantine_tests.rs +++ b/crates/testing/tests/tests_4/byzantine_tests.rs @@ -1,61 +1,61 @@ -use std::{collections::HashMap, rc::Rc, time::Duration}; +// use std::{collections::HashMap, rc::Rc, time::Duration}; -use hotshot_example_types::{ - node_types::{Libp2pImpl, MarketplaceTestVersions, MemoryImpl, PushCdnImpl}, - state_types::TestTypes, -}; -use hotshot_macros::cross_tests; -use hotshot_testing::{ - block_builder::SimpleBuilderImplementation, - byzantine::byzantine_behaviour::ViewDelay, - completion_task::{CompletionTaskDescription, TimeBasedCompletionTaskDescription}, - test_builder::{Behaviour, TestDescription}, -}; -use hotshot_types::{data::ViewNumber, traits::node_implementation::ConsensusTime}; +// use hotshot_example_types::{ +// node_types::{Libp2pImpl, MarketplaceTestVersions, MemoryImpl, PushCdnImpl}, +// state_types::TestTypes, +// }; +// use hotshot_macros::cross_tests; +// use hotshot_testing::{ +// block_builder::SimpleBuilderImplementation, +// byzantine::byzantine_behaviour::ViewDelay, +// completion_task::{CompletionTaskDescription, TimeBasedCompletionTaskDescription}, +// test_builder::{Behaviour, TestDescription}, +// }; +// use hotshot_types::{data::ViewNumber, traits::node_implementation::ConsensusTime}; -cross_tests!( - TestName: view_delay, - Impls: [MemoryImpl, Libp2pImpl, PushCdnImpl], - Types: [TestTypes], - Versions: [MarketplaceTestVersions], - Ignore: false, - Metadata: { +// cross_tests!( +// TestName: view_delay, +// Impls: [MemoryImpl, Libp2pImpl, PushCdnImpl], +// Types: [TestTypes], +// Versions: [MarketplaceTestVersions], +// Ignore: false, +// Metadata: { - let behaviour = Rc::new(|node_id| { - let view_delay = ViewDelay { - number_of_views_to_delay: node_id/3, - events_for_view: HashMap::new(), - stop_view_delay_at_view_number: 25, - }; - match node_id { - 6|10|14 => Behaviour::Byzantine(Box::new(view_delay)), - _ => Behaviour::Standard, - } - }); +// let behaviour = Rc::new(|node_id| { +// let view_delay = ViewDelay { +// number_of_views_to_delay: node_id/3, +// events_for_view: HashMap::new(), +// stop_view_delay_at_view_number: 25, +// }; +// match node_id { +// 6|10|14 => Behaviour::Byzantine(Box::new(view_delay)), +// _ => Behaviour::Standard, +// } +// }); - let mut metadata = TestDescription { - // allow more time to pass in CI - completion_task_description: CompletionTaskDescription::TimeBasedCompletionTaskBuilder( - TimeBasedCompletionTaskDescription { - duration: Duration::from_secs(60), - }, - ), - behaviour, - ..TestDescription::default() - }; +// let mut metadata = TestDescription { +// // allow more time to pass in CI +// completion_task_description: CompletionTaskDescription::TimeBasedCompletionTaskBuilder( +// TimeBasedCompletionTaskDescription { +// duration: Duration::from_secs(60), +// }, +// ), +// behaviour, +// ..TestDescription::default() +// }; - let num_nodes_with_stake = 15; - metadata.num_nodes_with_stake = num_nodes_with_stake; - metadata.da_staked_committee_size = num_nodes_with_stake; - metadata.overall_safety_properties.num_failed_views = 20; - metadata.overall_safety_properties.num_successful_views = 20; - metadata.overall_safety_properties.expected_views_to_fail = HashMap::from([ - (ViewNumber::new(6), false), - (ViewNumber::new(10), false), - (ViewNumber::new(14), false), - (ViewNumber::new(21), false), - (ViewNumber::new(25), false), - ]); - metadata - }, -); +// let num_nodes_with_stake = 15; +// metadata.num_nodes_with_stake = num_nodes_with_stake; +// metadata.da_staked_committee_size = num_nodes_with_stake; +// metadata.overall_safety_properties.num_failed_views = 20; +// metadata.overall_safety_properties.num_successful_views = 20; +// metadata.overall_safety_properties.expected_views_to_fail = HashMap::from([ +// (ViewNumber::new(6), false), +// (ViewNumber::new(10), false), +// (ViewNumber::new(14), false), +// (ViewNumber::new(21), false), +// (ViewNumber::new(25), false), +// ]); +// metadata +// }, +// ); diff --git a/crates/testing/tests/tests_4/test_with_failures_f.rs b/crates/testing/tests/tests_4/test_with_failures_f.rs index 6ea256fc2d..4fd033d0af 100644 --- a/crates/testing/tests/tests_4/test_with_failures_f.rs +++ b/crates/testing/tests/tests_4/test_with_failures_f.rs @@ -23,7 +23,7 @@ cross_tests!( Ignore: false, Metadata: { let mut metadata = TestDescription::default_more_nodes(); - metadata.overall_safety_properties.num_failed_views = 5; + metadata.overall_safety_properties.num_failed_views = 6; // Make sure we keep committing rounds after the bad leaders, but not the full 50 because of the numerous timeouts metadata.overall_safety_properties.num_successful_views = 20; metadata.num_bootstrap_nodes = 14; diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index e9ad6368b5..9575be6b33 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -48,7 +48,7 @@ serde_bytes = { workspace = true } tagged-base64 = { workspace = true } vbs = { workspace = true } displaydoc = { version = "0.2.5", default-features = false } -dyn-clone = { git = "https://github.com/dtolnay/dyn-clone", tag = "1.0.17" } +dyn-clone = "1.0.17" url = { workspace = true } utils = { path = "../utils" } vec1 = { workspace = true } diff --git a/crates/types/src/consensus.rs b/crates/types/src/consensus.rs index ec872af603..28d488db1c 100644 --- a/crates/types/src/consensus.rs +++ b/crates/types/src/consensus.rs @@ -27,15 +27,15 @@ use crate::{ message::{Proposal, UpgradeLock}, simple_certificate::{DaCertificate, QuorumCertificate}, traits::{ - block_contents::BuilderFee, + block_contents::{BlockHeader, BuilderFee}, metrics::{Counter, Gauge, Histogram, Metrics, NoMetrics}, node_implementation::{ConsensusTime, NodeType, Versions}, signature_key::SignatureKey, BlockPayload, ValidatedState, }, - utils::{BuilderCommitment, StateAndDelta, Terminator}, + utils::{BuilderCommitment, StateAndDelta, Terminator, Terminator::Inclusive}, vid::VidCommitment, - vote::HasViewNumber, + vote::{Certificate, HasViewNumber}, }; /// A type alias for `HashMap, T>` @@ -317,6 +317,9 @@ pub struct Consensus { /// A reference to the metrics trait pub metrics: Arc, + + /// Number of blocks in an epoch, zero means there are no epochs + pub epoch_height: u64, } /// Contains several `ConsensusMetrics` that we're interested in from the consensus interfaces @@ -405,6 +408,7 @@ impl Consensus { saved_payloads: BTreeMap>, high_qc: QuorumCertificate, metrics: Arc, + epoch_height: u64, ) -> Self { Consensus { validated_state_map, @@ -420,6 +424,7 @@ impl Consensus { saved_payloads, high_qc, metrics, + epoch_height, } } @@ -484,7 +489,7 @@ impl Consensus { pub fn update_view(&mut self, view_number: TYPES::View) -> Result<()> { ensure!( view_number > self.cur_view, - "New view isn't newer than the current view." + debug!("New view isn't newer than the current view.") ); self.cur_view = view_number; Ok(()) @@ -496,7 +501,7 @@ impl Consensus { pub fn update_epoch(&mut self, epoch_number: TYPES::Epoch) -> Result<()> { ensure!( epoch_number > self.cur_epoch, - "New epoch isn't newer than the current epoch." + debug!("New epoch isn't newer than the current epoch.") ); self.cur_epoch = epoch_number; Ok(()) @@ -548,7 +553,7 @@ impl Consensus { .last_proposals .last_key_value() .map_or(TYPES::View::genesis(), |(k, _)| { *k }), - "New view isn't newer than the previously proposed view." + debug!("New view isn't newer than the previously proposed view.") ); self.last_proposals .insert(proposal.data.view_number(), proposal); @@ -562,7 +567,7 @@ impl Consensus { pub fn update_last_decided_view(&mut self, view_number: TYPES::View) -> Result<()> { ensure!( view_number > self.last_decided_view, - "New view isn't newer than the previously decided view." + debug!("New view isn't newer than the previously decided view.") ); self.last_decided_view = view_number; Ok(()) @@ -575,7 +580,7 @@ impl Consensus { pub fn update_locked_view(&mut self, view_number: TYPES::View) -> Result<()> { ensure!( view_number > self.locked_view, - "New view isn't newer than the previously locked view." + debug!("New view isn't newer than the previously locked view.") ); self.locked_view = view_number; Ok(()) @@ -604,7 +609,7 @@ impl Consensus { { ensure!( new_delta.is_some() || existing_delta.is_none(), - "Skipping the state update to not override a `Leaf` view with `Some` state delta." + debug!("Skipping the state update to not override a `Leaf` view with `Some` state delta.") ); } else { bail!("Skipping the state update to not override a `Leaf` view with a non-`Leaf` view."); @@ -648,7 +653,7 @@ impl Consensus { pub fn update_high_qc(&mut self, high_qc: QuorumCertificate) -> Result<()> { ensure!( high_qc.view_number > self.high_qc.view_number || high_qc == self.high_qc, - "High QC with an equal or higher view exists." + debug!("High QC with an equal or higher view exists.") ); tracing::debug!("Updating high QC"); self.high_qc = high_qc; @@ -835,6 +840,102 @@ impl Consensus { } Some(()) } + + /// Returns true if the current high qc is for the last block in the epoch + pub fn is_high_qc_for_last_block(&self) -> bool { + let high_qc = self.high_qc(); + self.is_qc_for_last_block(high_qc) + } + + /// Returns true if the given qc is for the last block in the epoch + pub fn is_qc_for_last_block(&self, cert: &QuorumCertificate) -> bool { + let Some(leaf) = self.saved_leaves.get(&cert.data().leaf_commit) else { + return false; + }; + let block_height = leaf.height(); + if block_height == 0 || self.epoch_height == 0 { + false + } else { + block_height % self.epoch_height == 0 + } + } + + /// Returns true if the current high qc is an extended Quorum Certificate + /// The Extended Quorum Certificate (eQC) is the third Quorum Certificate formed in three + /// consecutive views for the last block in the epoch. + pub fn is_high_qc_extended(&self) -> bool { + let high_qc = self.high_qc(); + let ret = self.is_qc_extended(high_qc); + if ret { + tracing::debug!("We have formed an eQC!"); + }; + ret + } + + /// Returns true if the given qc is an extended Quorum Certificate + /// The Extended Quorum Certificate (eQC) is the third Quorum Certificate formed in three + /// consecutive views for the last block in the epoch. + pub fn is_qc_extended(&self, cert: &QuorumCertificate) -> bool { + if !self.is_qc_for_last_block(cert) { + tracing::debug!("High QC is not for the last block in the epoch."); + return false; + } + + let qc_view = cert.view_number(); + let high_qc_block_number = + if let Some(leaf) = self.saved_leaves.get(&cert.data().leaf_commit) { + leaf.block_header().block_number() + } else { + return false; + }; + + let mut last_visited_view_number = qc_view; + let mut is_qc_extended = true; + if let Err(e) = + self.visit_leaf_ancestors(qc_view, Inclusive(qc_view - 2), true, |leaf, _, _| { + tracing::trace!( + "last_visited_view_number = {}, leaf.view_number = {}", + *last_visited_view_number, + *leaf.view_number() + ); + + if leaf.view_number() == qc_view { + return true; + } + + if last_visited_view_number - 1 != leaf.view_number() { + tracing::trace!("The chain is broken. Non consecutive views."); + is_qc_extended = false; + return false; + } + if high_qc_block_number != leaf.height() { + tracing::trace!("The chain is broken. Block numbers do not match."); + is_qc_extended = false; + return false; + } + last_visited_view_number = leaf.view_number(); + true + }) + { + is_qc_extended = false; + tracing::trace!("The chain is broken. Leaf ascension failed."); + tracing::debug!("Leaf ascension failed; error={e}"); + } + tracing::trace!("Is the given QC an eQC? {}", is_qc_extended); + is_qc_extended + } + + /// Return true if the given Quorum Certificate takes part in forming an eQC, i.e. + /// it is one of the 3-chain certificates but not the eQC itself + pub fn is_qc_forming_eqc(&self, cert: &QuorumCertificate) -> bool { + self.is_qc_for_last_block(cert) && !self.is_qc_extended(cert) + } + + /// Return true if the high QC takes part in forming an eQC, i.e. + /// it is one of the 3-chain certificates but not the eQC itself + pub fn is_high_qc_forming_eqc(&self) -> bool { + self.is_high_qc_for_last_block() && !self.is_high_qc_extended() + } } /// Alias for the block payload commitment and the associated metadata. The primary data diff --git a/crates/types/src/constants.rs b/crates/types/src/constants.rs index b4c8a39008..6a1969ae31 100644 --- a/crates/types/src/constants.rs +++ b/crates/types/src/constants.rs @@ -21,7 +21,7 @@ pub const LOOK_AHEAD: u64 = 5; pub const KAD_DEFAULT_REPUB_INTERVAL_SEC: u64 = 28800; /// the number of messages to cache in the combined network -pub const COMBINED_NETWORK_CACHE_SIZE: usize = 1000; +pub const COMBINED_NETWORK_CACHE_SIZE: usize = 200_000; /// the number of messages to attempt to send over the primary network before switching to prefer the secondary network pub const COMBINED_NETWORK_MIN_PRIMARY_FAILURES: u64 = 5; diff --git a/crates/types/src/data.rs b/crates/types/src/data.rs index 71b682aa19..38092e0969 100644 --- a/crates/types/src/data.rs +++ b/crates/types/src/data.rs @@ -373,7 +373,7 @@ pub struct QuorumProposal { /// Possible timeout or view sync certificate. /// - A timeout certificate is only present if the justify_qc is not for the preceding view /// - A view sync certificate is only present if the justify_qc and timeout_cert are not - /// present. + /// present. pub proposal_certificate: Option>, } @@ -817,7 +817,7 @@ pub mod null_block { #[memoize(SharedCache, Capacity: 10)] #[must_use] pub fn commitment(num_storage_nodes: usize) -> Option { - let vid_result = vid_scheme(num_storage_nodes).commit_only(&Vec::new()); + let vid_result = vid_scheme(num_storage_nodes).commit_only(Vec::new()); match vid_result { Ok(r) => Some(r), diff --git a/crates/types/src/traits/node_implementation.rs b/crates/types/src/traits/node_implementation.rs index 43035b01b7..d05652b783 100644 --- a/crates/types/src/traits/node_implementation.rs +++ b/crates/types/src/traits/node_implementation.rs @@ -267,4 +267,7 @@ pub trait Versions: Clone + Copy + Debug + Send + Sync + 'static { /// The version at which to switch over to marketplace logic type Marketplace: StaticVersionType; + + /// The version at which to switch over to epochs logic + type Epochs: StaticVersionType; } diff --git a/crates/types/src/traits/states.rs b/crates/types/src/traits/states.rs index ce93502361..9c951bb8d0 100644 --- a/crates/types/src/traits/states.rs +++ b/crates/types/src/traits/states.rs @@ -41,7 +41,8 @@ pub trait StateDelta: /// * The type of block that modifies this type of state ([`BlockPayload`](`ValidatedStates:: /// BlockPayload`)) /// * The ability to validate that a block header is actually a valid extension of this state and -/// produce a new state, with the modifications from the block applied +/// produce a new state, with the modifications from the block applied +/// /// ([`validate_and_apply_header`](`ValidatedState::validate_and_apply_header)) pub trait ValidatedState: Serialize + DeserializeOwned + Debug + Default + PartialEq + Eq + Send + Sync + Clone diff --git a/crates/types/src/traits/storage.rs b/crates/types/src/traits/storage.rs index d400ce455b..81ba2f66f8 100644 --- a/crates/types/src/traits/storage.rs +++ b/crates/types/src/traits/storage.rs @@ -13,6 +13,7 @@ use std::collections::BTreeMap; use anyhow::Result; use async_trait::async_trait; +use jf_vid::VidScheme; use super::node_implementation::NodeType; use crate::{ @@ -21,6 +22,7 @@ use crate::{ event::HotShotAction, message::Proposal, simple_certificate::{QuorumCertificate, UpgradeCertificate}, + vid::VidSchemeType, }; /// Abstraction for storing a variety of consensus payload datum. @@ -29,7 +31,11 @@ pub trait Storage: Send + Sync + Clone { /// Add a proposal to the stored VID proposals. async fn append_vid(&self, proposal: &Proposal>) -> Result<()>; /// Add a proposal to the stored DA proposals. - async fn append_da(&self, proposal: &Proposal>) -> Result<()>; + async fn append_da( + &self, + proposal: &Proposal>, + vid_commit: ::Commit, + ) -> Result<()>; /// Add a proposal we sent to the store async fn append_proposal( &self, diff --git a/crates/types/src/vid.rs b/crates/types/src/vid.rs index 7d3bfb21a7..b36eaf2020 100644 --- a/crates/types/src/vid.rs +++ b/crates/types/src/vid.rs @@ -322,6 +322,7 @@ impl Precomputable for VidSchemeType { /// Foreign type rules prevent us from doing: /// - `impl From> for VidDisperse` /// - `impl VidDisperse {...}` +/// /// and similarly for `Statement`. /// Thus, we accomplish type conversion via functions. fn vid_disperse_conversion(vid_disperse: VidDisperse) -> VidDisperse { diff --git a/docs/diagrams/event_discriptions/QuorumProposalRecv.md b/docs/diagrams/event_discriptions/QuorumProposalRecv.md index 4ef1fb287b..4497ad0c18 100644 --- a/docs/diagrams/event_discriptions/QuorumProposalRecv.md +++ b/docs/diagrams/event_discriptions/QuorumProposalRecv.md @@ -15,7 +15,7 @@ * If `ViewSyncCommitCertificate`s are not included in the `QuorumProposal` it is possible for honest nodes to reject valid proposals. For example, a view leader may receive the `ViewSyncCommitCertificate` from the view sync relay, update its local view, and send a `QuorumProposal` for the new view. But other nodes may not have received the `ViewSyncCommitCertificate` yet (either through genuine network delays or Byzantine behavior by the view sync relay). Thus, the other nodes will not be able to process the `QuorumProposal` since they do not have evidence the network has advanced to the view in the `ViewSyncCommitCertificate`. These nodes would either need to reject the proposal outright, or wait to process the proposal until they receive the `ViewSyncCommitCertificate`. The former behavior would cause unnecessary view failures, and the latter would add complexity to the code. Including the `ViewSyncCommitCertificate` in the `QuorumProposal` addresses both these concerns. * It is possible for a node to receive multiple `ViewSyncCommitCertificate`s: one from the view sync relay and one from the view leader. Therefore processing this certificate must be idempotent. * It is possible (and valid) for a node to receive valid view change evidence but an invalid `QuorumProposal`. There are several ways to handle this scenario, but we choose to allow nodes to update their `latest_known_view` even if other validation of the proposal fails. This helps the network maintain view synchronization in spite of invalid proposals. -* It is possible for a `QuorumProposal` to have valid view change evidence from a `TimeoutCertificate` or `ViewSyncCommitCertificate`, but to have an invalid `QurorumCertificate`. It would be valid to update the view in this case, since there exists valid view change evidence. But for simplicity, we choose not to. If view change evidence is valid but the `QuorumCertificate` associated with the proposal is invalid nodes will not update their view. +* It is possible for a `QuorumProposal` to have valid view change evidence from a `TimeoutCertificate` or `ViewSyncCommitCertificate`, but to have an invalid `QuorumCertificate`. It would be valid to update the view in this case, since there exists valid view change evidence. But for simplicity, we choose not to. If view change evidence is valid but the `QuorumCertificate` associated with the proposal is invalid nodes will not update their view. ## Proposal Validation * This proposal validation represents the [HotStuff-2](https://eprint.iacr.org/2023/397.pdf) protocol. diff --git a/flake.lock b/flake.lock index 1bc6b5b40a..d5f4495ab2 100644 --- a/flake.lock +++ b/flake.lock @@ -41,11 +41,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1729924178, - "narHash": "sha256-ZhDqOYZwx0kYg1vPrmZ2fJm/wem739eNSSK+GlzdeqA=", + "lastModified": 1730529264, + "narHash": "sha256-5gC0y6cKXKQvumK4jOhKyjVsYqQ7EOcWKNtKB8UiP74=", "owner": "nix-community", "repo": "fenix", - "rev": "e831b4d256526cc56bd37c7c579842866410bebc", + "rev": "fff718e230e40b8202d7be6223c13492bb0010a8", "type": "github" }, "original": { @@ -72,11 +72,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1729850857, - "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=", + "lastModified": 1730272153, + "narHash": "sha256-B5WRZYsRlJgwVHIV6DvidFN7VX7Fg9uuwkRW9Ha8z+w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "41dea55321e5a999b17033296ac05fe8a8b5a257", + "rev": "2d2a9ddbe3f2c00747398f3dc9b05f7f2ebb0f53", "type": "github" }, "original": { @@ -99,11 +99,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1729845655, - "narHash": "sha256-6I3gJLnOLnUIWFUlEnvC0FdzX8Xwu+y3Vo0q4VB6Wbk=", + "lastModified": 1730463978, + "narHash": "sha256-9X/n9cC50NGVQVcfhOZPd26XGPR7GRxZhCo6z0Fclbo=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "f4466718b838de706d74e2c13f20a41c034d87a5", + "rev": "d1fbfc676bf91f44de6a19c86435ac4dbd390549", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d67b176017..f886824290 100644 --- a/flake.nix +++ b/flake.nix @@ -47,7 +47,7 @@ ]) (fenix.packages.${system}.fromToolchainFile { dir = ./.; - sha256 = "sha256-opUgs6ckUQCyDxcB9Wy51pqhd0MPGHUVbwRKKPGiwZU="; + sha256 = "sha256-yMuSb5eQPO/bHv+Bcf/US8LVMbf/G/0MSfiPwBhiPpk="; }) ]; # needed for compiling static binary diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8ef5943242..41ef0232fd 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.78" +channel = "1.82" components = [ "cargo", "clippy", "rust-src", "rustc", "rustfmt", "llvm-tools-preview" ]