From 87fc63d6fbb41361dea2258ea8cf2684034127ed Mon Sep 17 00:00:00 2001 From: Fi3 Date: Tue, 28 May 2024 10:01:10 +0200 Subject: [PATCH] Revert "Release 1.0.1 (#925)" This reverts commit 19d622126f59453590e68112ab62975ab1d91b50. --- .github/workflows/coverage.yaml | 75 +- .github/workflows/release-bin.yaml | 159 +- .github/workflows/release-libs.yaml | 4 +- .github/workflows/run-benchmarks.yaml | 1 - .gitignore | 4 +- RELEASE.md | 12 +- benches/Cargo.lock | 9 +- benches/Cargo.toml | 2 +- check-versioning-lib-release.sh | 11 +- code-coverage-report.sh | 4 - common/Cargo.lock | 88 +- common/Cargo.toml | 1 - common/src/lib.rs | 1 - examples/ping-pong-with-noise/Cargo.toml | 2 +- git-branching.png | Bin 63551 -> 61654 bytes message-generator-tests.sh | 21 +- protocols/Cargo.lock | 224 +-- protocols/v2/codec-sv2/Cargo.toml | 4 +- protocols/v2/codec-sv2/src/lib.rs | 4 +- protocols/v2/framing-sv2/Cargo.toml | 2 +- protocols/v2/framing-sv2/src/framing2.rs | 139 +- protocols/v2/framing-sv2/src/header.rs | 8 - protocols/v2/framing-sv2/src/lib.rs | 42 +- protocols/v2/roles-logic-sv2/Cargo.toml | 4 +- roles/Cargo.lock | 417 ++--- roles/jd-client/Cargo.toml | 6 +- roles/jd-client/README.md | 46 +- roles/jd-client/src/args.rs | 11 +- roles/jd-client/src/lib/downstream.rs | 16 +- .../src/lib/job_declarator/message_handler.rs | 4 +- roles/jd-client/src/lib/job_declarator/mod.rs | 68 +- roles/jd-server/Cargo.toml | 5 +- .../src/lib/job_declarator/message_handler.rs | 91 +- roles/jd-server/src/lib/job_declarator/mod.rs | 13 +- roles/jd-server/src/lib/mempool/error.rs | 19 +- roles/jd-server/src/lib/mempool/mod.rs | 69 +- roles/jd-server/src/main.rs | 4 + roles/mining-proxy/Cargo.toml | 4 +- .../config-examples/proxy-config-example.toml | 1 + roles/pool/Cargo.toml | 5 +- roles/pool/README.md | 60 +- .../pool-config-local-tp-example.toml | 1 + roles/pool/src/lib/mining_pool/mod.rs | 20 +- roles/roles-utils/network-helpers/Cargo.toml | 2 +- roles/roles-utils/network-helpers/src/lib.rs | 2 - .../src/noise_connection_async_std.rs | 2 +- .../src/noise_connection_tokio.rs | 2 +- roles/test-utils/mining-device/Cargo.toml | 9 +- roles/test-utils/mining-device/src/main.rs | 260 +-- roles/translator/Cargo.toml | 6 +- roles/translator/README.md | 41 +- .../tproxy-config-hosted-pool-example.toml | 36 - .../tproxy-config-local-jdc-example.toml | 1 + .../tproxy-config-local-pool-example.toml | 1 + roles/translator/src/args.rs | 11 +- roles/translator/src/main.rs | 2 +- .../bad-pool-config-test.json | 5 +- .../bad-pool-config-test.sh | 9 - .../interop-jd-translator.json | 0 .../interop-jd-translator.sh | 13 - .../interop-jdc-change-upstream.json | 6 - .../interop-jdc-change-upstream.sh | 12 - ...interop-proxy-with-multi-ups-extended.json | 0 .../interop-proxy-with-multi-ups-extended.sh | 11 - .../interop-proxy-with-multi-ups.json | 0 .../interop-proxy-with-multi-ups.sh | 11 - .../jds-do-not-fail-on-wrong-tsdatasucc.json | 0 .../jds-do-not-fail-on-wrong-tsdatasucc.sh | 9 - ...-do-not-panic-if-jdc-close-connection.json | 0 ...ds-do-not-panic-if-jdc-close-connection.sh | 9 - ...ds-do-not-stackoverflow-when-no-token.json | 0 .../jds-do-not-stackoverflow-when-no-token.sh | 11 - .../pool-sri-test-1-standard.json | 73 +- .../pool-sri-test-1-standard.sh | 9 - .../pool-sri-test-close-channel.json | 5 - .../pool-sri-test-close-channel.sh | 9 - .../pool-sri-test-extended_0.json | 0 .../pool-sri-test-extended_0.sh | 7 - .../pool-sri-test-extended_1.json | 0 .../pool-sri-test-extended_1.sh | 9 - .../pool-sri-test-reject-auth.json | 2 +- .../pool-sri-test-reject-auth.sh | 9 - .../standard-coverage-test.json | 21 + .../standard-coverage-test.sh | 9 - .../test/{sv1-test => }/sv1-test.json | 11 - .../test/sv1-test/sv1-test.sh | 10 - .../translation-proxy-broke-pool.json | 6 - .../translation-proxy-broke-pool.sh | 9 - .../translation-proxy.json | 10 - .../translation-proxy/translation-proxy.sh | 10 - utils/Cargo.lock | 1494 ++++++++++++++-- utils/key-utils/Cargo.toml | 2 +- utils/key-utils/src/lib.rs | 51 +- utils/message-generator/Cargo.lock | 1513 +++++++++++++++++ utils/message-generator/Cargo.toml | 4 +- utils/message-generator/README.md | 1 - utils/message-generator/src/main.rs | 19 +- 97 files changed, 3606 insertions(+), 1839 deletions(-) delete mode 100755 code-coverage-report.sh delete mode 100644 roles/translator/config-examples/tproxy-config-hosted-pool-example.toml rename test/message-generator/test/{bad-pool-config-test => }/bad-pool-config-test.json (98%) delete mode 100755 test/message-generator/test/bad-pool-config-test/bad-pool-config-test.sh rename test/message-generator/test/{interop-jd-translator => }/interop-jd-translator.json (100%) delete mode 100755 test/message-generator/test/interop-jd-translator/interop-jd-translator.sh rename test/message-generator/test/{interop-jdc-change-upstream => }/interop-jdc-change-upstream.json (97%) delete mode 100755 test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.sh rename test/message-generator/test/{interop-proxy-with-multi-ups-extended => }/interop-proxy-with-multi-ups-extended.json (100%) delete mode 100755 test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.sh rename test/message-generator/test/{interop-proxy-with-multi-ups => }/interop-proxy-with-multi-ups.json (100%) delete mode 100755 test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.sh rename test/message-generator/test/{jds-do-not-fail-on-wrong-tsdatasucc => }/jds-do-not-fail-on-wrong-tsdatasucc.json (100%) delete mode 100755 test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.sh rename test/message-generator/test/{jds-do-not-panic-if-jdc-close-connection => }/jds-do-not-panic-if-jdc-close-connection.json (100%) delete mode 100755 test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.sh rename test/message-generator/test/{jds-do-not-stackoverflow-when-no-token => }/jds-do-not-stackoverflow-when-no-token.json (100%) delete mode 100755 test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.sh rename test/message-generator/test/{pool-sri-test-1-standard => }/pool-sri-test-1-standard.json (78%) delete mode 100755 test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.sh rename test/message-generator/test/{pool-sri-test-close-channel => }/pool-sri-test-close-channel.json (96%) delete mode 100755 test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.sh rename test/message-generator/test/{pool-sri-test-extended_0 => }/pool-sri-test-extended_0.json (100%) delete mode 100755 test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.sh rename test/message-generator/test/{pool-sri-test-extended_1 => }/pool-sri-test-extended_1.json (100%) delete mode 100755 test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.sh rename test/message-generator/test/{pool-sri-test-reject-auth => }/pool-sri-test-reject-auth.json (98%) delete mode 100755 test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.sh rename test/message-generator/test/{standard-coverage-test => }/standard-coverage-test.json (89%) delete mode 100755 test/message-generator/test/standard-coverage-test/standard-coverage-test.sh rename test/message-generator/test/{sv1-test => }/sv1-test.json (94%) delete mode 100755 test/message-generator/test/sv1-test/sv1-test.sh rename test/message-generator/test/{translation-proxy-broke-pool => }/translation-proxy-broke-pool.json (95%) delete mode 100755 test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.sh rename test/message-generator/test/{translation-proxy => }/translation-proxy.json (96%) delete mode 100755 test/message-generator/test/translation-proxy/translation-proxy.sh create mode 100644 utils/message-generator/Cargo.lock diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index b35d1974ef..252a77af14 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -33,14 +33,14 @@ jobs: options: --security-opt seccomp=unconfined steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v3 - name: Generate code coverage run: | ./tarpaulin.sh - name: Archive Tarpaulin code coverage results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: tarpaulin-report path: | @@ -56,7 +56,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: @@ -70,69 +70,26 @@ jobs: - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - - name: Run bad-pool-config-test - run: sh ./test/message-generator/test/bad-pool-config-test/bad-pool-config-test.sh - - - name: Run interop-jd-translator - run: sh ./test/message-generator/test/interop-jd-translator/interop-jd-translator.sh - - #- name: Run interop-jdc-change-upstream - # run: sh ./test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.sh - - - name: Run interop-proxy-with-multi-ups - run: sh ./test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.sh - - - name: Run interop-proxy-with-multi-ups-extended - run: sh ./test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.sh - - - name: Run jds-do-not-fail-on-wrong-tsdatasucc - run: sh ./test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.sh - - - name: Run jds-do-not-panic-if-jdc-close-connection - run: sh ./test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.sh - - - name: Run jds-do-not-stackoverflow-when-no-token - run: sh ./test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.sh - - - name: Run pool-sri-test-1-standard - run: sh ./test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.sh - - - name: Run pool-sri-test-close-channel - run: sh ./test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.sh - - - name: Run pool-sri-test-extended_0 - run: sh ./test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.sh - - - name: Run pool-sri-test-extended_1 - run: sh ./test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.sh - - - name: Run pool-sri-test-reject-auth - run: sh ./test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.sh - - - name: Run standard-coverage - run: sh ./test/message-generator/test/standard-coverage-test/standard-coverage-test.sh - - - name: Run sv1-test - run: sh ./test/message-generator/test/sv1-test/sv1-test.sh - - - name: Run translation-proxy-broke-pool - run: sh ./test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.sh - - - name: Run translation-proxy - run: sh ./test/message-generator/test/translation-proxy/translation-proxy.sh + - name: Pre build everything + run: | + cargo build --manifest-path=benches/Cargo.toml + cargo build --manifest-path=common/Cargo.toml + cargo build --manifest-path=protocols/Cargo.toml + cargo build --manifest-path=roles/Cargo.toml + cargo build --manifest-path=utils/Cargo.toml - - name: Coverage report - run: sh ./code-coverage-report.sh + - name: Run message generator tests + run: sh ./message-generator-tests.sh - name: Archive MG code coverage results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: coverage-report path: 'target/*.xml' - name: Archive log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: logs path: './utils/message-generator/*.log' @@ -146,10 +103,10 @@ jobs: # steps: # - name: Checkout repository - # uses: actions/checkout@v4 + # uses: actions/checkout@v3 # - name: Download all workflow run artifacts - # uses: actions/download-artifact@v4 + # uses: actions/download-artifact@v3 # - name: Display structure of downloaded files # run: ls -R diff --git a/.github/workflows/release-bin.yaml b/.github/workflows/release-bin.yaml index 1ff1b896ae..253554eb48 100644 --- a/.github/workflows/release-bin.yaml +++ b/.github/workflows/release-bin.yaml @@ -15,26 +15,15 @@ jobs: matrix: os: [ubuntu-20.04, macos-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - + - name: Compile Native run: cargo build --release --locked --manifest-path=roles/pool/Cargo.toml - - name: Install cross - run: cargo install cross - - - name: Compile Binaries for aarch64-unknown-linux-gnu - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/pool/Cargo.toml --target aarch64-unknown-linux-gnu - - - name: Compile Binaries for arm-unknown-linux-gnueabi - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/pool/Cargo.toml --target arm-unknown-linux-gnueabi - - name: Install aarch64-apple-darwin target if: matrix.os == 'macos-latest' run: rustup target add aarch64-apple-darwin @@ -60,24 +49,6 @@ jobs: file: roles/target/release/pool_sv2 asset_name: pool_sv2-x86_64-apple-darwin tag: ${{ github.ref }} - - - name: Upload Linux aarch64 binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/aarch64-unknown-linux-gnu/release/pool_sv2 - asset_name: pool_sv2-aarch64-linux-gnu - tag: ${{ github.ref }} - - - name: Upload Linux ARM binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/arm-unknown-linux-gnueabi/release/pool_sv2 - asset_name: pool_sv2-arm-linux-gnueabi - tag: ${{ github.ref }} - name: Upload MacOS ARM64 binaries to release if: matrix.os == 'macos-latest' @@ -94,7 +65,7 @@ jobs: matrix: os: [ ubuntu-20.04, macos-latest ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -102,17 +73,6 @@ jobs: - name: Compile Native run: cargo build --release --locked --manifest-path=roles/jd-client/Cargo.toml - - - name: Install cross - run: cargo install cross - - - name: Compile Binaries for aarch64-unknown-linux-gnu - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/jd-client/Cargo.toml --target aarch64-unknown-linux-gnu - - - name: Compile Binaries for arm-unknown-linux-gnueabi - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/jd-client/Cargo.toml --target arm-unknown-linux-gnueabi - name: Install aarch64-apple-darwin target if: matrix.os == 'macos-latest' @@ -130,24 +90,6 @@ jobs: file: roles/target/release/jd_client asset_name: jd_client-x86_64-linux-gnu tag: ${{ github.ref }} - - - name: Upload Linux aarch64 binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/aarch64-unknown-linux-gnu/release/jd_client - asset_name: jd_client-aarch64-linux-gnu - tag: ${{ github.ref }} - - - name: Upload Linux ARM binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/arm-unknown-linux-gnueabi/release/jd_client - asset_name: jd_client-arm-linux-gnueabi - tag: ${{ github.ref }} - name: Upload MacOS x86-64 binaries to release if: matrix.os == 'macos-latest' @@ -173,7 +115,7 @@ jobs: matrix: os: [ ubuntu-20.04, macos-latest ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -181,17 +123,6 @@ jobs: - name: Compile Native run: cargo build --release --locked --manifest-path=roles/jd-server/Cargo.toml - - - name: Install cross - run: cargo install cross - - - name: Compile Binaries for aarch64-unknown-linux-gnu - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/jd-server/Cargo.toml --target aarch64-unknown-linux-gnu - - - name: Compile Binaries for arm-unknown-linux-gnueabi - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/jd-server/Cargo.toml --target arm-unknown-linux-gnueabi - name: Install aarch64-apple-darwin target if: matrix.os == 'macos-latest' @@ -209,24 +140,6 @@ jobs: file: roles/target/release/jd_server asset_name: jd_server-x86_64-linux-gnu tag: ${{ github.ref }} - - - name: Upload Linux aarch64 binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/aarch64-unknown-linux-gnu/release/jd_server - asset_name: jd_server-aarch64-linux-gnu - tag: ${{ github.ref }} - - - name: Upload Linux ARM binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/arm-unknown-linux-gnueabi/release/jd_server - asset_name: jd_server-arm-linux-gnueabi - tag: ${{ github.ref }} - name: Upload MacOS x86-64 binaries to release if: matrix.os == 'macos-latest' @@ -252,7 +165,7 @@ jobs: matrix: os: [ ubuntu-20.04, macos-latest ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -260,17 +173,6 @@ jobs: - name: Compile Native run: cargo build --release --locked --manifest-path=roles/mining-proxy/Cargo.toml - - - name: Install cross - run: cargo install cross - - - name: Compile Binaries for aarch64-unknown-linux-gnu - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/mining-proxy/Cargo.toml --target aarch64-unknown-linux-gnu - - - name: Compile Binaries for arm-unknown-linux-gnueabi - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/mining-proxy/Cargo.toml --target arm-unknown-linux-gnueabi - name: Install aarch64-apple-darwin target if: matrix.os == 'macos-latest' @@ -288,24 +190,6 @@ jobs: file: roles/target/release/mining_proxy_sv2 asset_name: mining_proxy_sv2-x86_64-linux-gnu tag: ${{ github.ref }} - - - name: Upload Linux aarch64 binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/aarch64-unknown-linux-gnu/release/mining_proxy_sv2 - asset_name: mining_proxy_sv2-aarch64-linux-gnu - tag: ${{ github.ref }} - - - name: Upload Linux ARM binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/arm-unknown-linux-gnueabi/release/mining_proxy_sv2 - asset_name: mining_proxy_sv2-arm-linux-gnueabi - tag: ${{ github.ref }} - name: Upload MacOS x86-64 binaries to release if: matrix.os == 'macos-latest' @@ -331,7 +215,7 @@ jobs: matrix: os: [ ubuntu-20.04, macos-latest ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -339,17 +223,6 @@ jobs: - name: Compile Native run: cargo build --release --locked --manifest-path=roles/translator/Cargo.toml - - - name: Install cross - run: cargo install cross - - - name: Compile Binaries for aarch64-unknown-linux-gnu - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/translator/Cargo.toml --target aarch64-unknown-linux-gnu - - - name: Compile Binaries for arm-unknown-linux-gnueabi - if: matrix.os == 'ubuntu-20.04' - run: cross build --release --locked --manifest-path=roles/translator/Cargo.toml --target arm-unknown-linux-gnueabi - name: Install aarch64-apple-darwin target if: matrix.os == 'macos-latest' @@ -367,24 +240,6 @@ jobs: file: roles/target/release/translator_sv2 asset_name: translator_sv2-x86_64-linux-gnu tag: ${{ github.ref }} - - - name: Upload Linux aarch64 binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/aarch64-unknown-linux-gnu/release/translator_sv2 - asset_name: translator_sv2-aarch64-linux-gnu - tag: ${{ github.ref }} - - - name: Upload Linux ARM binaries to release - if: matrix.os == 'ubuntu-20.04' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: roles/target/arm-unknown-linux-gnueabi/release/translator_sv2 - asset_name: translator_sv2-arm-linux-gnueabi - tag: ${{ github.ref }} - name: Upload MacOS x86-64 binaries to release if: matrix.os == 'macos-latest' @@ -402,4 +257,4 @@ jobs: repo_token: ${{ secrets.GITHUB_TOKEN }} file: roles/target/aarch64-apple-darwin/release/translator_sv2 asset_name: translator_sv2-aarch64-apple-darwin - tag: ${{ github.ref }} + tag: ${{ github.ref }} \ No newline at end of file diff --git a/.github/workflows/release-libs.yaml b/.github/workflows/release-libs.yaml index ac7883dbaa..9ab285ef41 100644 --- a/.github/workflows/release-libs.yaml +++ b/.github/workflows/release-libs.yaml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v3 - name: Run check-versioning-lib-release.sh run: | @@ -30,7 +30,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable diff --git a/.github/workflows/run-benchmarks.yaml b/.github/workflows/run-benchmarks.yaml index 150188218e..feec5a5e6f 100644 --- a/.github/workflows/run-benchmarks.yaml +++ b/.github/workflows/run-benchmarks.yaml @@ -4,7 +4,6 @@ on: pull_request: branches: - main - - dev jobs: benchmark_sv1_criterion: diff --git a/.gitignore b/.gitignore index 6121487a25..341e3cd477 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,9 @@ .idea -*/**/target +*/target /protocols/guix-example/guix-example.h /ignore /vendor/ed25519-dalek/target /utils/buffer/target -/utils/message-generator/Cargo.lock /sv2.h /test/bitcoin_data/regtest lcov.info @@ -14,4 +13,3 @@ lcov.info **/conf/** cobertura.xml /roles/*/*-config.toml -/examples/*/Cargo.lock diff --git a/RELEASE.md b/RELEASE.md index 1dc101018c..ff0a187de5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -30,11 +30,11 @@ The SRI repo holds two principal branches with an infinite lifetime: - `main` - `dev` -We consider `main` to be the branch where the source code of `HEAD` always reflects the latest release. +We consider `main` to be the branch where the source code of `HEAD` always reflects a production-ready state. -We consider `dev` to be the branch where the source code of `HEAD` always reflects the latest changes in the development cycle. +We consider `dev` to be the branch where the source code of `HEAD` always reflects a state with the latest delivered development changes for the next release. -The SRI team will decide the appropriate time when the changes to `dev` are merged back into `main` and then tagged with a release number while bumping `MAJOR`, `MINOR`, or `PATCH`. +The SRI team will decide the appropriate time when the changes to `dev` are merged back into `main` and then tagged with a release number while bumping `MAJOR` and/or `MINOR`. ## Feature Branches @@ -48,8 +48,8 @@ New features are developed into separate branches that only live in the contribu Bugs are patched into separate branches that only live in the contributor's forks. -- branch off from: `dev` -- merge back into: `dev` +- branch off from: `main` +- merge back into: `main` + `dev` - naming convention: `patch-x`, where `x` describes the bug/patch # Releasing Roles Binaries @@ -72,7 +72,7 @@ If a crate is not updated successfully, the step will fail, but since all steps Since steps can fail, the output of the action must be manually checked. -Every PR to `main` needs to increase the version of whatever crate it is touching. Otherwise, we will mess up the dependency chain of whoever is fetching from crates.io +Every PR to `main` (either coming from `dev`, or a patch) needs to increase the version of whatever crate it is touching. Otherwise, we will mess up the dependency chain of whoever is fetching from crates.io Manually running `cargo release` in the various workspaces helps to prepare the version number before the releases are published. diff --git a/benches/Cargo.lock b/benches/Cargo.lock index 946b7c02b8..8221e73c70 100644 --- a/benches/Cargo.lock +++ b/benches/Cargo.lock @@ -497,7 +497,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "codec_sv2" -version = "1.1.0" +version = "1.0.0" dependencies = [ "binary_sv2", "buffer_sv2", @@ -728,7 +728,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "framing_sv2" -version = "1.1.0" +version = "1.0.0" dependencies = [ "binary_sv2", "const_sv2", @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "network_helpers_sv2" -version = "2.0.0" +version = "1.0.0" dependencies = [ "async-channel 1.9.0", "async-std", @@ -1377,7 +1377,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "roles_logic_sv2" -version = "1.1.0" +version = "1.0.0" dependencies = [ "binary_sv2", "chacha20poly1305", @@ -1553,7 +1553,6 @@ name = "stratum-common" version = "1.0.0" dependencies = [ "bitcoin 0.29.2", - "secp256k1 0.28.2", ] [[package]] diff --git a/benches/Cargo.toml b/benches/Cargo.toml index ecba50ab8b..f9adf44d6c 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -12,7 +12,7 @@ serde_json = { version = "1.0.64", default-features = false, features = ["alloc" iai="0.1" mining_sv2 = { path = "../protocols/v2/subprotocols/mining", version = "^1.0.0" } roles_logic_sv2 = { path = "../protocols/v2/roles-logic-sv2", version = "^1.0.0" } -framing_sv2 = { version = "1.1.0", path = "../protocols/v2/framing-sv2" } +framing_sv2 = { version = "1.0.0", path = "../protocols/v2/framing-sv2" } serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] } num-bigint = "0.4.3" num-traits = "0.2.15" diff --git a/check-versioning-lib-release.sh b/check-versioning-lib-release.sh index 5fdf6eb912..6d2bcc7942 100755 --- a/check-versioning-lib-release.sh +++ b/check-versioning-lib-release.sh @@ -1,6 +1,7 @@ #!/bin/bash -git fetch --all +git fetch origin main +git fetch origin dev crates=( "utils/buffer" @@ -35,10 +36,6 @@ crates=( for crate in "${crates[@]}"; do cd "$crate" - # Check if the branches exist locally, if not, create them - git show-ref --verify --quiet refs/remotes/origin/main || { echo "Branch 'main' not found."; exit 1; } - git show-ref --verify --quiet refs/remotes/origin/dev || { echo "Branch 'dev' not found."; exit 1; } - # Check if there were any changes between dev and main git diff --quiet "origin/dev" "origin/main" -- . if [ $? -ne 0 ]; then @@ -47,12 +44,8 @@ for crate in "${crates[@]}"; do version_dev=$(git show origin/dev:./Cargo.toml | awk -F' = ' '$1 == "version" {gsub(/[ "]+/, "", $2); print $2}') version_main=$(git show origin/main:./Cargo.toml | awk -F' = ' '$1 == "version" {gsub(/[ "]+/, "", $2); print $2}') if [ "$version_dev" = "$version_main" ]; then - # this prevents the release PR from being merged, since we do `exit 1`, effectively stopping the Github CI echo "Changes detected in crate $crate between dev and main branches! Versions on dev and main branches are identical ($version_dev), so you should bump the crate version on dev before merging into main." exit 1 - else - # this creates a log of version changes, useful for release logs - echo "Changes detected in crate $crate between dev and main branches! Version in dev is: ($version_dev), while version in main is ($version_main)." fi fi diff --git a/code-coverage-report.sh b/code-coverage-report.sh deleted file mode 100755 index f54828ce00..0000000000 --- a/code-coverage-report.sh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh - -cd roles -RUST_LOG=debug cargo llvm-cov --ignore-filename-regex "utils/message-generator/|experimental/|protocols/" --cobertura --output-path "target/mg_coverage.xml" report diff --git a/common/Cargo.lock b/common/Cargo.lock index 0d9e63408d..ad03258e2f 100644 --- a/common/Cargo.lock +++ b/common/Cargo.lock @@ -16,7 +16,7 @@ checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ "bech32", "bitcoin_hashes", - "secp256k1 0.24.3", + "secp256k1", ] [[package]] @@ -27,68 +27,18 @@ checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "cfg-if", "libc", - "wasi", ] [[package]] name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "secp256k1" @@ -97,17 +47,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "bitcoin_hashes", - "secp256k1-sys 0.6.1", -] - -[[package]] -name = "secp256k1" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" -dependencies = [ - "rand", - "secp256k1-sys 0.9.2", + "secp256k1-sys", ] [[package]] @@ -119,25 +59,9 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-sys" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" -dependencies = [ - "cc", -] - [[package]] name = "stratum-common" version = "1.0.0" dependencies = [ "bitcoin", - "secp256k1 0.28.2", ] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/common/Cargo.toml b/common/Cargo.toml index 3b9d7cc2cd..0ad48861f1 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,4 +8,3 @@ repository = "https://github.com/stratum-mining/stratum" [dependencies] bitcoin = {version="0.29.1",optional=true} -secp256k1 = { version = "0.28.2", default-features = false, features =["alloc","rand","rand-std"] } diff --git a/common/src/lib.rs b/common/src/lib.rs index 242c7acb35..74b0562c91 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,4 +4,3 @@ //! and manage the shared dependencies and utils across stratum crates. #[cfg(feature = "bitcoin")] pub use bitcoin; -pub use secp256k1; diff --git a/examples/ping-pong-with-noise/Cargo.toml b/examples/ping-pong-with-noise/Cargo.toml index b1220bce7d..0e984b0e59 100644 --- a/examples/ping-pong-with-noise/Cargo.toml +++ b/examples/ping-pong-with-noise/Cargo.toml @@ -15,7 +15,7 @@ async-std="1.8.0" bytes = "1.0.1" binary_sv2 = { version = "^1.0.0", path = "../../protocols/v2/binary-sv2/binary-sv2" } codec_sv2 = { version = "^1.0.0", path = "../../protocols/v2/codec-sv2", features=["noise_sv2"] } -network_helpers_sv2 = { version = "^2.0.0", path = "../../roles/roles-utils/network-helpers", features=["async_std"] } +network_helpers_sv2 = { version = "^1.0.0", path = "../../roles/roles-utils/network-helpers", features=["async_std"] } key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } [features] diff --git a/git-branching.png b/git-branching.png index 1337f45ea1d4b18a23d7fb665882b22cc286bf88..0312c7fb006fe2f1fdd2993c0072a4a797309d18 100644 GIT binary patch literal 61654 zcmd?Rc{tQ<`vBc~@4pa<`z(OF07r-7VYX?%ckRT6MvE)&M@Vyc+%^ zo86rqDOT4>(DYbYkI0U=Ry5kUs@Rz^@xrD|0=yEu)GaaMdF+4xIbzU})!QS;{iQBy zuLyk0?~fVKwsC*H+?OlH{rSlLo-_BSE^ODoK2Y-i-w(*z4wTwW;^#pRx}tlt5#JZ}>wB9!k-ehAW-*tcN1P{HlSq$^ zq-Sw_JnxDtDtdNEpB;1|*wv4PWvYLB#mlA?Cm{_6dTT*MekeJR1^89`pcj03J0?3GeN24l$2&zO>XG>c+toC36d)Ai4pX&`uUc- zd_v0ffwB|BbvHlmUPf>HYRjG}NO!I>slPefSFrM;7vaX7ql6JOCt8yv6UH-9mkHln zCEeSf$-PhRWvz}!b~mq0XS(;jG=5)~dRPKJ(~b5|S?ViD$bkB16S0VH*8XABnZGo{ zd@2{nMW*#__$7IkR($k;M~_GEjLpyP74^ItlO^Mh)d{4FkAo`XN~RjAvHLsBf?Nrx)rc>ZTG+sXnQ8SevpcxA(7NczvJx7>&RgG*_Mc@&z3> z!}6==je&9}?}?^lYJ)U7>c_*e@Sop4zh6l}X@-|0Oj*&#E8FeNwPyNe- zL(0xZP=Vp2!deWoO5Zu?Nd^0w3Y`=g9c|W=x|Fg3`q6VCd-BmsgjMJ24#lQHqJK3> zZN**Jbun3U@e~Bse>^PtzL2C}omoh(E&E3JpljUqrEdRe!b05$YQHecPX9fqEx zV8yn%LXZjB4hg6rdf}^xg<9%7%hm-!@k?05^6xYk7?^nxe5De>SVKYmooiC`aLz^$ z23*Nc2a%kj%{u-A)|$9qy>EZOt1a)H{ed~1SmAsvDauxccn_ScL$lo1w#e{2xj>x( zqwL&|{Plgs-li$cH&SYyjON_LVUxEmjD=75){O>rT&HSEO~PzLeN+6%Ki&u`4f-aC zDb-Ow(bSycHaM$9u`K;uTO2OPJ3*oD_^^Kyn2JxrF)_GO%g--)%54huqd^Hn6|VZd zEyuENT{qw3Q=g(&zG9v+N} zz&6T$q~Pr;xspO#Q;+ZoM0oWEXFXGi_^WRbTU3MOETes6)+n|vL!od~6fHMym}iQQ zWu~xj0@r-qpNGSu5{E;NP#9?t2If@r90uE|xzv0^BZPLX9xPs`U(-^{`h2AAcAK&y z0f(^=pLjund?FgjiEzM{beDIRFyUVojx*+dA=f%w=GVq}4kbxIs@mue>yxSBKfq{* z`TroYD7g6K@LbzmE9e!B>t9g67iH&q;B4s^aOT|5lHEkUpE83zTkWZ1`=LovQR}%` z(*3S6A`Cg*`~~B!Zu6 z2=AXf#znV_>4V}PFUy}WT+VjYEfEE-N4xU27!8LB{qSW|DL3TMI$CiQUpwEC?(_A9WO z21@2b_QIKK$r^LV9o)6QzuQx{-$s0@-H=*kEphYiQzr_Y)qtw4X(w`5XhDBN1(6z9M=63V; z=OA8v@1$`OPUaCcF^@x~tl7jo~wl8M`Nhf3@!IGQDD1A(z= zg3ZYSQKDvIP9cxkb}<)`;k9qg2Qgc#RE^AQ)TFNH(u9X;-0Fw9Ba8O__(q;Gw*`3+(O6{3lunY`clr zXd8v|&wv@u;d6J1!P!SWB~Dw>oq}on(zj&k(RgFBhn2}4TC3T*T#r%7Y_^|B{)8sa z;m3OZW%ji`8M_MTCFTATh}A5%-Ju=yErmLkG4@|Pi7klrePzq*40#c6w1YpP)-&t4 zr!<1mYv5KQNPzk6pOWtP!}tW{+6wQ_r#iEp&Yfmmv&^+!XOR+tCo~TJ94j__N}M?w z+&#pmj2Sr6lG4Jzw5~TS;_36<0uAyid$kdmT?4$=0#}8B$zBIOMZ}gq_LoHYFXk$F zrtd9(>T2Gi=CJ96!!x{d$>>Rw;6Pckf7@8cKDhO(6JJXzR>VZ-Fx$EeO_QzZ#qJiv z$26Su_vfw-d*c-9(1rW^;1rAXrD|)eO_)QS?qY);6n=M-#&>OfpFUr`eB$+R*`4dIR!|L%afpH~`81?x znJA-xkLa_q&MR7CCBh#BFe$bpOD!*3ta%=t7a+`JN0t+Z2WsZ<#h<1ulM2e;&ZT2z zOWE4LzP-&`h^AR%r57f{4}EX!!AguD56$X@Q`?V9iou;4MGE+fhNrhS>)~K2Py=BT ziitsO4{R!bl5)`4kw#MUOoO=trxLUtu62eI9lgg5El9vvCkIW{Mpn#8_sn?^eJoZF z`;xU{r7ss3Jb@K4*UiN<%KTLx>HTN*gf(cgP312QAjONbm45sB(HBgqV_}d48**WT zKF(!*_RiPBv^E)J^WbT7MaG=UPe)6L7C~&=8y`{uWxqY*MZY5{%MvPE?*9xM7_h_y z;p0SDGYa8F@Gf8Za42OE%`RGLd1B~q<5EWZj(1%qKBeVJ{wel?`E?@&`RhjI0)8kM zvX$r2O#uSTZIY~OjL&XtDHX^Q*7;STfE}&9BFs;5GD1#R(L#l-AU1CbpQ*yDy~CPI zCY@-ZCQ)=dc5%3C(d)Jrt0BTgz;Uh`o zrHgv@OL{na@y1o_zPyRd`>4*Q=QYQnq-XlE~=d3kE?Jl1PF$NE%ATL3+ zIIFvzqFB&eiCtqgv(;YT{jc%JdRh6gmo_*!;;?oDIkXp2U~TEhF7?K-A-D3g|-GVHtPTB(P-Q`*h^Xx$+dYH6;HeO>10 zeUK8J0BrcjLc)FL)lX4T11=@&*3CJ|2lh9TN^n~ z44)O`zC`cPOsnpLF#YfPxbn}##~f59@S${+rKuK$qm|r)wK=a%Wwr|4OI2XN90ino-w3}G*NGym>+VDI=fbJ_q$;_F4U3;LW%3+1dm z9dbPGnHnR$5ZUKVCcZy&J5EuWDc|M_NT6qk9U>1(?ZuSnsZrLK` zv|4-Rt_o(w+%WMk*G%f1MpT-OQ>@aDFff;%vd+9ac3vg2{i)2E%kOA;gAFSC90@HEwSM-rE~llu2*5elKbj{7ZqS{YtKtNt)A{ z1dG?@M{%eXT_`UK->P)Y>M6#U7D~>^DduPkxNF$p=&Xi#zw?mm`2we?^R_d#D#v1{ z={VxJTBwEWK;`051M(lU9!$A*!*%S(T9)E0qPS3fTmvI>Qj5f$EtABZ>dqr-AkzupvOC8Zwt42Yp(HDGcxVziPn)UX zeB=F@XtXmlI2JXDRa#p@ZbWJhBn)^3kUjUXk^1;@w3WlQtsF$4s}@xymyIQV+hC{#R~! zm5!?U_Xe=S&60t3h#4l&X^p`lb0aA?{xeBk+PTr6G@S1yY8;7m7P?+Y4F#F9AJw+k z9RDYGquc=YL`$U(gj1cuMFj~GH;r_Rid2KU&Msee;QfqJ@O~GX)QXK+-YzP1?K%1m)xyc>c%9C@pUSECVb1 zdm~Z}V<`%+lAz->|EfbILw#JPpCJ;n4~pL(^x;5QW~MiVBsty~?6F?WD)6#@=3`l~ zMOOm6sd7i2Dzs*xN$!M{iEV*bb)MCp(%x5));orV)VKOnfi}wS^u6$jTa!t&OG7qi z>~Z`kYZ1Uv-o{)czntCo$sf6%N&L8?KnACC<3~Di(7kgGY18)w^{qs0)t1Og%^J8g zT<7cU;{EIAcLSU-kJq%Ge+XPLFqevsZx<#==$|8H*5X?2&H&zH{!nXchb}x zGakLT9xZ<{_F*(tV%E$AGWl1t+lNO73@rJqxZGL->fzQvOBrQm8->-fl=;(X#G;uUFq*7b6sLj1zKZD);dS1Y%m})q!~ue{URc zokNHaq-cS6spOX7qzqk}f~cO-BhrV*hZc?({H7=io(Ome`Q$uiU(`?EA?lgT_eOo{ zndQMqt5J~1xpiqSokfOT@uVRUM@`-aeTv~n`M0dKP84+7*ZFw41dlcZatf8nLiffq zSq57J$uF8&^}{*mcs1klrMH%BTm`g3e5|vH@5{`xtgzva$ovyFr4>3l%zn$2nKPLq zfC?MCa!v)#@I+e93kV3zZ^*GHEHVmgL`4g{d>C1t(u469t9%qQ*v?^0>A_sv)!bpD zjl$8r`V!|{$TD7peXBk9dmQ9{Cpc!-vxZmRzMBZ{*5VZQTll_I?bl@e{b9weVk{=sE>(R%$eeSHqc%c6zip;Y8G$* z7j1@imVhy_A}ZITIsJKFYI%nsni$c6Frnz!(Fnj%`c4qf;9QN1*0PyAg{rC|kJ=TW zLAMn3aDvin+X<|b8tI(GOD}S5tt?B_-N!zKS(_W^;TqVC0R3fm`VtDe`n^r29vOZ} za}WGdK@Mute+x!lXn&5jpPz0TCZ{x)Dh8)%{rGU`lG6<{`@lG7(d(@65;^|cjy<8e zht#}Znv(=eM6eP^Ad!g{WqGXUv-ceol#iNbJNiUEvwuv308(YzU+*$Qihh3(oqc$r zeK#DD3v!T`eU1I^)D^)KosO*l=1pGfdJ{g8#+nJ2>MbVOFF`j3c<<0&G%LHl`6IFn zu}p%Jp2=CxYd``AzL)b|rP{LR@#ziT^&29WXUK45KTZBlkKoUKrGN`mAp)lN zHM?#BFtA~JwII-k8eGz7+gz%xvmB~bKNzRQ=+PG!Yw+p+!>qOwa3Dl2n?pI6wQDu| z3~GDfRmh*8<3GLtwqgfQfRfNooH1C1K_2 z#+~&c5A+Zdu7rO*Fu}}VI5We?9%#bhr6@ZHq2Kd9l0`<(AFnnCe2FqQ_sLQ-AReRK z{%Ohg03|%jq&#yneaT#Mb?MR))PY7pq}T_(2<}pMAFlBV%jyax zn?Q%EtkL_`husXi7 z1Xs$7+ooYlfHQq=QLpW0DTYiIo6%|KZjTpf6a8%Vt}ws77AD{`$lCCw#o5xjS>|3i zCC)-vXmmBrR|Fz-HLqKgU<@oz?gGY;Gy{{~;1)?x=d>wV762IYir1+?7v9m!}Fm$7j#w7O)!Q+mECs$ro7xqRyh29Ef+;^m`Y; zw6vy6IvIs346KvCV+wYg#1wd!4b0*f%0I$Ai*vAXH6AYl?<1rjvnNYTao|5?@GEmM zMUo0sO6TmBiWRbYl>8(U@sVF9>e}1t73++$Dr3f)by~^EzQJAcWXRRLXnuLL(_f)% zC=)@~w1~j+*ALNFF|W$l5MteU=Au+I%(?24uORC|)C_S#FDrVWp+ zcu@{L&KY3~5-XS7=#Av)Zq__&jJACI6+P0@ZeC~5mb#tbp04N=U&b$g?i{3TVyl$_ zri_f_7Zos`x*nT=@x5a{w6oD=FS9W)0_wU~ zzcJfso5!=QORGS1EO%+XU$OpXaXZ`;RSoeE%e9Ton>cSsXZK)3dnIhg zj+X>j#mr{wr5|NzL@&E*1yYj|w_azI)cRf7sX2ejVX)~`N#=1vcBBANUEn>S{)^Kb zpi%hThx@)@VyUD8KboV;!LiFUM-DBcw+DO2MOZq7Hy0_GEG^5y+6IqlNB9xR|T;|O=-M0S*&Pbx>@?LnT(|3M-i(6zk zQ!Ad^yyzmSZV#td#s6bzNhC4kapBYV~knVTK+CiV| zfiNy9(k3IKXVsMB3uB#BWMCdTdi?|>&BxHFnt{=YX}>;48ndV+01CmYn+r9dZmtUp zk9zcxZ$TEu9fitK-rmSUrLD3kS6%8KIu)3ygaP9EV$=J94oUxJ*ZRgdtRe#+^tM+u z#D1dQf8shlf3#L}c-wpPN0vhc1Lud0c=Ojr)ohz+dN>`0v`mh?g!Ux?Lhp}3Zcbox zJ~`Ra4p(Im8;+y{hS)wH+k2sn?5mzWUo7^Lk;fVs_ z=CmX=gD^(F73m(-;PYvXAQv^bujsYtTt%2o>1tlUVfhBDPe1qi)uJQkT1t8{ecQK` zt?K*NJ&q-ESl&%I?=Oyzd+5`wPBqVD)(|W+TMf{ZLxxXDt-^%G@Hv=XUO)fkknmpN}~gZGsk?I}Mx+?$lby6vr_fFJ5x1=ZZu(k)jHIIg?Vmj!d?zT+yBy$zm} zSwDbD)skYRL5+kzT%eN^IyCcUvXF1y(sMvN`jVW{Si~qJ1f&cak`PdRZ*snI;|xgQ zDDvwU1qefWnfAjC(_cjYB+PYS(U&CTY)LVcy$)b&9d@L?1LK=G7gCyZe2l;0M}O?N zXSys%XHxB0O%rpMtyX4T@pUKuq8}h~*lQcn`)l9zd2Exn`?p7dDVJ{Sj2<+1DSGmz zSnz^Ca$XM|n(+jrEuxoUTbtxyt%Z7W4#$H`r^kfu>fzp`;ZEjKWfCvej0+QnSTZHw zs4W7wEi3>l-mWGJAB*f#s{p0Jx#bgpW`&F%0m(O?e(!hATj4;!i~n^V)PHNEz%1Rn zOq6kjQA0E~eYqs!`3m{T!o(xGOaaG-CkJ)WY0s~U$!Y2CeTGiDeYZ`&=;2%zQ;#z6 z0SnaKMvW0U)u~5-acrppr7Easf@N9{mR^i|33jBS#S?oH94!Q^|BeT!2aVYVMJm_mc5s~yFYe9WW>7Qn17lnzogLL)6P6AxLA-Y#PS1|@t~>Fi?+9?Vg(_Fu#2 zS9w$&s&6EH&++v;|0VvOGnG0}s~B$~Ya`NM+&64Ag*A10SYyJDJ2H_=6{gF#iHcx%R7h4)xPxZ3x0f#WmFHN&J0hN)>A|;f%aTzeeX+x({#y zh0}hWPiP)iVoGdnNK0&f_m@_!j{{N{SFa4=qyFRc44?HQ`H8|$1 zQ*wc3y$9nn6K+ZteY3ZY5gt2nT+|1S!akz2q|?>FX#gw)`a(J=J!e>kbm@1aEkvkUTKL0jKTYV*}XQMy7G)JCM9%FqSB6@clT1sQ7gBn zF1(n+@nLH19l&LaY8@WX=OLaA%=c~@FfI@xeBtZ0@;=#{W5XJ%-5p?Mp2Ota6%x8x z5adu+bo=7}#1u)ZxBl%f@0c!+%}(o$F#fQzY(M^vRuWJ%T?O(|*9)Yqy?IvaCEu{e zI`JhBlDkSIcMwctH5c;l*t6YhTxyP1aw{5Fp{|jB%!g7gwjs&`{1}xPN!n21166RY5fmU?ZvXb6y*W3 zygF2fle=0VC$_ho$;oHG0Huugq@r2FaT^&YLbhK&L$jZFVk~iX;t|&CLEnWOi2{5L zT2Pne1(SAaLM$G@@LBXhtb`?NaRZIzvKEhfPAuX}&piuSuwB3vj`!BK*Iuw_d`WL? zmvf?9`89g`sGj07&djGx*>f)}270iMinr7;PTA3|TCpb|B*RLTFRtTf1t@tJ+e-F> zDpTsNVbk>{?N@M-Qhp*_w(Kzq5}MVbq!rSm?*zT8w?Eg`t*$+AOrN%Hrb~Gnn0gv7 z79jk#V>di>DWAU(CMo%QldFZgaeq!;niJb!Ad8_|Z^>IeetE9&u*UJH(^Ztw zTln5y?eZM!iJs$-5|SEE`m~^pStukwF90KgE2@IemD~F)OqzxtwwFQZm7{psrFX^= zIuc{OLMwX+J@9+etE&%jnB3(RoT4z=Mh zHI$2aFvPGVz&3y~6EI^@eS^5qne<~X3ITtDTm1x0wS6!Er-s;F+?cGxkKn)frQ=a>TyzM z&ZLt%Cg>ePZCfDWzOR(Q8Z*t0@%gJ?6ze zt)KmO`L{Vq;e27%q6?;_2uAcp$(`2A7&bem-70O)S@)dnj73Inx3tiApfam!V>!iI zoxn1C`33U|>Gn%+Dq4icx{K4CX3R_)P)gn!259MFdL(nhcT4KOvpM;(!?c5oP=%x) zg6|#Wyj0&6AKrJgAi}g@$itHHZhXw@E6R`WqGV3TCG>lo*F%dl1H_KX8*Qvi9xGS8 zc1i6+``Ksb5oYCzpe z#KtsR%D6$A_-{X^a&KX&`)$qcQYy*oD2*?YFX{}IDW z5(Z*O?!O=TA48>Ojn^adMz<4mTjaiFGcQQ49}Bt^vpOcYSdHBJAZ6>)t1!wuTKD+g zTSn}l4y;a$+3|0SHXHKm$J=iwn=LXqIRej@N)2lbTn&eM{%<%)fP>iKg-;4!1J zjDzRzIp2HGBPj^zPyc)4zrb!Zo}(E&*iP8~`peV_(ufSgtGr>uAoy#6@bfHANc9ja zC5aSvZ1mbr*f-N)XR=!1f+m7gGqn6m-&|SG-$H2rnVw(t^n@zTdAtaGIS!10FIViq zLB_$4(e@4fqXS<|Ea~qgeLpCWg1UUmIzRlmjdSV1o?K|j-djxXUi1aAzm4rMB{)k5 z(v&@L_)vdZnAa~F)_rQOmecWN;}GMhXfBknov;R~FhO^F5=3^vAFFy(%b-9805^P~ z(EXzgD|5OUY5x_yb;E#WBCqEU-}Sc<84Cysk_tAWv=24g+*HqrR#8EI58AMjWgHdz z$CD3lz-R9!_DHk^u}lpz5ju&MxmIJYOEq0W;?+c%v|YjOKPPibjrGEd_jB* z#I|F`#dKvt&w8`v$*V#@qTz<8NK-!sk#LrOF6Q7SQ#K#c{_AHb_ftX3d!*R)X4bpl zPvd(so&R>2KGXyGP{zln$1*wW^-Qi7^4D^SnDQMj#dKD9?ec`hrXx5=1)>9Y302Q) za|31GFlxE)(o}v&qnJz9uFJuVFOVLR8wxhon=M)UbwDGyzq$8kAz;O)r_x>2NSRP5 z)iF3peW8ZTt)I;<`PBmP*VPYWFl<@p7XJO$fN;}80s_0a7@6n$dp>XTaclmSo6dR{ zlf62TSz=kl!j=Ix^GJT08s0H_ZHjYXAW>Y!$9D-#(Jh)adkk5<7Bn9&{#rG?Ltm+7 zi5QCkYh!h9oNG|%K+4$nBB))?9hBJ=1aM-`w{npW zC^#1#E<2f_zf=9)i_ihPLN471)YqqhB3YG}Z^xZlxh5pYKc6Mc&k1aw5}aaWh8Nh;8>kf%be z0v`n01v&+~Qm4vbjyQ}<(?b|Vd zicp>2UL7}UqfNX=E1gUBBCbQEQVOSf8D|xnZE((Ge4{?e+AL4ag_OdLUR7Px&I{zN zUT|5HJyzC^8y~RZu8?Gd+7AioIEJY$Wiw03RP*TCuL49+WKdQlW2{e*YrHJUpmbF2 z*?SOa>y1XNd@L?0b84z9ai}lX^5gtk;~aQ!wc3xcMiw%4zc&znGBP_NE<<_QXfsb{ zJq5IK{h{=#l&_Jk;vUbr2mX(%^<2R;=Rg|FlagMC+~BzX`1;YEg0bc(4kj9O*gOyR z^G@C6+)+J`uzo zB@l|N(1Sjz51!R60XlTLVKP}oNK#D|NLhbN|7QovGVPjgRU)@ve;HG@2xFHIP5+cs zzT@MSZs~uk?^naMl8wHf8~=1^x%bD9TuOV+Ex<*ATE}#(nDZ&i!pq;oD;1l+y-BpU zulE5W>O!FU2UA2HNVgJ9{Iv$}ySzLz;^6Veu!%yPV+d}R@iD;i>Qx$XfBZk)YwT{g zCeRRfX{|a21KD?mRM_BwL$6wXw4dM{umMKX>6Y%~j)Hi*57+zq8=2Vvz`uU(jG<|^ zm-Ir<+x4tDH{i*-+mbWbsZ>pQjtc3VK=aae%E_z1vtf;Q&dC?1^ zmrc)n{$m-4G1raYy|@$ne&U2Olxg5#h3KyL}R zJaY=PaHw$g;1I$R(X?3ihY0+}x&Q4L8W|ukjA-K|I^`rGm%=_nMl6c1NNtFCPb+=? zNph(}F0T>+ihXyG(R$~92ZApZ*WU~LGX(5&=8C;HL@u!dh1I``1P|DGWPmo3Oe5)t zcOmnGy*vIo^(wir)I7CXZb{ch*KM;$R}D1;=4Z8de0mi#4TQO>pbMlS%Xa0CpyIdi zTCS&s4U}fo7TPQi!n8-2bn1Fss^o9f_V-afuyy^+R}Hs|$>`sJOTvqGcwQeUv;VYo z|CxQowHTqgq5UB}=fpol@ST~^Zk=}^VrL2c_WDN%(ffY`ALzcn9jy0dPHRsyR94hg z>ej{G&DIrs2bt-vxCM_E$y-f!%8@z9Gh0sL|eK}DRY44rwu4@U6{Cf&`acl z0;;LT|A6WL3SDN}9nt&!?sGhr5_KKYrkY~vGu|Y9XSSUms__}>yV92L6``t?B6AJY z`}S;z&_O-7n!MpDA#1|_(kn()tLMj52ixhc{%`bM2|(z7;BEV2k+FYf_Xfd)i))qZ zBDJdhm!+-@!a6@Q zPcpGd_id38AO~jam+m@b_#8mF5p`e4dttD%0Kor!XJ^ZM4!?l5 zn5!28T{ovpP^zc7`VRHE;(Q+&J27W8d`=FWaNdjDLfPLU!@^T+OXFOA6KJg35P5cc zvrQeRW|@B2jtx{yATBMTm2U~WfE_LEeF(W&X?S80G*J;V3*0{{eliqGiZ6YfatTvu z5VhG^ob5ypYaM#oN=TdwnOE|VXP8R8a3;Vr-tN@woUeGhQ+$g}2N)e)=DL?WK<}sw zAbQD^)`C9=L2o3&|1m)K|H`EP%h%#+DFL-cWbTANrt;glWgS7G=XZc7b zXjhyaCp66ttTZHELv^^#zEGN9gNlWXSrFi%>oaO2J~speRrucw1E(k@-UyJhJE$M4 z{lPo*J5BaK`QPDl%kTCyejoT$s_kX4h@_9l&_19)u`SOmV$vnNdwXG{V__5%Bh=*J z*XU;WO2Mnwv6j8Q3YApz`KALn*iDYbtLJsTBkuPuC~yhv#!q(yJ8#r4WO9?5lP|_Q zPTJReV9XDZM?sN&nn5;&g61+r>w1DBh>t&X_L;eF^2C=zof#?%A)4~XxaksqaJzd? z&bjGtZ-t@hF42wLO1%{6*5@~|1|x0EpO?7lO;yx*@rR~$C5X8+w~rC%Z%Cl8%6I44 zZ?CTB)}K9ehF5!&W7c;bVJ+%I2dPrnkXw4qOy^v6MUI6w1|7p|E6r1d4< zmRMD$4N169qt)xw%Pp(#rS!WkHF6H`mqvu=HP=nkZc5N@fy z5fmm#U`KsH47c^N{88$7_WceR(T&RlWc1@6Bkg5zo4BVBwYmCnD6Wg=x`+K?gRbI` z`XwToebfz@F9&mRb?nuM@*S9ChgdgN**nbx$;0ziaFZAwXjcnMCAP!*i_I$^HBF^C zpz>3+hs*sztj;)n<394jbzetfd(`k}Pn8^Bch9m9V9pAize>h_k+(z`{WCZj*p=B; zw{jDRLeMrl4SFRjNRPP9k-LjJXNPOCji5?T0xE9znGC0TzbxXVQ+z;Iv@+~1O#b;s zO63lSHyMYdmrb`>32buSE@A;}p9ak^s-OY$gJ)i;0Xvus1D(fQsf_|_-lJdheH3%$ zwD{-R(vF-J2aSt<@~SL6AZ7zyKom=}nZp_S?r3~tMj+8_Q`iG7zj3_i^-RWk0Es&^pS_3qzG zyTQt&#{V-iIWUVOz7JO3FlkGcA^|B6G)TFlft5Ze&$D}Umqxc;Sv4U z21b0N_q}__%pTGwv2YIYQB$1w2z!SL;)4#UukkK&sJcgI?}Z)z+#r8A@H=fQO$csq zG7xjRnXEqjm*v&x;uSSlY8%rXgC0h(W{XHhGKibg-RPwyo2imNm(^!p+>pNYDJF;{ zDH09mRSl2q3wY90m`+vWX%NqU-BWCW0T`w(c zg$0!swgI)Pr+E(OxK1H96-;;9_t%I|q~PZ-vB7 zp4M{v((C-o-<NlwE_TMM;AK_~{t#GwhRY!@yc+$vT88HFU znO{z&McMH7E0Ql~@2Vy}D%{goqla?d-q>4cB3TU#csS_my**b>ab>IFB_f-wOJjZ5 zdsy`?mZM5(sD~sxPMbWHjz*rM+mw9|HxT#K$nnUIXmt#HFFO6;Q1U4UpGt#D)Cj#C zz=(JDO=;>5%WfZ^94U-uvsPBkK?EJ)hjTrwpQz!#h~i!Ujs2hlCmmdmB2EoP!Cm;t zB^+M0c~(ax($|kq6-l|g7Eo+g|Afc!$@>Jcb!;hUNf#4r1eSdYBr`7?LBFmK=?l>B z{?dPBbjT=Kl`HdRkIh$gDAwtOly9=wN!0rgdgsqozUSrX>=TE+`oU(SrzYKlQVzIJ z;(vO-*2|rKf1@?=G>))>`t69&9LBL~Zu2QuLO(%4X+_pGP9|$!2AbneAZ+v|2ImMOp$533~^G5JbdU~nn%RO+_BC(#uMvB z+tc_I=74rFOZvDZ^ZTfKrtdst8lX@WuI!MT<7R1i0xFENsLQv>j*AwZE5SSd2r#@= z_MvYf-iXw#qxi!#_10ut3KXRLb-#lU=qq*&8w;ggudO>m>elcZJyRVtbrA{KdKzS0 zNNeX!rd;+Ma>@3&G_}5Sds*N~nXv)IhF#g9p}r?^`XlJAZUUAa+&Qtq310@yy=!r@ z*E-Ub>LJS#8EYViU_fX7<(B_`=;Ot|FRiM)fxYM$Oh*4KI+=Q=DAwG}I>)OwFSZeg zOG&T!WqbfjNn3LFx`+ZD_$Y3)XDp750G}+(QM~Y{kVYYAKwk3qr4iu6KbyX8_MRUO z8s6En{j%#J=K~e8l%hYB+BbCSgg)eUq$}cS2gxOt$B>p8+?yDtxtN=KZAEb-r4MM? zH$?p*tG9M#IA;6~(cHSme=_8>iEm*}DqNnv7Z?2%t??E_c$4*&1riXO zUE9E^`HzoI6g&q+_)vrug&&#;z)8dLPq1VPXdKUITEutU{|q>+qXVd$_a;Ghq-N_F zXwXYc0~b{oQyfL-M_r38bU3ic%p&MRd~z83#h2JXjj1e}h+ z#{F@`suME({O_UsJ$rP}p41fn@H@GPK0AsOe1Fmj-w*bNZxT3wj}t=2dtVwq?c8Ow z-xbFMEjY^DHdf-L>zkbt8KIL?{9q-5jjpUrY!%6@pNJmu0lT%Lfg9jGLYjDCwdstQ zU#1Glv8x{U$c`toB(*&UaPBp3Ut4|a$87pvaCs6n(0}kP-1zJ!{%4B1w4`+NkABCK zcco`(Xo&|&d>2N-Mtps%f0}JJL}Cd#@dLLc;Eq@;L&9WjRNOni*=~#d4XXavIT7_6 z^we&i%1C@9G1Ir2J%dy?&qcy`c5O0=6YgCP9*UoXlowdC`8$7o2gG$uPzE4DXGiLB zL=DkR4vx*}?}IaNChg&v&Z_CQXO{pQ)CqFVn_{sOHNP?c|JtZPa1GIP!m;u8?Pa2N z_v`6%Xujjsz!T5H&^cRM2RPiG_8WVNp=&7ZxN-LR{jQ2$jG z!J^KUl&$hUozG7fIyHrH=0FwxAJH&VXQE}jM2NuJqx&z8=IhKKVbM zK2`9_;rA^r<(5Us;>tH45HF=}2CzV3xcC9K9N+$HtsAKZM7Q6d))AX*2`IfM#P{@{ zSM})n7Zv(c&)LGyoebQ9#ot<|Yb0mZ#CH>o8INJo5q z?Edz?5J&O&X3mwnB!@xYi7F9XpE4gB1^}5dC}m|31=V6UF>)}v&%vY&@BU&}TqT!x z=jP!=Nwt5K`TsGKT@WNEDi|=6Bi{6V4nD5ZaM}TsYC33x{D+qZ133ue7KTA8?Vh5w zatc7%WoZ76|6^BLv=OZ5fFWXG%?&qS}~OJ2TTdUNB*u3~_^GX)hJ zUO8)m)Y{L;!|-p~kpF?UMy{^8;_Trz@pE;hmx=_JpdcE3bCHe_*N$o!0$JHYXfUX$ zsesB&E>ZCM`Arf5KH?wa2NcFh+bcxvTHuSk8z;A)2c=#(R}TOCFfg6!)r-5 zX00~1RA1X&d+&f90bZ*PdgM&Hv$fbJ9}aBt#VK3hgV!pIM-nSQNWl#yaJ;tM+T=i_ zP1Hmm`VH{Z4;^I{@rnFfDf8b6Q2j3}K{`JOd}y7O`$(8o6}KeHWw%bcw2V&NyQurm zrK*pzQCb_iqV$#fH4tfUs+HQ!5Vu+F7P6^j4mgZ>f8iBA`^n$%$bZXq{%x)f+S_>B zZh{c4s1v329x3=ig)-+1sJRvU;;Fh3KNSFxnBn@HfAfC;M$7uGhK+rXj6icAgkLJ; z5n<;dsLd8$N>}`U*n97Ps{j9gTtiDLsXV13CCMs6c8RP|_EuS$r|8%m?I9z3D_h2i z$UKxH<4E?V!67po>u{XU?LqZ?lK1!W`UAed<sQn}|A_0AqbN~?_SZ(PIp>q!K-?x;k9rfr*^ zLagISS%&yPaq}-dk?ZC`GSgjxKuyYb!UOS|Y1&swGf88&5ZM!mb5=(6DqkOXCw5RI z!s(RlGl|v<*%+4()?h)9Z0z;qm=Cn->Unx^iB(w@8F-xU=ruo?ilw|~(aa~7GoeCt zb1d7eBJYfScuY?=@Vl{wMX5#s4{rqr+nwuI;;X$T7kk7bP? z=QKltzK>|2fh-Rwj_F088q(zBwdQF|)v7gY*a3~xCZT|x6hZgT8mDM)?)AX~4f$Ws zGrq`SRm`nsK2=TN`l)h1bkCkWp%JL!HlNm~Ki3HUygzn63s7oNq%27cZk2pH#gB2j zjoC)E)~;n@rnPPwdXU5~WvvtJYinihv3T+Ls^8a~?q)`4+d3wQYF zK!dAjs66v_L8}n#gwguFCxP5i%e6Id?P`Z)9S^u4tT5{u?_-aunFum_7e7`L!rhZ| zb*5S~3SY|c8sEP6DL#@0>B1;Fk{y6EI|%*X%!mVZkl`|}G2L^MBZV>TpHn62N|0a^ zh`)BLpkOG@ZCwgBX*t$1$`Cx{$1N6qJm?sSQ?|iPH4`9N&n=-*UF)oZ6Shxx!dtpsL30`?` z9HDwJR}Y{kH6YVp0~Ls2P`|v!)I!Xo=keOSR**gFmOpNXO@3c+B2-L+87p1;wQ}7g z7H5rL11#8K^;u$m*!aPYgM(vtPW&GcQ#BId5P-Pl2axPOZgHWH7jue+0m>ma!1H&n zvK%lmxz-*F% zLZML@?_{g7?_7kZ>KZng$+r~LS;-+TrW@P%cp17;5#p&9x7t(8v|0i|ebhQs4WQ9^ z8{Vq5lD#qu^{>2#Fr55vHLrkGOT~n%BP}t7C-M9vXqgvUE&JB_5%)5u~h6C9&1)(*}YwT<61^DjQ`rT3)9#o z1Mj7^_FT0J*~ztM;v#(4{)cPr~ozGmvqX$ z-8Mk?5yGu9UexkT+*xCa=Jss=CklL8KK`I^8;0hw0HA)*#Ad$L>H_R?pzem(I5WYu zv!6CB5q)D4hek{8OIrf9*k)JFJu>wzK0uid4&Sunx@*h4#45LYp}3VFas59?z10LL zzU4=dSx&7CVvlmdZ-8hR9Sdk!B4TxxFy^z$YYzFUP2m!_BV^=spDZ~L46$TSBqU^n z(ZVr7KB-{%q`zFmkJfcH%lsRKo2>%8}ZSZz>%UsRMEMo4dGfo8w3hJk$WvwZ# z0FxCZ&)vASq<6@@t^^HL@lm2JMh8>R-Q5%h8#fek$8I+;jf-Y1{cFxtuc46{fCD#@RI?p_o#DCTBPgRRia) z?b6i>ZFIswm{HNZDV2gHtxJ`BMWU_^7pU%O5&?+@ABlEo)?bS6(*KQmBBbgv>Y1co zT?mM}S>v`s)1)W|J`jLT?)**2twP-N1QA5`%k3p72OtvDfT?=s97Mcvfb~X zX+PhR28o$XGoe-l$>{MqC0CyxUBh~EntdqgsYNuK#-bkIV)(FzZsRi0z_p{5LID?$ zqjsbwMzW`;re1KQpLf5FZk)1_>qySx;j=*Y{}uCT;=>a-FV>cG11x=@T2`q&9G%)c zn}qj5cxz~TP;@*`5Y&xnIrD8VUfV6lW&*62#h?V$gSj(N)kZa{FV;|z7Y}5 z?!ALdtuJv6OM$Qm%F8T5(Qg)^vQ1XwQ^61}D8?S=vtd^50{vsX(dY5yQ%nmX(p&df zlRe(o^*v^f{<$*~VJAtnN!!=3)ScR|t?!3*8b6vN7Vk(@BM&$1$IY}5%+5|~)i^TK z@(*cdOdGNC8e+(3dqS9bIIR9$#GP*>TFx!0iCO~1AcFbn_qZR6 z^ZKO_|389{rX`-T3$*JkhORX|_qKgL@D7?-&uHm^X{b)#+Z-!V79KDQS;@@KbNhxg zdHKG(82HgyDi&^cwh-c{6lN?|um6i*PYs4cGMnmm9x~jTc2w*A9z+=r(xX5HBGV$T zfa#${62)X=TNZDV(z{m=J)Fy=D0|K(ETz!@ir)-bD0?g)(lVKmrbmWQS)iN?yeyjL z@jg6c7V#tyj8E>APtZ^-=09)PE}-biP2od-j#{+vR9H^^|K*;4@I%*>CC*-8eJr8g zqvY##D%;P`Z(|-ogYDr)B9o?MCmrg5Kb`J(ZG>;fh_H+;S)P9rQz3(bTR*NXGP};K zGnC2Uxib5Jl?69rm&_WwYu7W@&3l>pj&HdWd*_L&y85f<$+AyWr3*Y`*Q>%G$CX6t z4{wos_&Lxp;bCuyj#ofv+SYZY!zSrbW4Kxhm8;qGhtB8oq77N5)yIVGdcUX>SYk7n zx?f$ri*RW5g^pv25?apCcRTay0sF3>;My{BFL%5=uB?3dvbz`uKV#n^=hpqMk8-=GNT|!%E zKSuEw6of`x2OR`W1^T^_$6Nv^B2^tmJ1uw=8hbXEnvA|Z9j!fO-%Rdo?Bw=Kdt{jR zXkd!E&WbZu$cYX&s+Lr$nW8E~IauR&_%70ho^V3${xshZ=54{2e+_eT#s`2Gn}x*DYnIRJ^j;e18b zi$lEh_|c=2THXnVR8BiyD%c2*ZWAeao$t!hwhMQIu5O4XwnbAK^^?`53q3uo!=aNE zzgRd26J9<3{bP-WC#RXAP+A7HX3NG@tGgjc%jS%f7}3dst5b&tae>fhN@Kj?Heg6wbfvR5L3U>JPYrtd5=&g3P$7vt?<#(Ee}!Eg^z?pj%Ed6hTj?%39 z?XJX&VX^PelF6KgMR^CrT^jYNU#a51KiN&wc`t2onnxvclbsKFDq@a}s`AdtL0hq- zMJB=Q?Q=CSfe5${x`7caJ#&D1c4~X8R6(-vbuB&ZXHRg-TkFd)U4@Q{VA+X1!f1w0 z==>a>N_EbvcI-UNRI(1y;>CdYg)pP_eq5_Iw?kWwRY-4TfGowGQ#U(#VVWt)kQFUF zKQlVOLOZ_ElEthc?G0h{ug#jH0vnN-;|t0KK8AHErBzte41AhUkzrJ0@Ym+Bih;;n zL48k>KI@c7mi+_vOXO$`daH;+YX7};Gz@gOVip%08R911SO!mTO^jA8{mVtAM+bVU zOD6rYR=qLD_tN_`^`MGw%eDx}-*PsapWUINl+KxcOS4ssO$qvxd5SSFcZfHrv>hP+jz{#W{9L*KEYs`{;=$CH8X8t4vETh?clGEGX2)3QF`5UaGasx}&AMuLR^NZ5M&R+>b8h9CRys6zeH3Jt>_8hg zVM3sDHcwkFDkguw=f+5ptaHIW9Al4LIivFL*2~ZCp6cPX-L=_u)#2TMqAZeCv4-Mg zM>!cR$@K$A&D*BOPsDg#HFrMik*Mr{-2TCAL}lmT^-b2REDCKAU^7)yEk?X^ll>t^ zn7;hyZ*wjsu`{71lQ3pkiTl<$FwM#D-=Tm#?g`Eez7w zbTF+l#ACi-G-Vb^L%frwR4vCRN`>3_#@G%P=`j>p@@z_zSvh9vFCu7M#*=QZmXYK|QS>ASS^R~XsFM^B#kgO*YeoRA5GHiT!gwAuC()3a67}*6r+;jMbX{6 zcbE3ivxF@jZVekq=Kc`!Y`f& zp}J|tdKSi|`CsusAq#NLdt5~zM2=!(Wi5rh!*_U%=S51m>jHSaV-9+t;$^7(8JG6< z3RAo;&*$&KQ|Zh8J=70S9wr4kwRLmQRINsaifd_Wt(*=;CSdAJD*Vn-hD(5Jg-Huu zn(!6l#I}IFPk;?bGB>QD;Voi;QSfVRxUzL=I#w)nIm13E&Q=U*mK*~=6aob|VX0KF zw*Ng0$~at0qFDZvajMqk`t@Y%u7W0gYR~&iM|Fi;nD^aEe{3LT5+=729$8aH#kI6u zR*qw~u`7IC-u?e+W>k%d(PGZ3plvlR-v0LT(gyjDALY!E83Wl}yxZIa=>e!+()k!R z+}O2x1PV%Z^JNT1azK+#)!M;@Dy9guc7p1_UwcmVJTY1XtpJHeI_5!Ba!+at)yB=M zXKwFsU7-irCI3fa1hEz?QY8v(xBXr!pChX`$-6^1^k8G1WT8;EQ(SR0!`YvI?IZXI zRDT43M0-$FaKjemzXsSE2VeX9$$M~gbaVtoD%Ev=z1{XY2m*E7x7h;<06XdLPxQGE zZQHVBPH1JMVI)BOa2&!~0j+hrdRH%KNOhekNOmfNxg!?axYQD#-n)Mvwul_{Umx_U za|JODBJ7^3jSq*_s(eh(j&Guh-@ST3)j0#=_JpVE>AD&eF*DfAfPz}WK@9q9YBFT7 zQ1phCOHoZQ0W(furAqm0W$jM6)W%5iLa@hgw8>B5FYCY%$3XS%FJmAmI|i)aaW96B z8T7hWG^@8u)+v`GtgP{X|AN(Fh3ygmQnrXxss`jH`o1<;Q~Llk%H$wx>oG2L?GbjAD0Qpmv>R?cHOWTx z^We&9#uiQ=5Ic%Cbg8D#*5Vg1ax!oj?m!izV-d%*6uk;$0Ed5r#7AYcYFP^`$`aG< z-Ul2Mql*aSXvj)mcw>7v-%HUFS}iVyT`noVlynkqH8KKG%H1)+19k zdW{nP%+qyI7V`tFE&{M|5T1EWRL*lxKQc6BTFntl>jd`Cvdqyy$@;ka}C)-|j zypl1#Fcf`#%J`+&%##Ci^C_uBIh6K*sliM<%?-*bH--kM?+ zlRwnj5Dt<1?(If72dEYKtCA^3!>p)2*2}HyNM>yJV^0ZpLkUmv5 zh7%ChC3ez}u<=3b7CgMv1%r=F_Db0BJopNg%JctmDC(VZ#eH2X>*2>VY&oWhHl=LV%AnDP$FhRw_vg(v{ zeeP>Gh2#N^t_vwnN!&(xH{LDyQ?Yzm{ki8pMd6TSIKSw*GO0-AX|l>g4?R#x!v92m zoAQCVhIbv6|LWb$l*nW70~ybU{1S+~seT2efBdbX&;d!b0-UTqNUAP&Z)Of5%lfSO zK}WF#Ta?Q4P1i;-WO4fzDnHiMFFQW6AQOF-_QTU?iH=SIs`xD{54EAAw2Vw;iIGP& zeTv5?n-Qa+Er(P#zFlpJZNn(@%%pHVeogXz^m{I%7FS7=x64?{=yk{gfrSWE}9n_7Oo+|qv0n=i!LhqpjjpFsJ+SgUv92Ea+4z<(-eK5& zuG4EBWbOz@3Wp4{b31*S$5W9e=bASM2|Vjq%2prc1eqBR#AoftH8pgyQN{nW`n9=q zbKlXY+zvI;TC^SAPo=tX)tiV${}BB^pL{!1wtL9x-w$lbuBebh%HvO4x5_=)!|_tG zn*XuN3#t2ka4lm9Ts9^3DMk|Ip-A4nh&hF4lhXm%=aY=I+~a*VVz>7{y4*4yEoNW7 zu$zjdZRr4booz36FI3-=&Z>b*Jv_FPbTN^;>-g2eMKd0L{$NzF$C2{NlCc6=5XBuS zp&at#XL^jFa<-u}^CE~h^U%qv|L@bb?%Wx&o|>jILR@k}`k;N^WZffPHdL|O?JY(K z=!RvwpcK&u#^1+f$4RRA(@V2Lw`DMppb&JvujbH3EOUdTh#S->4$Y)|LegwQA!78; zboPrIglo}5Y|wPx-pC0S!S=hbqt>e-@ zX5BTxa6B1RZt{RBfH;Tl)2xgs@tjL9-nTrWr(vf)(kI@I^krA^?wWaaMAqa}q%hx= zw^T?$sCtIJ&OR>fUHz%^4@LItgRRje$nUXbAMWYjGoj3I{M()xG?uUN=O;XSW@G*Y-GRsNDJl4G@)PEk>t4ZNY z(awxLjq28S7;e34yPhg!Il)_h&OMPYj$1hCa>K{o7yDFP;DEV(Qd?d-9_b4TVZk=y zH}^l{AXPNjP3zZ>nmB%WyABE%jN+kfkBFVd@XG=3tzY0`Pym)KBLE_*0ICaee$`XI zmW$&c&QbCwOP#Cp(quT^`sYk3vd`IFX-_)3D>eS80bdD9sxYtYM~}8thMtOB6vhL- z3=l%pg>>a4%_NP~hSYWO%lRMcE>%947^jRllY&K;%1Ab^PW6;09yWvDrY6Q*2NlaN zwhUpp%}2%RizhoWJGi=B? z*~9zQnDCs&>W<=tM8k|XYDpJUX9Z?LBEQ>5??#a1t_kZBU-4&y{bKELG5OUd35V{- zA9@^r$UENlNy4EZb-=;w1-Qk;B4s(&o%^+ur4%keG@2xYZFiRHW+sL$WZ$qEo?wgE zDJLiQX#4B}lTJb3bBWRp$Jvm~YAtKY6Zw+_UvERb@_sQk1a>SiowHgKkvJsP#l4iqAWhlzdGLieOh#s)#VxABf}Xk?a7Bobk44eHJuPA-n(d2T-6!W zq#SwXt8<`#!Lc*PJoIubO>JXG+H<^MWIoF%&h0B|M4k=@ZG|9iY=0R~m&wm$dA^yM zsLZoht6VCOA6XJ3W$q#$q5mW|xQX^DSu>BE?iq}F? z0q-EW^BGD~1W}83>N6E*TKfhI4AK0M_;TDCK)00U3}NTg`!P9AnjQvog>%j4lnf|V z5(*rn#G#O^7J&`3o0ly9mW@-4W!vBMMwa`&@!y?LCFi>?W+38Hf>Ma`A=iSt7o&4^ zANb5ER|S^H*C&-I^J)z_j!8=OikbHOPW@Nt0`d=78`F%t-_4dg&9*}GKQ)Z{`O zco!GwX|kLfA;Wk4hEGr(`s9jEe)*Bk{ft|hdS1d4kKs#EE;}m*#>{_g86|$&oY}E` z;aaTN&(B9l$H)EZdKAK#P7E}>XyS`ys08w1$55$bmDgR#AUl=pnGZIdmt`L`O?qhA zc3T!x^Ta6xorsPrmGRma1a}Nqf+Udx^pqj_TRp9Q*(7+28OtQ}yp~C6AS3OcK0uLc!S$z%;K}QLU8^$mmLREu#@SA^U55m z3r3`jT0#MbutYxx!hbQy6@VYAf?}UukX|-Z?%tKh1#@?l>CJu=Q%G^08Rc`HFlo!T zPs$ge+VE?kTVl1!(hEFtb!#v~4WUgrID5^ppJ^fWzmNFsx57?8pZ8x@xXF%LT-aS% z=lI3{*U8G;hs${SYoOHYc}L@rWjhMmftcQ!2(8UGrNEzkj0>cK^!->Y!|k)gO=iE0 z7_Xll4?2AeYPQ5>?`s@Q)z+*NGp*WVPtS7v*N9nMHt_!*)hpiu`s}&m33=<%eAct~ z0<|Wlu=U(B{T$;QlgayICIb-$m1bj1s4Pdy5!~P-tjI*_Vl)OyUkNYU&12ll z;{va+{dQ@4ahAmkH#6cDLktZ89U}MF_0-m5G;4bVTD-&NhNk7Z7pN0PakSTr)O@+B zf<#ewWFOY(WRjC5O7)*#qMJiE3D(+`{5HGmQ|=Zt&p-h;p;{N1t8WMQYPRf3wR+qn zP&U~94MDjgev@PyrJlz+4up=yJ5|n>N-QSWf>cz+j9F!cY@xI!3ICq9S0cab-{GWed=^JnVUY6 ziA{$nL<*J4@uR_rU8wtji_F)Ti4ar}>)Ln9J`EVksAlQ8Xf&+z@jwn{ssV;B&Kg|u5}r_jwOj4@)+i*%~GsEJnsTEjbi()AH4}eu1>)b{EH#fq%C9LZ47^M z(R`SVOj?RYsN`?{{Bo`~F7VnhD9cyPvDEm+(DL-x7GsIiijqo;y`|ae5LRp*5HBC0 zSseYQ;x!ah&c8kHyW~{C3iiA62plZD6@u5v8jLF=WaY(W%yD1JOD+y}G@U(FJ8|~U zLB7HLO+q0BItHq~vDP7v1wyBxh*V2ZqJcrmyY?%RT+fKJtm?dU&JcseO6=ELOjH;T zPKnErc@pI3GR0hvDbB5XPa>L6e!_=@e;S+i9~QQAG4vH3EZ4|w&O1M5J{oTDmPPs= z71fPr^3vzjqx)|E+1+nZ7z#Ppy1S^&O(%liT)8N&bnvpmf5T(=H{qCE*)J=!QN%?Q zH+lP>X6lQ(GgG$A<$8(Nv<}|Za5T}xXqLPjx>fV>9|Oybqb^O~AM?p#j)k7FPcheF z`S>fGSTCon_r`i$416G5yFxi7RCh*01pO>U6^BXEDT;V@swMsoV=* z&*^um6q9r$&(8#9h)=~d{ixMIVYvhP)2E9ZrRqc{B2rw)jMYLzvMebW33Pmmn307%j^IHJ=myzE`Dg{Mt%>f+AuY+@pr* zYtc_m%u&n zI1GYTzLKVvCD{kfThl?J89ICt+AY+`v_rsl&{bVqTp`7-uZncq5-pM=l1>7DKsfel z%d%&>ck}y4#XieiS0v+6$E82G2nwbJO`|291h3~6ugszq}A6j&QTi?&21~6HYXHxZ+D%sL+(HWs%PR`$z2(VBTa*6dB_aRB7jA;c~3dGx8hx;5iQ7!pwsvxOpW zwwy*QWE9AMCr>dcyeO3sqinG0tPJOlz;Ejqef-uc%-PCO@y&3X_v{4`|I&%1(x`n9|{>ZkRT9#WWc_2aeH-r@oQn^C`+rZzRU8&MxT4M#LcVr+G$* zbv3(-XAN{DruQ8z*jjVvYFpg-*~@Jub5@U^e6#I*MPEk~k!{tY++Mu!fL$MJS}?sJ zr<;BK>gYCUEbfsZ)z639u1!J!(GNZN1%z%V#}&AmHl+2Nj6S~=U7=(Rv^wwRTo3c& zgMQy08Mc~011f(}6+@lun7DK?uW_bw^6W{9hIVh?CO^)Kh zG7&7>p&!EtytoKXMBq%3akzww)uxdqJadT{D+8+&aSswX3o1nj1PFBxeSh2%kJnPe z1biz~lv7s^%xBt#n})-|VhUtmr9E_ytBaLE%4YbGkR;&wD^cs`_=BO%^qKNuecw-1 z=LcZI3YV~v4ye=8f3k=B80Q=2De2*+PxQ6f0U&9t?W6{c%hEon;$u#TKNJ)Q8?JR$ zL)MEv_RYr}b z1z!%`9V;A@s0`taIUwqQ*VnN6{QRAOq=LNr093X1X)s^z&b|7SU6mYdYHZtk^MV{O z!qx&{O;XSwOT6SCbpzy8{82=?&8P5!iXGDpS#?6OddxF&Mk$2B}>TM8ypSbs3LP6d@@_JbON^S^jf_O9qwG~PW z(bivH%5s$93U76C7!+hL{5)UU(m1N$T}_{KJDmDG+&|izu;Bm_#|WyKFC@Qqg(leL z^tmD7U%z7l0g9^0y~D6*&!B^te;@P@^-@FI7JEk+%kLkP2b+k#Z6oE#%t5ZF+XmKoK;Z0eYo1GB`_m$GV zBQ(g<%JZghQz9Qw<6*+~iQo;+mcD=A_vPK)a!I-`p!|8$QGzMytqM{!duTJWF++H= zc{F&q&HjU7_Z{hFXG5iB43%%uZ8(5-|Dd_QoTf}%Z7s4 z-PL)=Ah7rhigf2pdj^%>@W~4^9usnt`v?R%?SIXcXDXe2KjB{DjjyGu2?~1=Wr-Lx zOCgnT$GA;AUVx^=6E-DGh}tadOhMtTfzRilhK>#C84C?s)D!}bA9kMTtuwL$iB1jX z^awPD7+sq{0wxCVB(|Y02 zr~jNP?UYuVKN5TwC~Ga~V0N*4w5^4{;M8POV^6&H__vUS88)%yGwIp;%Gtpcrps2U zci~5`cRBF!$M#qExJ`QJKW>I@rz$KTqaa9w7YF!}HJBU7z`cVH?gHB#vbV$6<&Kt; zSF?@9z0~u|8}aDFyB!{KEXo`BIm@+9Iik4t<~%N&0Eb(nbQ--apRwYm?7?%&kJ_0t z4`{?ABMz=yNy;DA;Gv63>;Ss0Q?}yRQC7CSx4T%GK+m?CyYlJ#=K&>Q2 ztWMhy`ncvl)`TJ^@bFzKN#o0kldyS($OL-EN9FMv3aG>*Deix~x+BUI%XZzfr@7~_tK<{n3 zH)|_GQX@}BY@a8_s zNva8}b4DyAQZ%QhlTGzfjD-7c?>;aRuo%vhgsF{ooo%3C%YU3W9a5ipkyt7KS`UAI z6~iBMKeR+#I&c%g*+XwBo}n9mkNwG$r+%;G(cS^YCF2)2Gz`gu3bVWRWZxl&n_A8otN z@AF+5R9(B>lr2n5;=5xQs}+r0#izQZysna zTEd=B6Z9EtfN^EYFSKEvvn17Tr0jTm_t!FPJ>f<^^DT9B3l2jsq<5}9O2S>FPFpic zmt8t4+-8$qXQjjA3ZFLkEqU>*?fNMOt~;y08^|uu7nH|y>+49>#|I4yb^p+D==eTX zSro)n^T&9fRk)laf|^hF0=4lw`qx@~oaGOz9+S8B2>i1p8#>h-`==VNBk(&=7n82g zTLq9^N}j+5;n6*un)ps>uQuk)r}5gaECcow&#V= z>>XuREU>twR;31N0Ik(e%dcxRZtoW2u5)hM<^ThZEve(3L`Y$xV^6XB)^a=iGt()j zzxyZ^;=}BLR48GfO zteVg^Vp`)%+n4+7{;gh~#iDy@G1Ga&`gMBB%u2I#LY~|_3^;j^31&ze=YvR#aI78V zmE!P2FQGo)HnwcoSKFbZKBwcT>&Tnv8@T2l{3Hf@Ef$v%h*_zu_ZIh-h`2OiJvrCI zJ%l+>Sp<&(>j#fPpcr_}Xny}8dwOm&%m=$FQ77WPJ+5E&s=Okd3bVyr=$T_2U!pJ8 zQ9&;8m9-;QC0iNQ0%Pg`8GjU~ecs~@sz4M{g5frE~GQq%4K zh~^o=R*fHl?Rlx*BBJm;Ty+uZp!!lc9o&&^VQd@g4F%HlV2f~CQrD(sxjyEiXFMu( zhlEvyB?89}dTGwU@pFb&*I*^!hPj%@ z+M`XWAxL;CXj@e9ks2p#63c#R!>Jd(#m1u|0>93+^^%qXHK8grsK6D>JH?o*munk+ z)<+bDn+ncMp8(ZLT5= zGV>yvL|(%o#D`Zi`}pQk)SoV&!dJ@@4mmmevu?$*2`#vEz&2JRO}mc1kN~2@!`9>3xiuQ|Go=kwWC+$t^=o>*CV^)0gXj}i zHirfDXN19`>-lu5G72|$&E=aa#>VpN#G2puW@zHm7jQrd59U?+ISW} zqT;~s7zOGbBxhdU>=2V(l7+jP>plVPQk!SAFRW0xX62yuijb|PN{-aiThwAb5{K_f zG+Q?Co-jS2pS{oR6Mcrwl-aF|KGox5aCmK1>8lz7kDBOzP6T8D$F4HHXPYVMa0Q{W z`D}a}A>%Bu9aIRvSEBVB$ct1{HMuS3Zi!a*8P66AnE2;&LWRXr$oXr%TE9W>*~XYj zF9u$o$q;OiD!>98hnp@o>(*8#Gc$x1zWWurQ^CR^+6X4%NQV}tycQNM%@C(s;xI7K zGa)s`J2jPO_Sw*ObmX&Eso==z>Gc~{O#icb5Ye-OXAgoN{uRJlqIiP23#Wg~lC|!B ziq7*E9Sj^Gpxn3`7_b68>$k2rZ@jAYApSfG_zP*$9a?VGlpU(3Yzg5_S~#||s8cqp z(S~gXJ`uIFe>2uaWmegal9aHxSN^}2 z;*nu|AT*w+gi=yY1WSU9GSrJ+=2uY)4b|_{AOa6@ zFHhPZF+5n;WjU6A^`|J&KDa8EP%SU@*W-7{`W$!$d8J%UxBwDN6TYQhSpA_b2*sEW zEftC8v!6d-5=IXO=2vMP`BgLVXB%wP1vNjhf94J~O%?P;tSS5Z=eERyOi~-;Pz!t| z!Y=4Xn*6R{`8@)!vta^O!SO0Fh8PECQHQkr+3;Pz^!^Z#9U(2S?jo$xSq##uyz!&lX{YWVBST$Ahnb6}E=}A3jm-W}H{!g>^ zr_$%o^oQ`ned2RSIufF`=dY2Sf^0J2Vi@0#+Mdb&S|Ns{zvnsuY>w=G)1&4BAhq@|@pQ{#`XUNsph=>9}U4l4vhZwKW8_BWsWHAkUf z6%r*;=C#oV%~&H8&ztpsy>bQsnew1zk5`J&gu8SY>@z`awrV01K>=I|O$6~F>3^NX zKT5{`kJIf1qT5Nfq1CI58br8Ri~9J-087;Cn+U8Pq7n{}7%uog9aODvx6f=^{boXF z)!eG&2TUfd4Jy@xhPd9hkLd8GW=dn-6La>pl~H?7$fcCtXR~hO zo78jVUg2H6&eFhPzeBxEZY-Ev{PIWrxu$h6VUHn7AF!W_E6u(2wbUbO@Zx`+W%rk+H#U0iA%wspi=cuBxfc=?qMZQ5 z9#rpFAx#UEG|B%;0G54g_m|U7Kd+F(gyG_tEPT(wD9_`LT}?8q98AbZT>S zT5_?y)z989XtFQWHvU=ByVcOX<*50mNYbQTONK#BStSot>t#8%o>a+W`*?5X{`iue zgkCs0Mod;2V^zamK6BX?^`Sk3@k>&n-?j?%^Nb5IIgnFJ8KY?n03rfgq#hNW$_cFt z)~Bb(;dHYfiPsmhkot?JN+{edphLg9LsGCZ>EeWgnlg^k z2Lt46r3fc1iuuf?5{Uu>QF4Ee>rAkPLBR(-a~oyRv1c?AEw<`4&(aSo(9T9m^jJ){DPB+6e^+@|EGI;>=?z1td&QtOz0Qdb#jq zC|N)1wxgy|sL3*&Qa@p+Z?seNTbTK^mO_1^$6}|wzwr4@I-Thei<3SBGi)w&mwx9j z(nMB2`09ffFD5MCKX5TD8k5+{eOYP(DrYCVon^6(`2#k(xB?H~yy}NEwN(H!sss68s8+LNa%Wpj)D2*CT)0sLL(zK`I+4+)0WmNai zuMb_s_ZAMK(NF9r_X`kRa!`4P1z`vVxf#XZUl-gCaw*YM4DugtF&b+#xARsBTM|$F z2^DgYtBXjle?sj#`;vpwV`qz-!Crk&v`2sc6mn4HL-*Sgqsc!tTBeJqzT73r{fxEk zBBBd#w#<#-W=t;5Pm>sn-I-l4GSdq7u;-Vr+QV2;D2+G{Z4^Jp+=uwgg6EAYXq1fN zuH{{;i_J10xJ2%EfB$eO?(I(XjA0$2zrW7}a<#*7iCja>T`0XXwa?7CbJ(Q?Gy7tJ zljMrEb!cKat*+2l%Uc$Q!TQXG4;^cn4NO^K8qnvVqG`(f3p5u};nB~#!t+M+q%?Lv zI?%CmvUW%ET5d`ZOHnaw^bxK z6bl_&uw%>;`p1fi{@b0tZDs7rFev)CC4Hzv%fo$$yREaN#BHHbjV~K*)z*rQ>BpHn zj+`LJ!{pERXQ)hO4c_Zg|5#pR~Xe_r-G5SmRf_V&FMhmmNNK@_ScN9J3NRf}(2tqc%I zjn+EkbkHm(e0iF}$CmduZQ5?4XqvHr2gbJv+HERr|73 zY@C)mcUOc!1Bgc2)iV@Blt*!MW{4R)+JJ7UtT2!9CbzpvOgxHL47k8sl77n~|HY-l zu?!)y2t2fuz+ev+!__|r)sc)2N?;CwOLsNBK zp#$!*4kNAZFO9xOcZ*TF9H*Z3gkJJ#!)~)c-_tobr7?d=_Stt2T4`RMf79OXz+AZT zDqlk6O{00|?Yeh+FD^XkPGjUBjC*|w8}up0Xmf_h$Qd({PJ3TN6>hC@os+UYPGkJv zYlNm+;*>*dFULLT)OjIQ)YlPLGIQdZhWVc&^-Pl1_)SRDfl6FqM5x@~9Q&A6Gc0yNus5;2;b z$~aAIn6M2vHi31U`(}g9;5@c+dwrd(l?(yP7r`r9iyhEN;``{XBy%H#vcTSLH7L>( z8ljUiAdnl@o!}*L-;Ml`8LlGk;c@J_rB>AUwXP#IF59?0*Vnt7`myv_D((J(BcE=D zq_%;Eh17D-hsZP9>^)G{w}eA3xeBkd+ti6~UaHA5%XHP3V1}(|&!3-CN^Bf6&iFx| z?h7#vk<@*isLrjUN-;DTO7*FKxy4&2!w3HoUgJ7Wo%qtGaq8{hOi9sVfuXrnr0hTL zZ7=S6*l4z7kZeC&x}zI~%;qL%x)q7vCjRRVsZY2xS(FYcS5Vva`k6JQDo*j45>qNA zOQypOGh(%<(+Ub-7l_*Ds3s5%LYo9~Eb~Q3?eV$-l{d*#q|w?zkTwsTB@;11#Rc#V zh0>`*P8vloB~y)>y28e=>hgyQrZf-cpQ^rAJWaG{sM-+3ImBdhbH+@c?q4v8PHxb) zaqv@>S++q9*I=`f1ZGsYb_nCKkSVcuF6RL)TK{E3uyJt8fX2BrTit|1obl0RsiVo( z#UFdY4ca@-=UAt-csmQ^V{&U**@FZd$L%TUMOtGg!=k^L5-WCCSLrYfzVtF3C>1=_Yum>eOO!lV?2-Tb~& zGx6zDX7TpFV$^_-0hGdsS0eSPKC_AYpa2h{>wYlw^Hg1|Pjd9yrLQN_tFn;lHzaZNy(4|PG=iM2o zy_-N9dw8jNk96b?9Vr%gsTrhVm*X8~;Bn=_W4;)z;Xf}hc zkPY-z2##uh`DL7PrAEu_%Lu)_+^W);L>22S(@$y4bS4k3sG1LXuJadH+*j*i9UXh0 zMlo&^EpetMNiF>QHcH7qgx&EVxBZPyZa^WW%8GgGYbEE?if;6{M>{DECYw(QW*GH! zDy;ysLHhug;2HRH>IouVi~ULfpFnj;2(#)q2Vv`q*qzt9nUwjl7xtt0I@g@ngLiix zb@Vx42Nk^b3@MB&CY6ka9D9;Y|1R8VtJpoDP0M_`f<8-&-+_G}yC(~E`rePsm;2{?V$KAXUlAGOH>pp*p zc8#x%10Hi)A<>=q#-PXPy_@2)PU9CKJJSvbLxq83SAt~Bg9i_);DTMe#+SRG1W?Fy zo9l(>Q0#I<>#(Ek!mNLEEeS);au2j5+!3dgaKB#5VI70fxiWr%^L^ zIt?=-*&U3JWnW}Ou8hiO{I&uD9_xcvYepG`qayG%Xh?dJ;Rvx_aUU+}M^Z>8P1}>6{O69ygGZ4_|k|nKix5*J<^V3DwR>!nb(Z<+pJL!q^*ute85PZPRnyTaJo+%(Hd?7ZNr}_IF#YJ} zooPWxMf$3FVfgfTM|)GMnfxqsZpAmF*VSs=G!I+$?Orx<7os0nfl#k2F9I+zfijcf)x|c#@x~o)s^bs7slIgDnm?9Nnsu#v zD$9DYCd<4Rof@CD|RerJt%_6b6KGKh}<{i$>vpFWu)g-ooht!6Mf0>te#C_ zV1QdIE05?V>TA8Nnw4{3$9Z=O%B{;z>e5qDv~7|H@%pFfX*2%>+<|0lRD*U>jk z`i)JLwLyckq!zPXJj zqxvGARBFZ9Rgm^lo4jxTIx+J&j-ZEBHUHsY1NXV!r@bu}9{CAtj zHvWS{E^$O8?Fu10+z)p$3o^XtyIe<^aSe5mzAPLjBv9C?QTQluuB9xGTkmD))BVAU z!Jj^z@McPmD`D`R);zAI|G+I&PcRM7W~Jp2aO5F{uV>$~qHqa9IWBMkI{~dXD@arN zV?XYcP$Ul1m|T4Q^5X0F(vG!Y|R z^GRF=Ht{%@7+Mu`NUjMTf%!Fn~Qy=fPjwcnd zj5@sw?@o(2851f#-Kzg_zesf)BUGR&d%r`{;H)M$p6jX?b1+ElQyc{ygZ|6P#$NI5 zM!G?P$ufoO!wIa~%HpxtyCxK1ked0Fj8fHUj1X4U_xNDP5yx9!5`7tp82(>-?-|zQ z)`X3sTd^RpvA{+_6a=Iz2uQaf(nP7!5(Pq$5&`KYc10v~LPwF_0t5&UiXun{X^Ejl zx)5sUgz~Lew(!31kMr}p&N=?`BF}o(v(~JcSu^+C!+(wSW~=Zb`Pgfwet(tcU8Zp= zjIE~;!eVDn;1^KlwMH8i(#Rp21Xy=YYnDCa2F+%MC%pw01{WgNsf&C-f! z6~V9onFgwujl0%8L+qLNCKowEE-h>(#P-MNdu~Z%dyU2ucs^-z37+-0f<@#iyVXr| zI@3s_dSUms=R}{#czP{PBr8b+qoxO%ewd5CsKIB&ix?9&)kn1&`3f`G{1oncT}>Yp zcfEFVl`7^kF9@Ig%rUiLZpdfTc1NM=yBUC4|Krmsfz2|G*1^9h7kJ4uE#($;?#_3KRa0)-CLF_!DgcoAUDdzkS8dT}R7iWFn_CTHj1q zi}kV`ys`RLCP)`}tO1XT~*0n|X^}hO+$rS%&xDy!H2aCSz(IQtM6CnY8QInXs1*hVbhL>xk8`h2y8sl6#n=?iGvkjl$2iNxD z>iB90h)a6O%KrB+Co)z3F_rH&E-^dLu6PQSWt?*IUZ*;UN!|68+4+jk-=BK{Wx|i~ z9Y0mOWDz1QHx{0syeX4ivZ?SK*3t0BX`rr)b0i>2$E%~^rGis^_B%HC{bVGEw2khK z(ajJ&U#Px>Y*A_htw2>wKytfTx+bO_Et~Bz6t?$%tvnAJ7+9X#u6W&TvQW!RqkQ{v)%i^9uA;GLhV4 z@l=kLGAMeCx7Vw9?8&3$Aw!tODA)7hiAJFmhj2;M*$EORjic|R-~rrK*yj~*@j2`| zKI?T0Ppw;uOnTSmR$a@=xhRFX1@Rd3PoYYpsOqLhAuUC1HPN-Pe+Hu2^g>#D!h(`9 z{*AABvn^_o?$nNk1Fs-Ij6X0z>vc12wxaOA5OVH!(HbY0A5Hch7Hw687-g6~5OmMf z&pM-}U}991!-NX;a;|TSD;bGteXZW(#y#>0%RMqh;D*g*tvjtJ40$ix9|-4?I~ML{ z91#|1q+-AksBRbeqTiDAU>cDgdY^6<=gOjhqi)1V(^uDJWvCLWG1IhJ7sC%s*e0c8CnUCYtT*iM4d5q^t5U zq{NpA-qU*36cYu$J8Jy#brxosG^!+6v{kNZx#{uV&NNhOx&+g!L>ShLf6Z3cBf<^ais(g} zKh)BEm1PubU{rbgN_U0v6Cgs}?R+CMRJrc?7DugZ%4XLwi@B!tkYfJk^SE(7RP0wyLC$XFJ1B|L!Ti^h z2cb^+cCNmvvKIN(k}u0?Iee5z`O=71YnIZ%8y$SG zr28W}TvoeRdYEcp#4_!CC&Lp&j91LYxTV20G|h{;1lGiN82df$qGKW;*iy|gDY5wW z;qek~;0UNq2unwl@!_O~!w!~I)z^~1$|$GAlE<|z%2MM|Eu4Un|BNEc@*2dIe_Bn(NbP`XaBB! z)ql{b`B*A;sh^M=tFe-un{~%MJ1c;ydHBfTNi7*UZqGtm5*94jERT}%Oom=&(w#gr zyzOOYir|Wl+28>`|F|1JBQO?k{UnH|Or!-$*9M%0cL|T3oefA zcUrJ6s(i-MmPxzde*tJju2ligfa>b%*uQy*`c;1B`DfPH3^4_1hcua*j&E@U+NQWR zQ|iwf-H;M)6@p{Wo{m!z6AV>h3*#hz;&s$Yvx7vbd}b6n%c7`CwbE=@Q(9?GyS>Qe*`clEAmJ#zQ!>xg)v_m2i6tk3vc1|jGv zc=>Sw6}M;gb8)BhJ#QC-)5^`i{Jbt_<(yw!g2B?(vHP4IIIpXal8qE6t2Yo#jr-k% zL?>%wiuu&RaK`fk`HnT|=ANNTFY1;gOJHNAI?Dl^+IOZ`XU4}Ir;Z&fZM&!mT&Wsz^V^lw>e37;iEjTN7MRgkn~vvTf(V8V-`%T<&) zFP8QcmuCx`6|b72gP^WijHv3qQSBQ5_OM8N$vaFjO2uAO+PuXcC0i6!En1<8&xsP| z*Wx28g-<^D-bE|sum%Z|zzZrfpdxYv1Phm92Cn+~9mu!&wA=7pd4zDB=_Q9Ox3#8v zHof#SP{i@ms??jNp@dlLjG4fi;c|W6k&!WVb+WWt9UrJ(9c^5iH`47MF?aT%vwnS4Ysr z@)YW~E0iT$-jRIun<^L|jRh&2JJ)?zx;Z*xw3r+iF)j4v-VTt}WUqnYMO4t~+sYPh z-qSiLrEXS1C2zf^?n0T7^V8+;W8biw+!3d_CboD2uIWE}@1v;0o*tB>jCwnW>B-VQsAD$FnldtClHWg72&pD=pMu>4{m zkl1K%ue3>{1mi*0XN{Z9_ne&IuY}{mw}f%h(7X2R{r8YPn!Z^9=SyHZ6pqy%dB`g} zD4VEU2v>*6CuvyR=oy3N1OeVIG5Nw6jLb*8mk1B6?TuN!Q@sRb8Q-;}1zNUmo2q@A z?QZP7PcQJ~a?o#Gmx<%zUFaS~Gtt`xR;_$digTxl1>zgLuQPyHXepYgEx`|{2ej&h zsv~Fi7v>boxmurIE%k8}x>PxHM}rS}_N-3Gr;^RCE!Ohz4GBBJF{>014MZ^f~<2A8`2xQ?z$DP%P| zgzgQdue+U`w#Ku|EM05HA~yT{>t4c@8`QN>VfyIn4XA{$AVR#D09w&Nt>58xyX-Xn zB+h26ZC^v3tyn|^3alenrSX;S0@2fGK7@B8O1(ikfeqz>7)5=;pD$0n>ecaDUf+a} zT@h$~*Xu2S@P+}le-HJtc`fhj6q7$)N35s}f+3f5CTHlThhm|)aDHKwV znFW5B{xJ4zWv`bTvGZ*CN|hRADU-Kj$}Co#95E7V5HBK-fb|Pfx_&gs^n{aod;cxs zaW>KS2oa08fYlVwkfmamfLIXKYSCppP@Z1AvxLZyoay5y*KQ*2rLa%v()-~Wa! zL#`jWfGmkq4CI2`I!^Lf^ML4JpLmnr4S(3QbMcnhrfzNg`nxg>)Bz7_ z7Qq9M&=imuxn!N((ZaDkm+_*FVkFla2*1P_vO&;@^TCTx2yaSE+PV?QaY^I59nZ%% zO`I;QZU&NsP8Zt7S2W$~wpk!K<=<7?rTR7WV=e#7Y?*jBEAKUPPaR9bi*w|rW*f14 z3$s2jSbJJk{(WLV{{4~S$%k)tP6+az<~B_?&nh_=4QZaRs$Wk>H9WBaQIiY&@!~jU zL|4VLGgIm~uep-e`i-sNdh>$~j09ORW8FeCn62Ar5BlMv#zx3J*=(iAf*Ru}iJa|r5mJ9+qns6dSQ{0;pl-5QhYW$lACA?c`d z;)selCso4>?{l+E+BJ$ck6CRMY`ofL9RSX|o@1uew$><0X7!#S?m~h*)jg^+yNt~s z`^=VC!JEk~A#9zmm9?dVQ+?aiJBoR#8E}Bb+h>=YC`L|6q6wj`rRzb?t4*3!(|@zC zIS*Vwoy!oGh8RFRH*V?Th0AY6h)jfWir%}n?auP?bw3Nw^&56}SsRusy}>;D&bS(K z87g9n7iM6hw-;JR5WqoOGcX8KQekVL==XQ3GL4zbeX{tNunKFh+nsM8KEH-DjB3ss zz$YW`L&7LBXH>i}?c%m(mkkRinGCV6$U-4(Aj==e`}Vm+0D~qj^IICgWgm$yO;uu+Se6tN8d5nLQh0vxjFe^UhWa=D z?H)U9;Ur*An!sn>* zf16*nZXysxwPNuzT*&y($>=SBs6O74(V)Qkwx53^E6VFKy`^Rbe`ex*gzV4WHjq*;>~X?&o6pvU1L$OOlHR*_@5BM>m)ci%omFH~ zkZhof>heF>xZt=K*8TMg@qP+_Ya;t|3v)XGKjU^?eRQhn1E`>^4~Ouwd>)uJpz z$&OOdyzMd*Y|zF~oc`&342XSUk ze3Mhy0}^*Mfb@pt2gz$_p>5vdS)n#Ls}_!uxz8s?W-7OCmeVK|01L2LT)GS&A769( zBd?vWxvigw1-#REay}p;pxq#0plU@MFvpXNfK}{f+h=lhp>(_d*COrNoYM@tClo+X zQ6SJ42)wI1a3#<*bg5>S0ZVz#HqYSwd;kPv>#R1L5(k3+b?>geob>-I=Rdw`>_oW$ zPRi=S(vbHq?0-J*2chOPvp4giOt?XIH4kz2+rdP_v26?YP_fM`#WY4|l*Y6NxP!hb z9eTjnMn1Sr1jQ=zFPK8wkwn!2X;UyjY4%;cl4MM=6{Ifg zXGW3Wm8SaZvrl6$KKQWtH_|i)T{qNwWB3>^`F`<8SmQSBmZH)ll+>;T0-JePVp5c z`~Fx@yyZ>Z=XZH_{IEGC&pcUcpbGg)Az|F0wBTAGN4;OhTL3TLwqTmB01a498F8+* z)#uB&c0lHDE;#hqH<=v^Z^Y4Gr0FXF?Ptk$XbNf+4SfbSH*=3X;3xYdEm!;nv=l~O z=}B8{?&JDuaKIf<-|hW#!02%(QH7zASH01Yy$A0Yhd#c0ddF-(4%eP^2GqZnAR+nH zfYJTM_NSF|qsZe+0@~FqfTj+bX@EtaoCP%tf4;;2ZqIrx7xE(G@MM5LMrrSdBRh`D z6MLIlBoY)=WpQ5ovU!wF>+kKNyT6DiVk`?7`Y;P*^pw`F**!alj_J*c;sG_!&c@iH z|1os;e5)LI_()$)+=c*M{EppXv18}~w^o}|R$QIvCQ7AHpb11?4x z;|qTu+BxN^Zz-DXA_k%=vGiu1$IhNQ03u)syT2XSu`|aH;RX+?0RCM*P=^SW{KmfX zuhrgLy8usW!S|?5X5~vuGpdRt?nf>*S$}4*f*SZWs9VwbRRAmhcy2VTOg zlhxX#R|~sx8^U3f_kj&hr0gxms-A<6?7BPVF`!}`3e^$O@U@3+?pfcljn4t$%q#%d zY*$tPk90f;3BTGd5C0bqlrZV%7aZ_jrLp&O08E!+o9O{+%1$7*OqbBcR?wrjUhbH` ztCvAe7&uG~j~GOQ9O}`jEf=1Om0TOG+^XQ{&ac`0`w?JC*)9OGWiFW-UYj1{EUcsZ zdl5159`g;o`0SCD{_>@ld!Fo6A=iylHABV6=Q4je zlgw&3+9p09N;5G;PItqgyx#a60}=AwI3NYIeGo(bK^rZ^D!X zh5z^Y)F_@&R7s*YvjpVhK3$Kjc9@Ah##O;Q?U|Q$(a!gpL52lX;Xlsz$D(_kXMuij zx)>_)a&*qKgMpG>XxA?L;?=`KmM9YU33NtaSSb>Gx^`TRxaNM2h@!Vs9jCb z3g-TChW}HkzWZ25M!Ny-cS|RX<&xfC@jDLcyN?-ZXK72exi+sw&DhntL)U-#W}zK& zsAN)HC8<=#e5SOq!svs}P61l6rC5xgJUj?YS&9{4#_(Eoq6+TP+Ns+t=GdSYpL7Kn zc2rjS=sgg4zo2*FOS2PbGitY%I1vB)kvTIFM~T#kD)_%J$V z-rcZ%U}f)iYe@4`2UK<}7|>xf#kJiRB} zM$c$*hhi%oM;F99^`c;qsfc4`d zg!7d41PPD{XjC_f5MF8kMzcHm_P8K3!*unK3q)m|Wr-SGotS-Z7WztDW7g z>@WlB$$qC0-!+FYaV8n(nEY@ugXOSUo2yn-!AFM{xz1e@tz45;DLX%=B;B_L9q$9$ zKs|1ojf~FXyiiy8O*87`zyRJa=Mm;SfA-oSRT25XyaiD)-46vVsT`;%+3oh?Yx%?U zg$7hBa6~n9Es{98%ZL?fr#PL3(K76z3cZo@3940)s$iz~lOryH-}93%nLNS$=Q6=46~IY;rHf7VqA<+# zHKKY97?Z@&gsHaCkzQA~BPD2}4zg!MQ55iz{+kz}H=il%U;(U5HmwR)P{|;{$Tm4x zJ$*W29x;OSIvM2XY>?8gi0E?|m%g8|u;P++DDDDj&e2jmqolHR)(@W_%7#XbpEuT4 zT3RLwS@cK8Ap_@~OaTA$?`)+1UAYQGYA zCSUsaL_4$P7#=hX2nZfz3D(ZJ!dp^oX@7vBQN(}%KgB?pDV*k#=GPZ3OM7utz(^xQ z7k8(@p!CxH&I}&0LT^$j;=@;V{8*>UhqJY7WgI9##`!xd!2PvJ(qjq`FA){t@j$;v z+`W#DD!@sLb-Q0`h(Mp!Dw{Q$*tpHZXWW`c2%5uF2_&bNCe9np;#OU*$W^t_U$4KElcgfke$yxUb zlmCHYY6$Y!<0y#3#;RuPWpRr^dGb_nM?{j>8&5_Deoq#TUq|=jIlv@q)0q}r*fmja zR7f+79yz`~w&j)^qaJhu7nIRN$&$P8s+sYw%&&<*oAg?@^7MWXg_H!XS3&gw*7l+SZdKoPp4)E#T0m`S=Pn?bP&fAY1gLIPJc}~#J zY$L~6e6*;C1292Ftu1sc=_MSQ_aI_#@lfZC7b<2y<3N;obl9Ld-a#}txuLGv?Lx?R zM(TeK=bx3!b;3B?NK#czEnm!4f39+4biXcv-$0a@clWVRmlaHrYu+QORctD+uFiLz zwcN7l02<;uf7Mpn67$@x?ekwq*b{~Aa$d7~j!hewbPt%{QB=UWItkOy^ zhMx4Ou4r&JQ%rc%B5SXR$XSjlUpeo&ac=wL%9aXCU(N9@4$ZbFq|t7+MO8~Q^^)nJ zk&vi7@?mXpNzc-#o6L~vy*WyLJo)%LV^cAWuJtz{APNK&;d|}Wt-w_cdAE6jc3*5B zs_iid=e5B;j6v_q-$yIIa{@f-ztId95i;?TLA3><)*YW&a>nHN+|6;Wh3G2D$D2kU zjIW`cH}B+jI~rTojsPO`-)a3^b>eH{+sl7ZP2&x_ubn$hXc55=mNc8!XzqlEco7>9{G5g+yx2Gu$Uv`BqN75rws=D=^ zNblKIY&tfIycRu%NU@n~sYTYx^enI|ws|rcD#%1M0)Fe?7B86l{g9ryx%rg8ho#lS zf;Xk(d^9)h4ZQcxQZ~dMaicX7ZF~ypb^UHsrI=T4$$4|jnj4RwJRfeef`AAeWpGhD z|DmBrsfT(k#ga9L1PV`}r}Z+S-1CH~o8^6Frc;B_P8%X_Nyh!pYyzRRvZG5cmJJ`< z?UtLOIP2S^=H>@E$eK|JYk^@^%CC)}M-th_p8Y&*qjmxWLYKGYV1W7Oy03CG^5h5- z2)5L5G0UIoNzuY8UAwj3!=6*pkG=`waF%S}Y#OCgam{uf8$L@1ZPn2pl|Ex9@rXz3 zD~)ix%R_Ye0BgGQNTGgjH`);yl!4}l#t>4oM!Cs zc^?^P;G=gwD_SaqXXu8ji&eIF55_v-h{yYKbPQ}yu9E!m(~SZ%TVLSMh8$l(EDrue zRy4D-ib3ou4;-9ZK59bSCYovPcdsm8T>7FqpS@oSC!K0)*$~2rkAPs}m%H7ZFel&Cw{fd z<`j2~7rs-ea^J+WL^t!cP~UXzmeknca?%2a#YU}aj~L=XuN7A!8|X0f1NlR&1#}u0 zjdNQ!dWZ$hB(dE>LT$FADLpeqEe&>}S{9-Q!klnmjwXT2ajwwheoI%$mKd?h3tpuq zLyqFn7-h7FJf`2-rwnrSv$2&`5h>nv+ukSw?purU{%@tZ#HSmj^`kRvkHfpZOQQCR z2RcGAsoL{4sz0mKuT#hgFZtfWs zZXV5>fS79KlugsumaXGekhStXf0x%C{plgZlzUU^`8jYg&5@N_^UJS4FfcM|mgh{b zz9HI|cw{nX9nnhe#XHYlBn!77M3HX5`ezqG>!=C7=H-1Q1oU_jeQKN(XN6Y4P}uma zd6@TtG8;GwIObfubIN&~L=V@zorLFS@mlsY3As_SO+^mit@*8LH$$Atra_iw((Uv< zane4HWpccBa^uAo_a+PbCIUtyDu1VkjW}maZ9j>of}UtZw#!Tw70gY`R~sBF?M7Oo zaVPqCpx&ff7Kf(QR+Q30IH;fMsq8fTlkRZAa1o-w3js8L%AcF|LUtd-1Nr4u_H%dN zx@ctm@a!|u+57;cTYyN%{E0eG9OdFl7-07%hP-_9b$QP@^9n@MGE0l8wsuHoNm))A zsUno8KeDOyWr7cn3%a;!t+ez{3UeY1fDA!)W7sIWF06oHEk#lqrS6Y1-+ce}A%!rr zp>=?i_2vM?Sr|^YIrRKr4|t*w6zArk{pZap;7!ZSEv8*-@xwEa}mOCKU)qwIgEOa3~OPV zLO`cMnefYk*6iw#!w$IEb^6OwQt@{t{<$nEl@Z|<{q?e=AV13V$!74i%OXW=!m+y5OLcP67p5^Wbg8q_wAs_o+|j@;J=IJ5=eAn zebneociE}}O_UgzjFz`4!gWeUW==kd zaV37WVziiq0Tf(OVWK+vquIpqS48JHH^tSEBX>6b07tww2L}g}0J~)fXbJwXmYn~b zp6Ivgd(*2Iz3MAXS{|ix-2}ZSA_5g>CTRosXMne3{^Y`Sd8HQIQw+B%Vw7Yc zY(!IV7?x(d=I0-E01i(6V}kl2&&kWOPnPUDY`^a*DW>Pom1X$%k{9FADnEb7xGcz= zxcuOp67!9jq8^7(Ejc&mYg5FOxu?w+A9oS|O;PtZ`TO||e7!#GE>N2vldvzzs>s&> zmsWZW{&i-5k3@jXV?CCecU?sPtjgymd=_Xu{}oRE0NK>4b+ex#5mN3+aUu93ixoP` zHXQePOge%`nEpKCX%lFC;mC;-w$MEv3?ma_!V=!adX`Z^C(0yzav_L2q@*_-$ZGk6 zfKYJp=}SvXJJfm$=QwnoI!M=2wccy-(9(I{IU+P?*%)_|b5-$v8qb3%^P6||HU^I` zF{^z3{XQ85&zFbT%}fy&MxM(MxcBykE*;0)AU-#>n%+DI2x&?v(PWNb+l1@P7ee6` ztDiRq>i+p9D1xafXqkaGtJ1Rk4$pT3h(!!{s>$eC0RhzvsCVANarqXOQUT|QJ^IQr zkGo2EeyO~Xh3}HI0>H`xmmUolBw#_G@&-mm2ghoMhR7p#6e!<^mY6?9{a*5XuZ0x5 zd!-W@nKTCPCETvF_k0zbTWtVoC->>omj(55ge%{~PwaCyXS;an{je?4P~s;W=Z)0sH**OfrzO-vTvlWUoxK(xMkRe zyWc+VH2Hy#YL=0t09lTKUu0sc8*iG~Rmri8bL8L{*$DUWyp&*+r+pIwq=M%Y8rxy%f_z1pJyuJF_L}*7;##Eb~+z46SxY&TYDY z}=B`4m3$_>sJHRJHTt(0Pvi)fb6tMVqEF7ZyBiC zbLr?~rh9DWONu1Pv2!l>WatTzE1I6c&9p;Y#09+yO3xpgao{yBn#n_pr~W$O{W1b= zPjg(WGh&>JB;;aD_ryrq-{0u5;sYG!-QBiIqb(W@bEUN4t6r~BFs)HIF<6~_r<>KU;S9o5c_M}++np7ACWg)yjT~|JbXE=!ys>8xY^eTDs(3p z>OhO2G+CVBqu9m@tY4J82jvdp#mkoo&MVOpA_fjCDLlG;v1J5B{(18j?^idNe!-l| z^1q=PIf4P(bcsWfPgexc%!XT|&!0U@s(7H`0qt?Qu^B<(G&v5zK;qh`^5#5MXga) z%avko4?#BNb8KgW3DW`Ap91vlxn>(wX7Iu-35>DdFxzXtbTTB*?D&HSyK5~2B-^KTE#)5chZ_MBWwjnnz1(#4wmGp2u};&mPZVgj9~ zMSzh{+;`m_sKQ_$>Jl;GB;CsERRv4mgea2j=(4feKa~J@(>{)JqyY7IszdjP<6dV$ z4Q;?ON=@rhYS6y}W<{?j(gv($hGTyW$Xa9nfcD_LqWPrO>C|7YJLGGgWg7UMB!h3d zJyd~i_#Z!2Rqbh{G>7Byv?#7mBmJO&{zojMEXaNEtp+)SKno+U$kBvbsh7 z5h@#b0dD|+pQ+5&^j`vHp#R1egsHGr6K?mM+_hqTy6A%5ySrpVfIVaSX#-{(f_-dZ zMyLlWX{9obq45|rE1gr)b+jAEg2w2q6|v@fZJnmxcNYI8V#$&^P`76p#u6K~SDYrl zK$rA(UqTi0YyZH+fTNW1Pu91i+Z(+$Yj7ulIsLOGAKbiU0 zBaUpZM>)ivg2iQyM)L179XwnhZd%$t6k(IWHdJYW&Dk zJDItwEt4i#`(F&bEK*x|Ys)bgO*~(_A8y+JX>*qD(FH}af)T}ZIhNtIt4_v&|gHd&$(d;$`( zMLyqNN`J29*Y#shOiA^vrbue5jIY&l#wmmdS&%>U@FeqIx)nB+z=R;N_n*~P#nI0&jI1|fjDr||>o0!BLw`!)ijpVPW8_#pu*ju7fMZQ?kxbBXiy{5WkNgzPEtQ#}K&9zd{gaP& zJS*o3n%tcRj6|V;oOrwki`Ga`>?`$|{F)~YXv8~5EL&m)0Mj=Ll=?QnD>wM;dy2wA zZwM2Ra?J+1LiP;sRWJ@)124HOfa8_U6*Ks~?R`5Ms$?4l(mwTohDKMI;3{-~M!am0f$iG<0~Sp7V+nyhTx=%FtH;O=WBLIrVP zqnWKWG8#|ySzAywXDxw5lsXxW?hhF9o%1*VdD$%s}1%-Mo^FMZeHkJ7{N(rjL}DUiIhZ z=03!hu$L=stz#A|O2UHsUUK=KWma5y3mAiIeGMXZ37JxYtZ|`t@ z2J{+E0-P3jRkUSOWN>Nk+sjY0B$Pm_ljd}6iQf+4Q}Wz*=%2ea@1j84kDAiv=I@dq zG%QR*<2p#!&PE6sw0PoZel=)qaDi*;6Z0v5Wv&$jKxzB#-e*` zzwfg^nEqd&z7s)56a8-~8c*pNv%X6rQUD0eSep8B7af4Yvi(-GgUKjJKKC*y1%RlR znE#^t;QUKA0Hjmd#3c6Fvu78tNKb*jk+qxm=;+*$zeMnqrz9#~QHE8i zFX?uSY(W{WM}F00ceSUdv%b9W+kVnIRq&fm0>&pJM82&A-6e)Uli?E-Y{&~ona1p* z11#phZK70dAQvixSN+GYMgIIc4eauG;?7^Ew^6r38C0k%t_5;*;Ge4U&1*SV?mqcH D?6RHh literal 63551 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�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"] edition = "2018" description = "Sv2 data format" @@ -9,7 +9,7 @@ repository = "https://github.com/stratum-mining/stratum" [dependencies] serde = { version = "1.0.89", default-features = false, optional = true } -framing_sv2 = { version = "1.1.0", path = "../../../protocols/v2/framing-sv2" } +framing_sv2 = { version = "1.0.0", path = "../../../protocols/v2/framing-sv2" } noise_sv2 = { version = "1.0", path = "../../../protocols/v2/noise-sv2", optional=true} binary_sv2 = { version = "1.0.0", path = "../../../protocols/v2/binary-sv2/binary-sv2" } const_sv2 = { version = "1.0.0", path = "../../../protocols/v2/const-sv2"} diff --git a/protocols/v2/codec-sv2/src/lib.rs b/protocols/v2/codec-sv2/src/lib.rs index f5cbc013d2..01f1ee02b8 100644 --- a/protocols/v2/codec-sv2/src/lib.rs +++ b/protocols/v2/codec-sv2/src/lib.rs @@ -21,9 +21,9 @@ pub use encoder::Encoder; #[cfg(feature = "noise_sv2")] pub use encoder::NoiseEncoder; -#[cfg(feature = "noise_sv2")] -pub use framing_sv2::framing2::HandShakeFrame; pub use framing_sv2::framing2::{Frame, Sv2Frame}; +#[cfg(feature = "noise_sv2")] +pub use framing_sv2::framing2::{HandShakeFrame, NoiseFrame}; #[cfg(feature = "noise_sv2")] pub use noise_sv2::{self, Initiator, NoiseCodec, Responder}; diff --git a/protocols/v2/framing-sv2/Cargo.toml b/protocols/v2/framing-sv2/Cargo.toml index 67465688dc..551eb4645e 100644 --- a/protocols/v2/framing-sv2/Cargo.toml +++ b/protocols/v2/framing-sv2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framing_sv2" -version = "1.1.0" +version = "1.0.0" authors = ["fi3 "] edition = "2018" description = "Sv2 frames" diff --git a/protocols/v2/framing-sv2/src/framing2.rs b/protocols/v2/framing-sv2/src/framing2.rs index 4ba8960633..95afc617dd 100644 --- a/protocols/v2/framing-sv2/src/framing2.rs +++ b/protocols/v2/framing-sv2/src/framing2.rs @@ -15,8 +15,6 @@ type Slice = Vec; type Slice = buffer_sv2::Slice; impl Sv2Frame { - /// Maps a `Sv2Frame` to `Sv2Frame` by applying `fun`, - /// which is assumed to be a closure that converts `A` to `C` pub fn map(self, fun: fn(A) -> C) -> Sv2Frame { let serialized = self.serialized; let header = self.header; @@ -33,39 +31,31 @@ pub trait Frame<'a, T: Serialize + GetSize>: Sized { type Buffer: AsMut<[u8]>; type Deserialized; - /// Write the serialized `Frame` into `dst`. + /// Serialize the frame into dst if the frame is already serialized it just swap dst with + /// itself fn serialize(self, dst: &mut [u8]) -> Result<(), Error>; - /// Get the payload + //fn deserialize(&'a mut self) -> Result; + fn payload(&'a mut self) -> &'a mut [u8]; - /// Returns `Some(self.header)` when the frame has a header (`Sv2Frame`), returns `None` where it doesn't (`HandShakeFrame`). + /// If is an Sv2 frame return the Some(header) if it is a noise frame return None fn get_header(&self) -> Option; - /// Try to build a `Frame` from raw bytes. - /// Checks if the payload has the correct size (as stated in the `Header`). - /// Returns `Self` on success, or the number of the bytes needed to complete the frame - /// as an error. Nothing is assumed or checked about the correctness of the payload. + /// Try to build an Frame frame from raw bytes. + /// It return the frame or the number of the bytes needed to complete the frame + /// The resulting frame is just a header plus a payload with the right number of bytes nothing + /// is said about the correctness of the payload fn from_bytes(bytes: Self::Buffer) -> Result; - /// Builds a `Frame` from raw bytes. - /// Does not check if the payload has the correct size (as stated in the `Header`). - /// Nothing is assumed or checked about the correctness of the payload. fn from_bytes_unchecked(bytes: Self::Buffer) -> Self; - /// Helps to determine if the frame size encoded in a byte array correctly representing the size of the frame. - /// - Returns `0` if the byte slice is of the expected size according to the header. - /// - Returns a negative value if the byte slice is smaller than a Noise Frame header; this value - /// represents how many bytes are missing. - /// - Returns a positive value if the byte slice is longer than expected; this value - /// indicates the surplus of bytes beyond the expected size. fn size_hint(bytes: &[u8]) -> isize; - /// Returns the size of the `Frame` payload. fn encoded_length(&self) -> usize; - /// Try to build a `Frame` from a serializable payload. - /// Returns `Some(Self)` if the size of the payload fits in the frame, `None` otherwise. + /// Try to build an Frame frame from a serializable payload. + /// It return a Frame if the size of the payload fit in the frame, if not it return None fn from_message( message: T, message_type: u8, @@ -74,12 +64,11 @@ pub trait Frame<'a, T: Serialize + GetSize>: Sized { ) -> Option; } -/// Abstraction for a SV2 Frame. #[derive(Debug, Clone)] pub struct Sv2Frame { header: Header, payload: Option, - /// Serialized header + payload + /// Serializsed header + payload serialized: Option, } @@ -93,16 +82,20 @@ impl Default for Sv2Frame { } } -/// Abstraction for a Noise Handshake Frame -/// Contains only a `Slice` payload with a fixed length -/// Only used during Noise Handshake process #[derive(Debug)] -pub struct HandShakeFrame { +pub struct NoiseFrame { payload: Slice, } -impl HandShakeFrame { - /// Returns payload of `HandShakeFrame` as a `Vec` +pub type HandShakeFrame = NoiseFrame; + +#[cfg(feature = "with_buffer_pool")] +impl From>> for Sv2Frame { + fn from(_: EitherFrame>) -> Self { + unreachable!() + } +} +impl NoiseFrame { pub fn get_payload_when_handshaking(&self) -> Vec { self.payload[0..].to_vec() } @@ -112,9 +105,8 @@ impl<'a, T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<'a, T> for type Buffer = B; type Deserialized = B; - /// Write the serialized `Sv2Frame` into `dst`. - /// This operation when called on an already serialized frame is very cheap. - /// When called on a non serialized frame, it is not so cheap (because it serializes it). + /// Serialize the frame into dst if the frame is already serialized it just swap dst with + /// itself #[inline] fn serialize(self, dst: &mut [u8]) -> Result<(), Error> { if let Some(mut serialized) = self.serialized { @@ -137,28 +129,30 @@ impl<'a, T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<'a, T> for } } - /// `self` can be either serialized (`self.serialized` is `Some()`) or - /// deserialized (`self.serialized` is `None`, `self.payload` is `Some()`). - /// This function is only intended as a fast way to get a reference to an - /// already serialized payload. If the frame has not yet been - /// serialized, this function should never be used (it will panic). + // self can be either serialized (it cointain an AsMut<[u8]> with the serialized data or + // deserialized it contain the rust type that represant the Sv2 message. If the type is + // deserialized self.paylos.is_some() is true. To get the serialized payload the inner type + // should be serialized and this function should never be used, cause is intended as a fast + // function that return a reference to an already serialized payload. For that the function + // panic. fn payload(&'a mut self) -> &'a mut [u8] { if let Some(serialized) = self.serialized.as_mut() { &mut serialized.as_mut()[Header::SIZE..] } else { // panic here is the expected behaviour - panic!("Sv2Frame is not yet serialized.") + panic!() } } - /// `Sv2Frame` always returns `Some(self.header)`. + /// If is an Sv2 frame return the Some(header) if it is a noise frame return None fn get_header(&self) -> Option { Some(self.header) } - /// Tries to build a `Sv2Frame` from raw bytes, assuming they represent a serialized `Sv2Frame` frame (`Self.serialized`). - /// Returns a `Sv2Frame` on success, or the number of the bytes needed to complete the frame - /// as an error. `Self.serialized` is `Some`, but nothing is assumed or checked about the correctness of the payload. + /// Try to build a Frame frame from raw bytes. + /// It return the frame or the number of the bytes needed to complete the frame + /// The resulting frame is just a header plus a payload with the right number of bytes nothing + /// is said about the correctness of the payload #[inline] fn from_bytes(mut bytes: Self::Buffer) -> Result { let hint = Self::size_hint(bytes.as_mut()); @@ -181,34 +175,23 @@ impl<'a, T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<'a, T> for } } - /// After parsing `bytes` into a `Header`, this function helps to determine if the `msg_length` - /// field is correctly representing the size of the frame. - /// - Returns `0` if the byte slice is of the expected size according to the header. - /// - Returns a negative value if the byte slice is shorter than expected; this value - /// represents how many bytes are missing. - /// - Returns a positive value if the byte slice is longer than expected; this value - /// indicates the surplus of bytes beyond the expected size. #[inline] fn size_hint(bytes: &[u8]) -> isize { match Header::from_bytes(bytes) { Err(_) => { - // Returns how many bytes are missing from the expected frame size + // Return incorrect header length (Header::SIZE - bytes.len()) as isize } Ok(header) => { if bytes.len() - Header::SIZE == header.len() { - // expected frame size confirmed 0 } else { - // Returns how many excess bytes are beyond the expected frame size (bytes.len() - Header::SIZE) as isize + header.len() as isize } } } } - /// If `Sv2Frame` is serialized, returns the length of `self.serialized`, - /// otherwise, returns the length of `self.payload`. #[inline] fn encoded_length(&self) -> usize { if let Some(serialized) = self.serialized.as_ref() { @@ -221,8 +204,8 @@ impl<'a, T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<'a, T> for } } - /// Tries to build a `Sv2Frame` from a non-serialized payload. - /// Returns a `Sv2Frame` if the size of the payload fits in the frame, `None` otherwise. + /// Try to build an Frame frame from a serializable payload. + /// It returns a Frame if the size of the payload fits in the frame, if not it returns None fn from_message( message: T, message_type: u8, @@ -239,29 +222,35 @@ impl<'a, T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<'a, T> for } } -impl<'a> Frame<'a, Slice> for HandShakeFrame { +#[inline] +pub fn build_noise_frame_header(frame: &mut [u8], len: u16) { + frame[0] = len.to_le_bytes()[0]; + frame[1] = len.to_le_bytes()[1]; +} + +impl<'a> Frame<'a, Slice> for NoiseFrame { type Buffer = Slice; type Deserialized = &'a mut [u8]; - /// Put the Noise Frame payload into `dst` + /// Serialize the frame into dst if the frame is already serialized it just swap dst with + /// itself #[inline] fn serialize(mut self, dst: &mut [u8]) -> Result<(), Error> { dst.swap_with_slice(self.payload.as_mut()); Ok(()) } - /// Get the Noise Frame payload #[inline] fn payload(&'a mut self) -> &'a mut [u8] { &mut self.payload[NoiseHeader::HEADER_SIZE..] } - /// `HandShakeFrame` always returns `None`. + /// If is an Sv2 frame return the Some(header) if it is a noise frame return None fn get_header(&self) -> Option { None } - /// Builds a `HandShakeFrame` from raw bytes. Nothing is assumed or checked about the correctness of the payload. + // For a NoiseFrame from_bytes is the same of from_bytes_unchecked fn from_bytes(bytes: Self::Buffer) -> Result { Ok(Self::from_bytes_unchecked(bytes)) } @@ -271,13 +260,6 @@ impl<'a> Frame<'a, Slice> for HandShakeFrame { Self { payload: bytes } } - /// After parsing the expected `HandShakeFrame` size from `bytes`, this function helps to determine if this value - /// correctly representing the size of the frame. - /// - Returns `0` if the byte slice is of the expected size according to the header. - /// - Returns a negative value if the byte slice is smaller than a Noise Frame header; this value - /// represents how many bytes are missing. - /// - Returns a positive value if the byte slice is longer than expected; this value - /// indicates the surplus of bytes beyond the expected size. #[inline] fn size_hint(bytes: &[u8]) -> isize { if bytes.len() < NoiseHeader::HEADER_SIZE { @@ -294,16 +276,15 @@ impl<'a> Frame<'a, Slice> for HandShakeFrame { } } - /// Returns the size of the `HandShakeFrame` payload. #[inline] fn encoded_length(&self) -> usize { self.payload.len() } - /// Tries to build a `HandShakeFrame` frame from a byte slice. - /// Returns a `HandShakeFrame` if the size of the payload fits in the frame, `None` otherwise. - /// This is quite inefficient, and should be used only to build `HandShakeFrames` - // TODO check if is used only to build `HandShakeFrames` + /// Try to build a `Frame` frame from a serializable payload. + /// It returns a Frame if the size of the payload fits in the frame, if not it returns None + /// Inneficient should be used only to build `HandShakeFrames` + /// TODO check if is used only to build `HandShakeFrames` #[allow(clippy::useless_conversion)] fn from_message( message: Slice, @@ -321,7 +302,6 @@ impl<'a> Frame<'a, Slice> for HandShakeFrame { } } -/// Returns a `HandShakeFrame` from a generic byte array #[allow(clippy::useless_conversion)] pub fn handshake_message_to_frame>(message: T) -> HandShakeFrame { let mut payload = Vec::new(); @@ -331,10 +311,6 @@ pub fn handshake_message_to_frame>(message: T) -> HandShakeFrame } } -/// Basically a boolean bit filter for `extension_type`. -/// Takes an `extension_type` represented as a `u16` and a boolean flag (`channel_msg`). -/// If `channel_msg` is true, it sets the most significant bit of `extension_type` to 1, -/// otherwise, it clears the most significant bit to 0. fn update_extension_type(extension_type: u16, channel_msg: bool) -> u16 { if channel_msg { let mask = 0b1000_0000_0000_0000; @@ -345,8 +321,11 @@ fn update_extension_type(extension_type: u16, channel_msg: bool) -> u16 { } } -/// A wrapper to be used in a context we need a generic reference to a frame -/// but it doesn't matter which kind of frame it is (`Sv2Frame` or `HandShakeFrame`) +/// A frame can be either +/// 1: Sv2Frame +/// 2: NoiseFrame +/// 3: HandashakeFrame +/// #[derive(Debug)] pub enum EitherFrame { HandShake(HandShakeFrame), diff --git a/protocols/v2/framing-sv2/src/header.rs b/protocols/v2/framing-sv2/src/header.rs index 05272b52a7..4262e90ad8 100644 --- a/protocols/v2/framing-sv2/src/header.rs +++ b/protocols/v2/framing-sv2/src/header.rs @@ -7,7 +7,6 @@ use binary_sv2::{Deserialize, Serialize, U24}; use const_sv2::{AEAD_MAC_LEN, SV2_FRAME_CHUNK_SIZE}; use core::convert::TryInto; -/// Abstraction for a SV2 Frame Header. #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub struct Header { extension_type: u16, // TODO use specific type? @@ -33,7 +32,6 @@ impl Header { pub const SIZE: usize = const_sv2::SV2_FRAME_HEADER_SIZE; - /// Construct a `Header` from ray bytes #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() < Self::SIZE { @@ -54,7 +52,6 @@ impl Header { }) } - /// Get the payload length #[allow(clippy::len_without_is_empty)] #[inline] pub fn len(&self) -> usize { @@ -62,7 +59,6 @@ impl Header { inner as usize } - /// Construct a `Header` from payload length, type and extension type. #[inline] pub fn from_len(len: u32, message_type: u8, extension_type: u16) -> Option
{ Some(Self { @@ -72,23 +68,19 @@ impl Header { }) } - /// Get the `Header` message type. pub fn msg_type(&self) -> u8 { self.msg_type } - /// Get the `Header` extension type. pub fn ext_type(&self) -> u16 { self.extension_type } - /// Check if `Header` represents a channel message pub fn channel_msg(&self) -> bool { let mask = 0b0000_0000_0000_0001; self.extension_type & mask == self.extension_type } - /// Calculate the length of the encrypted `Header` pub fn encrypted_len(&self) -> usize { let len = self.len(); let mut chunks = len / (SV2_FRAME_CHUNK_SIZE - AEAD_MAC_LEN); diff --git a/protocols/v2/framing-sv2/src/lib.rs b/protocols/v2/framing-sv2/src/lib.rs index 34fe8708b6..64fa5a7fda 100644 --- a/protocols/v2/framing-sv2/src/lib.rs +++ b/protocols/v2/framing-sv2/src/lib.rs @@ -1,33 +1,25 @@ -//! The SV2 protocol is binary, with fixed message framing. -//! Each message begins with the extension type, message type, and message length (six bytes in total), followed by a variable length message. -//! -//! This crate provides primitives for framing of SV2 binary messages. -//! -//! The message framing is outlined below ([according to SV2 specs](https://stratumprotocol.org/specification/03-Protocol-Overview/#32-framing)): -//! -//! | Protocol Type | Byte Length | Description | -//! |----------------|-------------|-------------| -//! | `extension_type` | `U16` | Unique identifier of the extension describing this protocol message.

Most significant bit (i.e.bit `15`, `0`-indexed, aka `channel_msg`) indicates a message which is specific to a channel, whereas if the most significant bit is unset, the message is to be interpreted by the immediate receiving device.

Note that the `channel_msg` bit is ignored in the extension lookup, i.e.an `extension_type` of `0x8ABC` is for the same "extension" as `0x0ABC`.

If the `channel_msg` bit is set, the first four bytes of the payload field is a `U32` representing the `channel_id` this message is destined for (these bytes are repeated in the message framing descriptions below).

Note that for the Job Declaration and Template Distribution Protocols the `channel_msg` bit is always unset. | -//! | `msg_type` | `U8` | Unique identifier of the extension describing this protocol message. | -//! | `msg_length` | `U24` | Length of the protocol message, not including this header. | -//! | `payload` | `BYTES` | Message-specific payload of length `msg_length`. If the MSB in `extension_type` (the `channel_msg` bit) is set the first four bytes are defined as a `U32` `"channel_id"`, though this definition is repeated in the message definitions below and these 4 bytes are included in `msg_length`. | -//! -//! # Features -//! This crate can be built with the following features: -//! - `with_serde`: builds `binary_sv2` and `buffer_sv2` crates with `serde`-based encoding and decoding. -//! - `with_buffer_pool`: uses `buffer_sv2` to provide a more efficient allocation method for `non_std` environments. Please refer to `buffer_sv2` crate docs for more context. -//! -//! The `with_serde` feature flag is only used for the Message Generator, and deprecated for any other kind of usage. It will likely be fully deprecated in the future. - #![no_std] extern crate alloc; -/// SV2 framing types +/// +/// Sv2 messages are framed as +/// ```txt +/// extension type: u16 +/// msg type: u8 +/// msg length: u24 +/// payload: [u8; msg length] +/// ``` +/// +/// Sv2 messages can be encapsulated in noise messages, noise messages are framed as: +/// +/// ```txt +/// msg length: u16 +/// payload: [u8; msg length] +/// ``` +/// +/// pub mod framing2; -/// SV2 framing errors pub mod error; - -/// SV2 framing header pub mod header; pub use error::Error; diff --git a/protocols/v2/roles-logic-sv2/Cargo.toml b/protocols/v2/roles-logic-sv2/Cargo.toml index 4254d6a1f5..526a13ed51 100644 --- a/protocols/v2/roles-logic-sv2/Cargo.toml +++ b/protocols/v2/roles-logic-sv2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roles_logic_sv2" -version = "1.1.0" +version = "1.0.0" edition = "2018" description = "Common handlers for use within SV2 roles" license = "MIT OR Apache-2.0" @@ -17,7 +17,7 @@ mining_sv2 = { path = "../../../protocols/v2/subprotocols/mining", version = "^1 template_distribution_sv2 = { path = "../../../protocols/v2/subprotocols/template-distribution", version = "^1.0.0" } job_declaration_sv2 = { path = "../../../protocols/v2/subprotocols/job-declaration", version = "^1.0.0" } const_sv2 = { version = "^1.0.0", path = "../../../protocols/v2/const-sv2"} -framing_sv2 = { version = "^1.1.0", path = "../../../protocols/v2/framing-sv2" } +framing_sv2 = { version = "^1.0.0", path = "../../../protocols/v2/framing-sv2" } tracing = { version = "0.1"} chacha20poly1305 = { version = "0.10.1"} nohash-hasher = "0.2.0" diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 7b588075e0..67b803622a 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -78,55 +78,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "async-attributes" version = "1.1.2" @@ -150,13 +101,13 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.2.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", ] @@ -176,13 +127,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.11.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" dependencies = [ + "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.1.0", + "fastrand 2.0.2", "futures-lite 2.3.0", "slab", ] @@ -193,7 +145,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.2.0", "async-executor", "async-io 2.3.2", "async-lock 3.3.0", @@ -234,8 +186,8 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.0", - "rustix 0.38.34", + "polling 3.6.0", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -274,13 +226,13 @@ dependencies = [ [[package]] name = "async-recursion" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] @@ -312,9 +264,9 @@ dependencies = [ [[package]] name = "async-task" -version = "4.7.1" +version = "4.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "atomic-waker" @@ -335,9 +287,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" @@ -458,16 +410,18 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.2.0", "async-lock 3.3.0", "async-task", + "fastrand 2.0.2", "futures-io", "futures-lite 2.3.0", "piper", + "tracing", ] [[package]] @@ -489,9 +443,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" @@ -507,9 +461,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -552,49 +506,9 @@ dependencies = [ "zeroize", ] -[[package]] -name = "clap" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.61", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - [[package]] name = "codec_sv2" -version = "1.1.0" +version = "1.0.1" dependencies = [ "binary_sv2", "buffer_sv2", @@ -605,12 +519,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - [[package]] name = "common_messages_sv2" version = "1.0.0" @@ -621,9 +529,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -748,9 +656,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.3.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -769,11 +677,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -788,9 +696,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "fnv" @@ -800,7 +708,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "framing_sv2" -version = "1.1.0" +version = "1.0.0" dependencies = [ "binary_sv2", "buffer_sv2", @@ -877,7 +785,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.0.2", "futures-core", "futures-io", "parking", @@ -892,7 +800,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] @@ -937,9 +845,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -976,9 +884,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" dependencies = [ "bytes", "fnv", @@ -1015,15 +923,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" @@ -1109,9 +1011,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", @@ -1141,7 +1043,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.6", "tokio", "tower", "tower-service", @@ -1155,7 +1057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.14.3", ] [[package]] @@ -1187,12 +1089,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - [[package]] name = "itoa" version = "1.0.11" @@ -1201,7 +1097,7 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jd_client" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", "async-recursion 0.3.2", @@ -1225,7 +1121,7 @@ dependencies = [ [[package]] name = "jd_server" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", "binary_sv2", @@ -1242,6 +1138,7 @@ dependencies = [ "rand", "roles_logic_sv2", "rpc_sv2", + "secp256k1 0.28.2", "serde", "serde_json", "stratum-common", @@ -1270,7 +1167,7 @@ dependencies = [ [[package]] name = "key-utils" -version = "1.1.0" +version = "1.0.0" dependencies = [ "bs58", "secp256k1 0.28.2", @@ -1294,9 +1191,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linux-raw-sys" @@ -1312,9 +1209,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1337,30 +1234,25 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mining-device" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", "async-recursion 0.3.2", "async-std", "binary_sv2", "buffer_sv2", - "clap", "codec_sv2", "const_sv2", "futures", - "key-utils", "network_helpers_sv2", "rand", "roles_logic_sv2", - "sha2 0.10.8", "stratum-common", - "tracing", - "tracing-subscriber", ] [[package]] name = "mining_proxy_sv2" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", "async-recursion 0.3.2", @@ -1412,7 +1304,7 @@ dependencies = [ [[package]] name = "network_helpers_sv2" -version = "2.0.0" +version = "1.0.1" dependencies = [ "async-channel 1.9.0", "async-std", @@ -1455,10 +1347,11 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ + "autocfg", "num-integer", "num-traits", ] @@ -1474,9 +1367,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.19" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -1526,9 +1419,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", @@ -1536,15 +1429,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -1564,14 +1457,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1586,7 +1479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.0.2", "futures-io", ] @@ -1608,15 +1501,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.3.9", "pin-project-lite", - "rustix 0.38.34", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] @@ -1646,10 +1539,10 @@ dependencies = [ [[package]] name = "pool_sv2" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", - "async-recursion 1.1.1", + "async-recursion 1.1.0", "binary_sv2", "buffer_sv2", "codec_sv2", @@ -1662,6 +1555,7 @@ dependencies = [ "noise_sv2", "rand", "roles_logic_sv2", + "secp256k1 0.28.2", "serde", "stratum-common", "tokio", @@ -1688,9 +1582,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1703,9 +1597,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1742,11 +1636,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags 2.5.0", + "bitflags 1.3.2", ] [[package]] @@ -1780,7 +1674,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "roles_logic_sv2" -version = "1.1.0" +version = "1.0.0" dependencies = [ "binary_sv2", "chacha20poly1305", @@ -1812,9 +1706,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" @@ -1832,9 +1726,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ "bitflags 2.5.0", "errno", @@ -1845,9 +1739,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scopeguard" @@ -1896,29 +1790,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.200" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -1968,9 +1862,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -2008,9 +1902,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2021,15 +1915,8 @@ name = "stratum-common" version = "1.0.0" dependencies = [ "bitcoin", - "secp256k1 0.28.2", ] -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "subtle" version = "2.5.0" @@ -2079,9 +1966,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -2129,7 +2016,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -2142,20 +2029,21 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", + "tracing", ] [[package]] @@ -2215,7 +2103,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", ] [[package]] @@ -2255,7 +2143,7 @@ dependencies = [ [[package]] name = "translator_sv2" -version = "0.1.1" +version = "0.1.0" dependencies = [ "async-channel 1.9.0", "async-compat", @@ -2312,12 +2200,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "valuable" version = "0.1.0" @@ -2326,9 +2208,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "74797339c3b98616c009c7c3eb53a0ce41e85c8ec66bd3db96ed132d20cfdee8" [[package]] name = "version_check" @@ -2378,7 +2260,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -2412,7 +2294,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2451,11 +2333,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "windows-sys 0.52.0", + "winapi", ] [[package]] @@ -2479,7 +2361,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.4", ] [[package]] @@ -2499,18 +2381,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -2521,9 +2402,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -2533,9 +2414,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -2545,15 +2426,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -2563,9 +2438,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -2575,9 +2450,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -2587,9 +2462,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -2599,9 +2474,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "zeroize" diff --git a/roles/jd-client/Cargo.toml b/roles/jd-client/Cargo.toml index 4c79016d06..f7ccc5f779 100644 --- a/roles/jd-client/Cargo.toml +++ b/roles/jd-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jd_client" -version = "0.1.1" +version = "0.1.0" edition = "2021" description = "TODO" license = "MIT OR Apache-2.0" @@ -17,8 +17,8 @@ async-recursion = "0.3.2" binary_sv2 = { version = "^1.0.0", path = "../../protocols/v2/binary-sv2/binary-sv2" } buffer_sv2 = { version = "^1.0.0", path = "../../utils/buffer" } codec_sv2 = { version = "^1.0.1", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2", "with_buffer_pool"] } -framing_sv2 = { version = "^1.1.0", path = "../../protocols/v2/framing-sv2" } -network_helpers_sv2 = { version = "2.0.0", path = "../roles-utils/network-helpers", features=["with_tokio", "with_buffer_pool"] } +framing_sv2 = { version = "^1.0.0", path = "../../protocols/v2/framing-sv2" } +network_helpers_sv2 = { version = "1.0.0", path = "../roles-utils/network-helpers", features=["with_tokio", "with_buffer_pool"] } roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] } futures = "0.3.25" diff --git a/roles/jd-client/README.md b/roles/jd-client/README.md index 18ab95197f..efc5d8d2a1 100644 --- a/roles/jd-client/README.md +++ b/roles/jd-client/README.md @@ -1,34 +1,38 @@ # JD Client - +The JD Client is a Sv2 proxy that support one extended channel upstream and one extended channel +dowstream, and do job declaration. On start it will: * connect to the jd-server * connect to the template-provider -The JD Client receives custom block templates from a Template Provider and declares use of the template with the pool using the Job Declaration Protocol. Further distributes the jobs to Mining Proxy (or Proxies) using the Job Distribution Protocol. ``` +* listen for and `OpenExtendedChannel` from downstream * transparently relay the `OpenExtendedChannel` to upstream +After the setup phase it will start to negotiate jobs with upstream and send the negotiated job +downstream, so that everything that is dowstream do not need to know that job is negotiated. ## Setup - ### Configuration File +The `proxy-config-example.toml` is a configuration example. The configuration file contains the following information: -1. The downstream socket information, which includes the listening IP address (`downstream_address`) and port (`downstream_port`). -2. The maximum and minimum SRI versions (`max_supported_version` and `min_supported_version`) with size as (`min_extranonce2_size`) -3. The authentication keys for the downstream connection (`authority_public_key`, `authority_secret_key`) -4. A `retry` parameter which tells JDC the number of times to reinitialize itself after a failure. -6. The Template Provider address (`tp_address`). -7. Optionally, you may want to verify that your TP connection is authentic. You may get `tp_authority_public_key` from the logs of your TP, for example: - +1. The Upstream connection information which includes the SV2 Pool authority public key + (`upstream_authority_pubkey`) and the SV2 Pool connection address (`upstream_address`) and port + (`upstream_port`). +2. The maximum and minimum SV2 versions (`max_supported_version` and `min_supported_version`) +3. The Job Declarator information which includes the Pool JD connection address (`jd_address`) and the Template Provider connection address to which to connect (`tp_address`). +4. Optionally, you may want to verify that your TP connection is authentic. You may get `tp_authority_public_key` from the logs of your TP, for example: +``` # 2024-02-13T14:59:24Z Template Provider authority key: EguTM8URcZDQVeEBsM4B5vg9weqEUnufA8pm85fG4bZd +``` ### Run - -Run the Job Declarator Client (JDC): -There are two files when you cd into roles/jd-client/config-examples/ - -1. `jdc-config-hosted-example.toml` connects to the community-hosted roles. -2. `jdc-config-local-example.toml` connects to self-hosted Job Declarator Client (JDC) and Translator Proxy - -``` bash -cd roles/jd-client/config-examples/ -cargo run -- -c jdc-config-hosted-example.toml -``` +1. Copy the `jdc-config-example.toml` into `conf/` directory. +2. Edit it with custom desired configuration and rename it `jdc-config.toml` +3. Point the SV1 Downstream Mining Device(s) to the Translator Proxy IP address and port. +4. Run the Translator Proxy: + + ``` + cd roles/translator + ``` + ``` + cargo run -p translator_sv2 -- -c conf/jdc-config.toml + ``` diff --git a/roles/jd-client/src/args.rs b/roles/jd-client/src/args.rs index 7802351c31..65328de58a 100644 --- a/roles/jd-client/src/args.rs +++ b/roles/jd-client/src/args.rs @@ -44,16 +44,7 @@ impl Args { Some(ArgsResult::None) } }, - ArgsState::ExpectPath => { - let path = PathBuf::from(item.clone()); - if !path.exists() { - return Some(ArgsResult::Help(format!( - "Error: File '{}' does not exist!", - path.display() - ))); - } - Some(ArgsResult::Config(path)) - } + ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))), ArgsState::Done => None, } }) diff --git a/roles/jd-client/src/lib/downstream.rs b/roles/jd-client/src/lib/downstream.rs index ddc6e5bd0f..fdac57a12c 100644 --- a/roles/jd-client/src/lib/downstream.rs +++ b/roles/jd-client/src/lib/downstream.rs @@ -289,14 +289,8 @@ impl DownstreamMiningNode { // pool's job_id. The below return as soon as we have a pairable job id for the // template_id associated with this share. let last_template_id = self_mutex.safe_lock(|s| s.last_template_id).unwrap(); - let job_id_future = - UpstreamMiningNode::get_job_id(&upstream_mutex, last_template_id); - let job_id = match timeout(Duration::from_secs(10), job_id_future).await { - Ok(job_id) => job_id, - Err(_) => { - return; - } - }; + let job_id = + UpstreamMiningNode::get_job_id(&upstream_mutex, last_template_id).await; share.job_id = job_id; debug!( "Sending valid block solution upstream, with job_id {}", @@ -649,11 +643,7 @@ impl ParseDownstreamCommonMessages use network_helpers_sv2::noise_connection_tokio::Connection; use std::net::SocketAddr; -use tokio::{ - net::TcpListener, - task::AbortHandle, - time::{timeout, Duration}, -}; +use tokio::{net::TcpListener, task::AbortHandle}; /// Strat listen for downstream mining node. Return as soon as one downstream connect. #[allow(clippy::too_many_arguments)] diff --git a/roles/jd-client/src/lib/job_declarator/message_handler.rs b/roles/jd-client/src/lib/job_declarator/message_handler.rs index 7516f24f94..c05393c64f 100644 --- a/roles/jd-client/src/lib/job_declarator/message_handler.rs +++ b/roles/jd-client/src/lib/job_declarator/message_handler.rs @@ -54,9 +54,7 @@ impl ParseServerJobDeclarationMessages for JobDeclarator { message: ProvideMissingTransactions, ) -> Result { let tx_list = self - .last_declare_mining_jobs_sent - .get(&message.request_id) - .unwrap() + .last_declare_mining_job_sent .clone() .unwrap() .tx_list diff --git a/roles/jd-client/src/lib/job_declarator/mod.rs b/roles/jd-client/src/lib/job_declarator/mod.rs index abaf852ca2..c03959b75f 100644 --- a/roles/jd-client/src/lib/job_declarator/mod.rs +++ b/roles/jd-client/src/lib/job_declarator/mod.rs @@ -55,9 +55,8 @@ pub struct JobDeclarator { req_ids: Id, min_extranonce_size: u16, // (Sent DeclareMiningJob, is future, template id, merkle path) - last_declare_mining_jobs_sent: HashMap>, + last_declare_mining_job_sent: Option, last_set_new_prev_hash: Option>, - set_new_prev_hash_counter: u8, #[allow(clippy::type_complexity)] future_jobs: HashMap< u64, @@ -115,14 +114,13 @@ impl JobDeclarator { allocated_tokens: vec![], req_ids: Id::new(), min_extranonce_size, - last_declare_mining_jobs_sent: HashMap::with_capacity(10), + last_declare_mining_job_sent: None, last_set_new_prev_hash: None, future_jobs: HashMap::with_hasher(BuildNoHashHasher::default()), up, task_collector, coinbase_tx_prefix: vec![].try_into().unwrap(), coinbase_tx_suffix: vec![].try_into().unwrap(), - set_new_prev_hash_counter: 0, })); Self::allocate_tokens(&self_, 2).await; @@ -130,35 +128,20 @@ impl JobDeclarator { Ok(self_) } - fn get_last_declare_job_sent(self_mutex: &Arc>, request_id: u32) -> LastDeclareJob { + fn get_last_declare_job_sent(self_mutex: &Arc>) -> LastDeclareJob { self_mutex .safe_lock(|s| { - s.last_declare_mining_jobs_sent - .get(&request_id) - .expect("LastDeclareJob not found") + s.last_declare_mining_job_sent .clone() .expect("unreachable code") }) .unwrap() } - fn update_last_declare_job_sent( - self_mutex: &Arc>, - request_id: u32, - j: LastDeclareJob, - ) { + fn update_last_declare_job_sent(self_mutex: &Arc>, j: LastDeclareJob) { self_mutex - .safe_lock(|s| { - //check hashmap size in order to not let it grow indefinetely - if s.last_declare_mining_jobs_sent.len() < 10 { - s.last_declare_mining_jobs_sent.insert(request_id, Some(j)); - } else if let Some(min_key) = s.last_declare_mining_jobs_sent.keys().min().cloned() - { - s.last_declare_mining_jobs_sent.remove(&min_key); - s.last_declare_mining_jobs_sent.insert(request_id, Some(j)); - } - }) - .unwrap(); + .safe_lock(|s| s.last_declare_mining_job_sent = Some(j)) + .unwrap() } #[async_recursion] @@ -262,7 +245,7 @@ impl JobDeclarator { coinbase_pool_output, tx_list: tx_list_.clone(), }; - Self::update_last_declare_job_sent(self_mutex, id, last_declare); + Self::update_last_declare_job_sent(self_mutex, last_declare); let frame: StdFrame = PoolMessages::JobDeclaration(JobDeclaration::DeclareMiningJob(declare_job)) .try_into() @@ -289,8 +272,7 @@ impl JobDeclarator { match next_message_to_send { Ok(SendTo::None(Some(JobDeclaration::DeclareMiningJobSuccess(m)))) => { let new_token = m.new_mining_job_token; - let last_declare = - Self::get_last_declare_job_sent(&self_mutex, m.request_id); + let last_declare = Self::get_last_declare_job_sent(&self_mutex); let mut last_declare_mining_job_sent = last_declare.declare_job; let is_future = last_declare.template.future_template; let id = last_declare.template.template_id; @@ -373,35 +355,21 @@ impl JobDeclarator { ) { tokio::task::spawn(async move { let id = set_new_prev_hash.template_id; - let _ = self_mutex.safe_lock(|s| { - s.last_set_new_prev_hash = Some(set_new_prev_hash.clone()); - s.set_new_prev_hash_counter += 1; - }); let (job, up, merkle_path, template, mut pool_outs) = loop { - match self_mutex + if let Some(future_job_tuple) = self_mutex .safe_lock(|s| { - if s.set_new_prev_hash_counter > 1 - && s.last_set_new_prev_hash != Some(set_new_prev_hash.clone()) - //it means that a new prev_hash is arrived while the previous hasn't exited the loop yet - { - s.set_new_prev_hash_counter -= 1; - Some(None) - } else { - s.future_jobs.remove(&id).map( - |(job, merkle_path, template, pool_outs)| { - s.future_jobs = - HashMap::with_hasher(BuildNoHashHasher::default()); - s.set_new_prev_hash_counter -= 1; - Some((job, s.up.clone(), merkle_path, template, pool_outs)) - }, - ) + s.last_set_new_prev_hash = Some(set_new_prev_hash.clone()); + match s.future_jobs.remove(&id) { + Some((job, merkle_path, template, pool_outs)) => { + s.future_jobs = HashMap::with_hasher(BuildNoHashHasher::default()); + Some((job, s.up.clone(), merkle_path, template, pool_outs)) + } + None => None, } }) .unwrap() { - Some(Some(future_job_tuple)) => break future_job_tuple, - Some(None) => return, - None => {} + break future_job_tuple; }; tokio::task::yield_now().await; }; diff --git a/roles/jd-server/Cargo.toml b/roles/jd-server/Cargo.toml index 6f55ece068..b89c07023c 100644 --- a/roles/jd-server/Cargo.toml +++ b/roles/jd-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jd_server" -version = "0.1.1" +version = "0.1.0" edition = "2018" license = "MIT OR Apache-2.0" repository = "https://github.com/stratum-mining/stratum" @@ -16,7 +16,7 @@ binary_sv2 = { version = "^1.0.0", path = "../../protocols/v2/binary-sv2/binary- buffer_sv2 = { version = "^1.0.0", path = "../../utils/buffer" } codec_sv2 = { version = "^1.0.1", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2"] } const_sv2 = { version = "^1.0.0", path = "../../protocols/v2/const-sv2" } -network_helpers_sv2 = { version = "2.0.0", path = "../roles-utils/network-helpers", features = ["with_tokio"] } +network_helpers_sv2 = { version = "1.0.0", path = "../roles-utils/network-helpers", features = ["with_tokio"] } noise_sv2 = { version = "1.1.0", path = "../../protocols/v2/noise-sv2" } rand = "0.8.4" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } @@ -30,5 +30,6 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc","r serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } hashbrown = { version = "0.11", default-features = false, features = ["ahash", "serde"] } key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } +secp256k1 = { version = "0.28.2", default-features = false, features =["alloc","rand","rand-std"] } rpc_sv2 = { version = "1.0.0", path = "../roles-utils/rpc" } hex = "0.4.3" diff --git a/roles/jd-server/src/lib/job_declarator/message_handler.rs b/roles/jd-server/src/lib/job_declarator/message_handler.rs index 96887bdd0e..58a40fcba0 100644 --- a/roles/jd-server/src/lib/job_declarator/message_handler.rs +++ b/roles/jd-server/src/lib/job_declarator/message_handler.rs @@ -154,63 +154,46 @@ impl ParseClientJobDeclarationMessages for JobDeclaratorDownstream { &mut self, message: ProvideMissingTransactionsSuccess, ) -> Result { - let (declared_mining_job, ref mut transactions_with_state, missing_indexes) = - &mut self.declared_mining_job; + let (_, ref mut transactions_with_state, missing_indexes) = &mut self.declared_mining_job; let mut unknown_transactions: Vec = vec![]; - match declared_mining_job { - Some(declared_job) => { - let id = declared_job.request_id; - // check request_id in order to ignore old ProvideMissingTransactionsSuccess (see issue #860) - if id == message.request_id { - for (i, tx) in message.transaction_list.inner_as_ref().iter().enumerate() { - let mut cursor = Cursor::new(tx); - let transaction = - Transaction::consensus_decode_from_finite_reader(&mut cursor) - .map_err(|e| Error::TxDecodingError(e.to_string()))?; - Vec::push(&mut unknown_transactions, transaction.clone()); - let index = - *missing_indexes - .get(i) - .ok_or(Error::LogicErrorMessage(Box::new( - AllMessages::JobDeclaration( - JobDeclaration::ProvideMissingTransactionsSuccess( - message.clone().into_static(), - ), - ), - )))? as usize; - // insert the missing transactions in the mempool - transactions_with_state[index] = - TransactionState::PresentInMempool(transaction.txid()); - } - self.add_txs_to_mempool - .add_txs_to_mempool_inner - .unknown_transactions - .append(&mut unknown_transactions); - // if there still a missing transaction return an error - for tx_with_state in transactions_with_state { - match tx_with_state { - TransactionState::PresentInMempool(_) => continue, - TransactionState::Missing => return Err(Error::JDSMissingTransactions), - } - } - // TODO check it - let tx_hash_list_hash = self.tx_hash_list_hash.clone().unwrap().into_static(); - let message_success = DeclareMiningJobSuccess { - request_id: message.request_id, - new_mining_job_token: signed_token( - tx_hash_list_hash, - &self.public_key.clone(), - &self.private_key.clone(), - ), - }; - let message_enum_success = - JobDeclaration::DeclareMiningJobSuccess(message_success); - return Ok(SendTo::Respond(message_enum_success)); - } + for (i, tx) in message.transaction_list.inner_as_ref().iter().enumerate() { + let mut cursor = Cursor::new(tx); + let transaction = Transaction::consensus_decode_from_finite_reader(&mut cursor) + .map_err(|e| Error::TxDecodingError(e.to_string()))?; + Vec::push(&mut unknown_transactions, transaction.clone()); + let index = *missing_indexes + .get(i) + .ok_or(Error::LogicErrorMessage(Box::new( + AllMessages::JobDeclaration(JobDeclaration::ProvideMissingTransactionsSuccess( + message.clone().into_static(), + )), + )))? as usize; + // insert the missing transactions in the mempool + transactions_with_state[index] = TransactionState::PresentInMempool(transaction.txid()); + } + self.add_txs_to_mempool + .add_txs_to_mempool_inner + .unknown_transactions + .append(&mut unknown_transactions); + // if there still a missing transaction return an error + for tx_with_state in transactions_with_state { + match tx_with_state { + TransactionState::PresentInMempool(_) => continue, + TransactionState::Missing => return Err(Error::JDSMissingTransactions), } - None => return Err(Error::NoValidJob), } - Ok(SendTo::None(None)) + // TODO check it + let tx_hash_list_hash = self.tx_hash_list_hash.clone().unwrap().into_static(); + let message_success = DeclareMiningJobSuccess { + request_id: message.request_id, + new_mining_job_token: signed_token( + tx_hash_list_hash, + &self.public_key.clone(), + &self.private_key.clone(), + ), + }; + let message_enum_success = JobDeclaration::DeclareMiningJobSuccess(message_success); + Ok(SendTo::Respond(message_enum_success)) } fn handle_submit_solution(&mut self, message: SubmitSolutionJd<'_>) -> Result { diff --git a/roles/jd-server/src/lib/job_declarator/mod.rs b/roles/jd-server/src/lib/job_declarator/mod.rs index 56d56223cc..3a3405cd75 100644 --- a/roles/jd-server/src/lib/job_declarator/mod.rs +++ b/roles/jd-server/src/lib/job_declarator/mod.rs @@ -4,7 +4,7 @@ use async_channel::{Receiver, Sender}; use binary_sv2::{B0255, U256}; use codec_sv2::{Frame, HandshakeRole, Responder}; use error_handling::handle_result; -use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey, SignatureService}; +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; use network_helpers_sv2::noise_connection_tokio::Connection; use nohash_hasher::BuildNoHashHasher; use roles_logic_sv2::{ @@ -14,6 +14,7 @@ use roles_logic_sv2::{ parsers::{JobDeclaration, PoolMessages as JdsMessages}, utils::{Id, Mutex}, }; +use secp256k1::{Keypair, Message as SecpMessage, Secp256k1}; use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::{net::TcpListener, time::Duration}; use tracing::{debug, error, info}; @@ -394,9 +395,15 @@ pub fn signed_token( _pub_key: &Secp256k1PublicKey, prv_key: &Secp256k1SecretKey, ) -> B0255<'static> { - let secp = SignatureService::default(); + let secp = Secp256k1::signing_only(); - let signature = secp.sign(tx_hash_list_hash.to_vec(), prv_key.0); + // Create the SecretKey and PublicKey instances + let secret_key = prv_key.0; + let kp = Keypair::from_secret_key(&secp, &secret_key); + + let message: Vec = tx_hash_list_hash.to_vec(); + + let signature = secp.sign_schnorr(&SecpMessage::from_digest_slice(&message).unwrap(), &kp); // Sign message signature.as_ref().to_vec().try_into().unwrap() diff --git a/roles/jd-server/src/lib/mempool/error.rs b/roles/jd-server/src/lib/mempool/error.rs index f2ce316e84..e554a0b14d 100644 --- a/roles/jd-server/src/lib/mempool/error.rs +++ b/roles/jd-server/src/lib/mempool/error.rs @@ -1,5 +1,5 @@ use rpc_sv2::mini_rpc_client::RpcError; -use std::{convert::From, sync::PoisonError}; +use tokio::task::JoinError; use tracing::{error, warn}; #[derive(Debug)] @@ -8,18 +8,7 @@ pub enum JdsMempoolError { NoClient, Rpc(RpcError), PoisonLock(String), -} - -impl From for JdsMempoolError { - fn from(value: RpcError) -> Self { - JdsMempoolError::Rpc(value) - } -} - -impl From> for JdsMempoolError { - fn from(value: PoisonError) -> Self { - JdsMempoolError::PoisonLock(value.to_string()) - } + TokioJoin(JoinError), } pub fn handle_error(err: &JdsMempoolError) { @@ -40,5 +29,9 @@ pub fn handle_error(err: &JdsMempoolError) { error!("{:?}", err); error!("Poison lock error)"); } + JdsMempoolError::TokioJoin(_) => { + error!("{:?}", err); + error!("Poison lock error)"); + } } } diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index a9aa8ecc93..f2b97fe4e2 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -5,7 +5,7 @@ use async_channel::Receiver; use bitcoin::blockdata::transaction::Transaction; use hashbrown::HashMap; use roles_logic_sv2::utils::Mutex; -use rpc_sv2::{mini_rpc_client, mini_rpc_client::RpcError}; +use rpc_sv2::mini_rpc_client; use std::{convert::TryInto, str::FromStr, sync::Arc}; use stratum_common::{bitcoin, bitcoin::hash_types::Txid}; @@ -69,7 +69,8 @@ impl JDsMempool { let txids = add_txs_to_mempool_inner.known_transactions; let transactions = add_txs_to_mempool_inner.unknown_transactions; let client = self_ - .safe_lock(|a| a.get_client())? + .safe_lock(|a| a.get_client()) + .map_err(|e| JdsMempoolError::PoisonLock(e.to_string()))? .ok_or(JdsMempoolError::NoClient)?; // fill in the mempool the transactions id in the mempool with the full transactions // retrieved from the jd client @@ -96,37 +97,53 @@ impl JDsMempool { pub async fn update_mempool(self_: Arc>) -> Result<(), JdsMempoolError> { let mut mempool_ordered: HashMap> = HashMap::new(); - let client = self_ - .safe_lock(|x| x.get_client())? + .safe_lock(|x| x.get_client()) + .map_err(|e| JdsMempoolError::PoisonLock(e.to_string()))? .ok_or(JdsMempoolError::NoClient)?; - - let mempool: Vec = client.get_raw_mempool().await?; - for id in &mempool { - let key_id = Txid::from_str(id) - .map_err(|err| JdsMempoolError::Rpc(RpcError::Deserialization(err.to_string())))?; - - let tx = self_.safe_lock(|x| match x.mempool.get(&key_id) { - Some(entry) => entry.clone(), - None => None, - })?; - - mempool_ordered.insert(key_id, tx); - } - - if mempool_ordered.is_empty() { - Err(JdsMempoolError::EmptyMempool) - } else { - let _ = self_.safe_lock(|x| x.mempool = mempool_ordered); - Ok(()) + let new_mempool: Result>, JdsMempoolError> = { + let self_ = self_.clone(); + tokio::task::spawn(async move { + let mempool: Vec = client + .get_raw_mempool() + .await + .map_err(JdsMempoolError::Rpc)?; + for id in &mempool { + let key_id = Txid::from_str(id).unwrap(); + let tx = self_.safe_lock(|x| match x.mempool.get(&key_id) { + Some(entry) => entry.clone(), + None => None, + }); + let id = Txid::from_str(id).unwrap(); + mempool_ordered.insert(id, tx.unwrap()); + } + if mempool_ordered.is_empty() { + Err(JdsMempoolError::EmptyMempool) + } else { + Ok(mempool_ordered) + } + }) + .await + .map_err(JdsMempoolError::TokioJoin)? + }; + match new_mempool { + Ok(new_mempool_) => { + let _ = self_.safe_lock(|x| { + x.mempool = new_mempool_; + }); + Ok(()) + } + Err(a) => Err(a), } } pub async fn on_submit(self_: Arc>) -> Result<(), JdsMempoolError> { - let new_block_receiver: Receiver = - self_.safe_lock(|x| x.new_block_receiver.clone())?; + let new_block_receiver: Receiver = self_ + .safe_lock(|x| x.new_block_receiver.clone()) + .map_err(|e| JdsMempoolError::PoisonLock(e.to_string()))?; let client = self_ - .safe_lock(|x| x.get_client())? + .safe_lock(|x| x.get_client()) + .map_err(|e| JdsMempoolError::PoisonLock(e.to_string()))? .ok_or(JdsMempoolError::NoClient)?; while let Ok(block_hex) = new_block_receiver.recv().await { diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 9d56b491f7..3391a93be8 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -146,6 +146,10 @@ async fn main() { mempool::error::handle_error(&err); handle_result!(sender_update_mempool, Err(err)); } + JdsMempoolError::TokioJoin(_) => { + mempool::error::handle_error(&err); + handle_result!(sender_update_mempool, Err(err)); + } JdsMempoolError::PoisonLock(_) => { mempool::error::handle_error(&err); handle_result!(sender_update_mempool, Err(err)); diff --git a/roles/mining-proxy/Cargo.toml b/roles/mining-proxy/Cargo.toml index 951645fde3..6e77ccc7e6 100644 --- a/roles/mining-proxy/Cargo.toml +++ b/roles/mining-proxy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mining_proxy_sv2" -version = "0.1.1" +version = "0.1.0" authors = ["user"] edition = "2018" description = "SV2 mining proxy role" @@ -20,7 +20,7 @@ buffer_sv2 = { version = "^1.0.0", path = "../../utils/buffer" } codec_sv2 = { version = "^1.0.1", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2", "with_buffer_pool"] } const_sv2 = { version = "^1.0.0", path = "../../protocols/v2/const-sv2" } futures = "0.3.19" -network_helpers_sv2 = {version = "2.0.0", path = "../roles-utils/network-helpers", features = ["with_tokio","with_buffer_pool"] } +network_helpers_sv2 = {version = "1.0.0", path = "../roles-utils/network-helpers", features = ["with_tokio","with_buffer_pool"] } once_cell = "1.12.0" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } diff --git a/roles/mining-proxy/config-examples/proxy-config-example.toml b/roles/mining-proxy/config-examples/proxy-config-example.toml index 6766f82d6c..35d3917dde 100644 --- a/roles/mining-proxy/config-examples/proxy-config-example.toml +++ b/roles/mining-proxy/config-examples/proxy-config-example.toml @@ -6,6 +6,7 @@ listen_mining_port = 34255 max_supported_version = 2 min_supported_version = 2 downstream_share_per_minute = 1 +coinbase_reward_sat = 5_000_000_000 # This value is used by the proxy to communicate to the pool the expected hash rate when we open an # extended channel, based on it the pool will set a target for the channel expected_total_downstream_hr = 10_000 diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml index 3b62c74e1e..a1da3a21f9 100644 --- a/roles/pool/Cargo.toml +++ b/roles/pool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pool_sv2" -version = "0.1.1" +version = "0.1.0" edition = "2018" description = "SV2 pool role" license = "MIT OR Apache-2.0" @@ -17,7 +17,7 @@ binary_sv2 = { version = "^1.0.0", path = "../../protocols/v2/binary-sv2/binary- buffer_sv2 = { version = "^1.0.0", path = "../../utils/buffer" } codec_sv2 = { version = "^1.0.1", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2"] } const_sv2 = { version = "^1.0.0", path = "../../protocols/v2/const-sv2" } -network_helpers_sv2 = { version = "2.0.0", path = "../roles-utils/network-helpers", features =["with_tokio","with_buffer_pool"] } +network_helpers_sv2 = { version = "1.0.0", path = "../roles-utils/network-helpers", features =["with_tokio","with_buffer_pool"] } noise_sv2 = { version = "1.1.0", path = "../../protocols/v2/noise-sv2" } rand = "0.8.4" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } @@ -30,6 +30,7 @@ async-recursion = "1.0.0" error_handling = { version = "1.0.0", path = "../../utils/error-handling" } nohash-hasher = "0.2.0" key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } +secp256k1 = { version = "0.28.2", default-features = false, features =["alloc","rand","rand-std"] } [dev-dependencies] hex = "0.4.3" diff --git a/roles/pool/README.md b/roles/pool/README.md index 1e608b80d4..5d7bd5b507 100644 --- a/roles/pool/README.md +++ b/roles/pool/README.md @@ -1,6 +1,4 @@ - # SRI Pool - SRI Pool is designed to communicate with Downstream role (most typically a Translator Proxy or a Mining Proxy) running SV2 protocol to exploit features introduced by its sub-protocols. The most typical high level configuration is: @@ -20,35 +18,47 @@ The most typical high level configuration is: ``` ## Setup - ### Configuration File - -`pool-config-hosted-tp-example.toml` and `pool-config-local-tp-example.toml` are examples of configuration files. +The `pool-config-example.toml` is a configuration example which can be copy/paste into `/conf` directory by the party that is running the SV2 Pool (most +typically the pool service provider) to address the most preferred customization. The configuration file contains the following information: -1. The SRI Pool information which includes the SRI Pool authority public key - (`authority_public_key`), the SRI Pool authority secret key (`authority_secret_key`). -2. The address which it will use to listen to new connection from downstream roles (`listen_address`) -3. The list of uncompressed pubkeys for coinbase payout (`coinbase_outputs`) -4. A string that serves as signature on the coinbase tx (`pool_signature`). -5. The Template Provider address (`tp_address`). -6. Optionally, you may want to verify that your TP connection is authentic. You may get `tp_authority_public_key` from the logs of your TP, for example: - +1. The SRI Pool information which includes the SRI Pool authority public key + (`authority_pubkey`), the SRI Pool authority secret key (`authority_secret_key`), along with its certificate validity (`cert_validity_sec`). In addition to this, it contains the address which it will use to listen to new connection from downstream roles (`listen_address`) and the list of uncompressed pubkeys for coinbase payout (`coinbase_outputs`). +2. The SRI Pool Job Negatiator information which includes the Template Provider address (`tp_address`) and the address it uses to listen new request from the downstream JDs (`jd_address`). +3. Optionally, you may want to verify that your TP connection is authentic. You may get `tp_authority_public_key` from the logs of your TP, for example: ``` # 2024-02-13T14:59:24Z Template Provider authority key: EguTM8URcZDQVeEBsM4B5vg9weqEUnufA8pm85fG4bZd ``` ### Run - -There are two files found in `roles/pool/config-examples` - -1. `pool-config-hosted-tp-example.toml` runs on our community hosted server. -2. `pool-config-example-tp-example.toml` runs with your local config. - -Run the Pool: - -```bash -cd roles/pool/config-examples -cargo run -- -c pool-config-hosted-tp-example.toml -``` +1. Copy the `pool-config-example.toml` into `conf/` directory. +2. Edit it with custom desired configuration and rename it `pool-config.toml` + > **Warning**
+ > If you want to mine spendable bitcoin on regtest, you can do it with bitcoin-cli: + > 1. Get a legacy Bitcoin address: + > ``` + > bitcoin-cli -regtest -rpcwallet="" getnewaddress "test" "legacy" + > ``` + > 2. Retrieve its corresponding public key: + > ``` + > bitcoin-cli -regtest getaddressinfo + > ``` + > 3. Copy the pubkey showed in the output + > 4. Paste it in the `coinbase_outputs` of `pool-config.toml`, after deleting the one which is already present + > 5. Mine a block + > 6. Generate 100 blocks + > ``` + > bitcoin-cli -regtest generatetoaddress 100 bcrt1qc5xss0cma0zldxfzzdpjxsayut7yy86e2lr6km + > ``` + > Now the mined bitcoin are spendable! + +3. Run the Pool: + + ``` + cd roles/v2/pool + ``` + ``` + cargo run -p pool_sv2 -- -c conf/pool-config.toml + ``` \ No newline at end of file diff --git a/roles/pool/config-examples/pool-config-local-tp-example.toml b/roles/pool/config-examples/pool-config-local-tp-example.toml index edc69b3c18..016c372f59 100644 --- a/roles/pool/config-examples/pool-config-local-tp-example.toml +++ b/roles/pool/config-examples/pool-config-local-tp-example.toml @@ -1,6 +1,7 @@ # SRI Pool config authority_public_key = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72" authority_secret_key = "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n" +#authority_secret_key = "7qbpUjScc865jyX2kiB4NVJANoC7GA7TAJupdzXWkc62" cert_validity_sec = 3600 test_only_listen_adress_plain = "0.0.0.0:34250" listen_address = "0.0.0.0:34254" diff --git a/roles/pool/src/lib/mining_pool/mod.rs b/roles/pool/src/lib/mining_pool/mod.rs index e189c5406a..6f2bec3071 100644 --- a/roles/pool/src/lib/mining_pool/mod.rs +++ b/roles/pool/src/lib/mining_pool/mod.rs @@ -6,7 +6,7 @@ use async_channel::{Receiver, Sender}; use binary_sv2::U256; use codec_sv2::{Frame, HandshakeRole, Responder, StandardEitherFrame, StandardSv2Frame}; use error_handling::handle_result; -use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey, SignatureService}; +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; use network_helpers_sv2::noise_connection_tokio::Connection; use nohash_hasher::BuildNoHashHasher; use roles_logic_sv2::{ @@ -28,10 +28,7 @@ use std::{ net::SocketAddr, sync::Arc, }; -use stratum_common::{ - bitcoin::{Script, TxOut}, - secp256k1, -}; +use stratum_common::bitcoin::{Script, TxOut}; use tokio::{net::TcpListener, task}; use tracing::{debug, error, info, warn}; @@ -286,11 +283,18 @@ pub fn verify_token( signature: secp256k1::schnorr::Signature, pub_key: key_utils::Secp256k1PublicKey, ) -> Result<(), secp256k1::Error> { - let message: Vec = tx_hash_list_hash.to_vec(); + let secp = secp256k1::Secp256k1::verification_only(); + // Create PublicKey instance + let x_only_public_key = pub_key.0; - let secp = SignatureService::default(); + let message: Vec = tx_hash_list_hash.to_vec(); - let is_verified = secp.verify(tx_hash_list_hash.to_vec(), signature, pub_key.0); + // Verify signature + let is_verified = secp.verify_schnorr( + &signature, + &secp256k1::Message::from_digest_slice(&message)?, + &x_only_public_key, + ); // debug debug!("Message: {}", std::str::from_utf8(&message).unwrap()); diff --git a/roles/roles-utils/network-helpers/Cargo.toml b/roles/roles-utils/network-helpers/Cargo.toml index e2c69806a3..31de7a5840 100644 --- a/roles/roles-utils/network-helpers/Cargo.toml +++ b/roles/roles-utils/network-helpers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "network_helpers_sv2" -version = "2.0.0" +version = "1.0.1" authors = ["fi3 "] edition = "2018" description = "Networking utils for SV2 roles" diff --git a/roles/roles-utils/network-helpers/src/lib.rs b/roles/roles-utils/network-helpers/src/lib.rs index 3555c2056d..2879e3ad64 100644 --- a/roles/roles-utils/network-helpers/src/lib.rs +++ b/roles/roles-utils/network-helpers/src/lib.rs @@ -30,8 +30,6 @@ pub enum Error { CodecError(CodecError), RecvError, SendError, - // This means that a socket that was supposed to be opened have been closed, likley by the peer - SocketClosed, } impl From for Error { diff --git a/roles/roles-utils/network-helpers/src/noise_connection_async_std.rs b/roles/roles-utils/network-helpers/src/noise_connection_async_std.rs index ae40529037..0bfad7e9d7 100644 --- a/roles/roles-utils/network-helpers/src/noise_connection_async_std.rs +++ b/roles/roles-utils/network-helpers/src/noise_connection_async_std.rs @@ -47,7 +47,7 @@ impl Connection { ), Error, > { - let address = stream.peer_addr().map_err(|_| Error::SocketClosed)?; + let address = stream.peer_addr().unwrap(); let (mut reader, writer) = (stream.clone(), stream.clone()); let (sender_incoming, receiver_incoming): ( diff --git a/roles/roles-utils/network-helpers/src/noise_connection_tokio.rs b/roles/roles-utils/network-helpers/src/noise_connection_tokio.rs index 2e2996365f..06a4961be1 100644 --- a/roles/roles-utils/network-helpers/src/noise_connection_tokio.rs +++ b/roles/roles-utils/network-helpers/src/noise_connection_tokio.rs @@ -48,7 +48,7 @@ impl Connection { ), Error, > { - let address = stream.peer_addr().map_err(|_| Error::SocketClosed)?; + let address = stream.peer_addr().unwrap(); let (mut reader, mut writer) = stream.into_split(); diff --git a/roles/test-utils/mining-device/Cargo.toml b/roles/test-utils/mining-device/Cargo.toml index 4ce6c5037a..f308cb1468 100644 --- a/roles/test-utils/mining-device/Cargo.toml +++ b/roles/test-utils/mining-device/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mining-device" -version = "0.1.1" +version = "0.1.0" edition = "2018" publish = false @@ -14,13 +14,8 @@ const_sv2 = { version = "1.0.0", path = "../../../protocols/v2/const-sv2" } async-channel = "1.5.1" async-std={version = "1.8.0", features = ["attributes"]} binary_sv2 = { version = "1.0.0", path = "../../../protocols/v2/binary-sv2/binary-sv2" } -network_helpers_sv2 = { version = "2.0.0", path = "../../roles-utils/network-helpers", features=["async_std"] } +network_helpers_sv2 = { version = "1.0.0", path = "../../roles-utils/network-helpers", features=["async_std"] } buffer_sv2 = { version = "1.0.0", path = "../../../utils/buffer"} async-recursion = "0.3.2" rand = "0.8.4" futures = "0.3.5" -key-utils = { version = "^1.0.0", path = "../../../utils/key-utils" } -clap = { version = "^4.5.4", features = ["derive"] } -tracing = { version = "0.1" } -tracing-subscriber = "0.3" -sha2 = "0.10.6" diff --git a/roles/test-utils/mining-device/src/main.rs b/roles/test-utils/mining-device/src/main.rs index 1bfbf6737a..a0cc047a2f 100644 --- a/roles/test-utils/mining-device/src/main.rs +++ b/roles/test-utils/mining-device/src/main.rs @@ -1,116 +1,35 @@ use async_std::net::TcpStream; -use key_utils::Secp256k1PublicKey; -use network_helpers_sv2::Connection; +use network_helpers_sv2::PlainConnection; use roles_logic_sv2::utils::Id; -use std::{net::SocketAddr, sync::Arc, thread::sleep, time::Duration}; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, +}; -use async_std::net::ToSocketAddrs; -use clap::Parser; -use rand::{thread_rng, Rng}; -use std::time::Instant; use stratum_common::bitcoin::{ blockdata::block::BlockHeader, hash_types::BlockHash, hashes::Hash, util::uint::Uint256, }; -use tracing::{error, info}; - -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -struct Args { - #[arg( - short, - long, - help = "Pool pub key, when left empty the pool certificate is not checked" - )] - pubkey_pool: Option, - #[arg( - short, - long, - help = "Sometimes used by the pool to identify the device" - )] - id_device: Option, - #[arg( - short, - long, - help = "Address of the pool in this format ip:port or domain:port" - )] - address_pool: String, - #[arg( - long, - help = "This value is used to slow down the cpu miner, it rapresents the number of micro-seconds that are awaited between hashes", - default_value = "0" - )] - handicap: u32, - #[arg( - long, - help = "User id, used when a new channel is opened, it can be used by the pool to identify the miner" - )] - id_user: Option, -} -async fn connect( - address: String, - pub_key: Option, - device_id: Option, - user_id: Option, - handicap: u32, -) { - let address = address - .clone() - .to_socket_addrs() - .await - .expect("Invalid pool address, use one of this formats: ip:port, domain:port") - .next() - .expect("Invalid pool address, use one of this formats: ip:port, domain:port"); - info!("Connecting to pool at {}", address); - let socket = loop { - let pool = - async_std::future::timeout(Duration::from_secs(5), TcpStream::connect(address)).await; - match pool { - Ok(result) => match result { - Ok(socket) => break socket, - Err(e) => { - error!( - "Failed to connect to Upstream role at {}, retrying in 5s: {}", - address, e - ); - sleep(Duration::from_secs(5)); - } - }, - Err(_) => { - error!("Pool is unresponsive, terminating"); - std::process::exit(1); - } - } - }; - info!("Pool tcp connection established at {}", address); - let address = socket.peer_addr().unwrap(); - let initiator = Initiator::new(pub_key.map(|e| e.0)); +async fn connect(address: SocketAddr, handicap: u32) { + let stream = TcpStream::connect(address).await.unwrap(); let (receiver, sender): (Receiver, Sender) = - Connection::new(socket, codec_sv2::HandshakeRole::Initiator(initiator), 10) - .await - .unwrap(); - info!("Pool noise connection established at {}", address); - Device::start(receiver, sender, address, device_id, user_id, handicap).await + PlainConnection::new(stream, 10).await; + Device::start(receiver, sender, address, handicap).await } #[async_std::main] async fn main() { - let args = Args::parse(); - tracing_subscriber::fmt::init(); - info!("start"); - connect( - args.address_pool, - args.pubkey_pool, - args.id_device, - args.id_user, - args.handicap, - ) - .await + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 34255); + //task::spawn(async move { connect(socket, 10000).await }); + //task::spawn(async move { connect(socket, 11070).await }); + //task::spawn(async move { connect(socket, 7040).await }); + println!("start"); + connect(socket, 0).await } use async_channel::{Receiver, Sender}; use binary_sv2::u256_from_int; -use codec_sv2::{Frame, Initiator, StandardEitherFrame, StandardSv2Frame}; +use codec_sv2::{Frame, StandardEitherFrame, StandardSv2Frame}; use roles_logic_sv2::{ common_messages_sv2::{Protocol, SetupConnection, SetupConnectionSuccess}, common_properties::{IsMiningUpstream, IsUpstream}, @@ -137,19 +56,12 @@ impl SetupConnectionHandler { pub fn new() -> Self { SetupConnectionHandler {} } - fn get_setup_connection_message( - address: SocketAddr, - device_id: Option, - ) -> SetupConnection<'static> { + fn get_setup_connection_message(address: SocketAddr) -> SetupConnection<'static> { let endpoint_host = address.ip().to_string().into_bytes().try_into().unwrap(); let vendor = String::new().try_into().unwrap(); let hardware_version = String::new().try_into().unwrap(); let firmware = String::new().try_into().unwrap(); - let device_id = device_id.unwrap_or_default(); - info!( - "Creating SetupConnection message with device id: {:?}", - device_id - ); + let device_id = String::new().try_into().unwrap(); SetupConnection { protocol: Protocol::MiningProtocol, min_version: 2, @@ -160,24 +72,22 @@ impl SetupConnectionHandler { vendor, hardware_version, firmware, - device_id: device_id.try_into().unwrap(), + device_id, } } pub async fn setup( self_: Arc>, receiver: &mut Receiver, sender: &mut Sender, - device_id: Option, address: SocketAddr, ) { - let setup_connection = Self::get_setup_connection_message(address, device_id); + let setup_connection = Self::get_setup_connection_message(address); let sv2_frame: StdFrame = MiningDeviceMessages::Common(setup_connection.into()) .try_into() .unwrap(); let sv2_frame = sv2_frame.into(); sender.send(sv2_frame).await.unwrap(); - info!("Setup connection sent to {}", address); let mut incoming: StdFrame = receiver.recv().await.unwrap().try_into().unwrap(); let message_type = incoming.get_header().unwrap().msg_type(); @@ -198,7 +108,6 @@ impl ParseUpstreamCommonMessages for SetupConnectionHandler { _: SetupConnectionSuccess, ) -> Result { use roles_logic_sv2::handlers::common::SendTo; - info!("Setup connection success"); Ok(SendTo::None(None)) } @@ -206,7 +115,6 @@ impl ParseUpstreamCommonMessages for SetupConnectionHandler { &mut self, _: roles_logic_sv2::common_messages_sv2::SetupConnectionError, ) -> Result { - error!("Setup connection error"); todo!() } @@ -232,17 +140,14 @@ pub struct Device { sequence_numbers: Id, } -fn open_channel(device_id: Option) -> OpenStandardMiningChannel<'static> { - let user_identity = device_id.unwrap_or_default().try_into().unwrap(); +fn open_channel() -> OpenStandardMiningChannel<'static> { + let user_identity = "ABC".to_string().try_into().unwrap(); let id: u32 = 10; - info!("Measuring CPU hashrate"); - let nominal_hash_rate = measure_hashrate(5) as f32; - info!("Pc hashrate is {}", nominal_hash_rate); - info!("MINING DEVICE: send open channel with request id {}", id); + println!("MINING DEVICE: send open channel with request id {}", id); OpenStandardMiningChannel { request_id: id.into(), user_identity, - nominal_hash_rate, + nominal_hash_rate: 1000.0, // use 1000 or 10000 to test group channels max_target: u256_from_int(567_u64), } } @@ -252,20 +157,11 @@ impl Device { mut receiver: Receiver, mut sender: Sender, addr: SocketAddr, - device_id: Option, - user_id: Option, handicap: u32, ) { let setup_connection_handler = Arc::new(Mutex::new(SetupConnectionHandler::new())); - SetupConnectionHandler::setup( - setup_connection_handler, - &mut receiver, - &mut sender, - device_id, - addr, - ) - .await; - info!("Pool sv2 connection established at {}", addr); + SetupConnectionHandler::setup(setup_connection_handler, &mut receiver, &mut sender, addr) + .await; let miner = Arc::new(Mutex::new(Miner::new(handicap))); let self_ = Self { channel_opened: false, @@ -278,7 +174,7 @@ impl Device { sequence_numbers: Id::new(), }; let open_channel = - MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(open_channel(user_id))); + MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(open_channel())); let frame: StdFrame = open_channel.try_into().unwrap(); self_.sender.send(frame.into()).await.unwrap(); let self_mutex = std::sync::Arc::new(Mutex::new(self_)); @@ -289,7 +185,7 @@ impl Device { let handicap = miner.safe_lock(|m| m.handicap).unwrap(); std::thread::spawn(move || loop { std::thread::sleep(std::time::Duration::from_micros(handicap.into())); - if miner.safe_lock(|m| m.next_share()).unwrap().is_valid() { + if miner.safe_lock(|m| m.next_share()).unwrap().is_ok() { let nonce = miner.safe_lock(|m| m.header.unwrap().nonce).unwrap(); let time = miner.safe_lock(|m| m.header.unwrap().time).unwrap(); let job_id = miner.safe_lock(|m| m.job_id).unwrap(); @@ -418,7 +314,7 @@ impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> fo self.channel_opened = true; self.channel_id = Some(m.channel_id); let req_id = m.get_request_id_as_u32(); - info!( + println!( "MINING DEVICE: channel opened with: group id {}, channel id {}, request id {}", m.group_channel_id, m.channel_id, req_id ); @@ -461,12 +357,12 @@ impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> fo &mut self, m: SubmitSharesSuccess, ) -> Result, Error> { - info!("SUCCESS {:?}", m); + println!("SUCCESS {:?}", m); Ok(SendTo::None(None)) } fn handle_submit_shares_error(&mut self, _: SubmitSharesError) -> Result, Error> { - info!("Submit shares error"); + println!("Submit shares error"); Ok(SendTo::None(None)) } @@ -529,11 +425,8 @@ impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> fo todo!() } - fn handle_set_target(&mut self, m: SetTarget) -> Result, Error> { - self.miner - .safe_lock(|miner| miner.new_target(m.maximum_target.to_vec())) - .unwrap(); - Ok(SendTo::None(None)) + fn handle_set_target(&mut self, _: SetTarget) -> Result, Error> { + todo!() } fn handle_reconnect(&mut self, _: Reconnect) -> Result, Error> { @@ -564,10 +457,6 @@ impl Miner { fn new_target(&mut self, mut target: Vec) { // target is sent in LE and comparisons in this file are done in BE target.reverse(); - let hex_string = target - .iter() - .fold("".to_string(), |acc, b| acc + format!("{:02x}", b).as_str()); - info!("Set target to {}", hex_string); self.target = Some(Uint256::from_be_bytes(target.try_into().unwrap())); } @@ -594,78 +483,19 @@ impl Miner { }; self.header = Some(header); } - pub fn next_share(&mut self) -> NextShareOutcome { - if let Some(header) = self.header.as_ref() { - let mut hash = header.block_hash().as_hash().into_inner(); - hash.reverse(); - let hash = Uint256::from_be_bytes(hash); - if hash < *self.target.as_ref().unwrap() { - info!( - "Found share with nonce: {}, for target: {:?}, with hash: {:?}", - header.nonce, self.target, hash, - ); - NextShareOutcome::ValidShare - } else { - NextShareOutcome::InvalidShare - } + pub fn next_share(&mut self) -> Result<(), ()> { + let header = self.header.as_ref().ok_or(())?; + let mut hash = header.block_hash().as_hash().into_inner(); + hash.reverse(); + let hash = Uint256::from_be_bytes(hash); + if hash < *self.target.as_ref().ok_or(())? { + println!( + "Found share with nonce: {}, for target: {:?}, with hash: {:?}", + header.nonce, self.target, hash, + ); + Ok(()) } else { - std::thread::yield_now(); - NextShareOutcome::InvalidShare + Err(()) } } } - -enum NextShareOutcome { - ValidShare, - InvalidShare, -} - -impl NextShareOutcome { - pub fn is_valid(&self) -> bool { - matches!(self, NextShareOutcome::ValidShare) - } -} - -// returns hashrate based on how fast the device hashes over the given duration -fn measure_hashrate(duration_secs: u64) -> f64 { - let mut rng = thread_rng(); - let prev_hash: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); - let prev_hash = Hash::from_inner(prev_hash); - // We create a random block that we can hash, we are only interested in knowing how many hashes - // per unit of time we can do - let merkle_root: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); - let merkle_root = Hash::from_inner(merkle_root); - let header = BlockHeader { - version: rng.gen(), - prev_blockhash: BlockHash::from_hash(prev_hash), - merkle_root, - time: std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH - std::time::Duration::from_secs(60)) - .unwrap() - .as_secs() as u32, - bits: rng.gen(), - nonce: 0, - }; - let start_time = Instant::now(); - let mut hashes: u64 = 0; - let duration = Duration::from_secs(duration_secs); - let mut miner = Miner::new(0); - // We put the target to 0 we are only interested in how many hashes per unit of time we can do - // and do not want to be botherd by messages about valid shares found. - miner.new_target(vec![0_u8; 32]); - miner.header = Some(header); - - while start_time.elapsed() < duration { - miner.next_share(); - hashes += 1; - } - - let elapsed_secs = start_time.elapsed().as_secs_f64(); - hashes as f64 / elapsed_secs -} -fn generate_random_32_byte_array() -> [u8; 32] { - let mut rng = thread_rng(); - let mut arr = [0u8; 32]; - rng.fill(&mut arr[..]); - arr -} diff --git a/roles/translator/Cargo.toml b/roles/translator/Cargo.toml index 182370cbd4..79d8720192 100644 --- a/roles/translator/Cargo.toml +++ b/roles/translator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "translator_sv2" -version = "0.1.1" +version = "0.1.0" edition = "2021" description = "Server used to bridge SV1 miners to SV2 pools" license = "MIT OR Apache-2.0" @@ -18,8 +18,8 @@ async-std = { version = "1.12.0", features = ["attributes"] } binary_sv2 = { version = "^1.0.0", path = "../../protocols/v2/binary-sv2/binary-sv2" } buffer_sv2 = { version = "^1.0.0", path = "../../utils/buffer" } codec_sv2 = { version = "^1.0.1", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2", "with_buffer_pool"] } -framing_sv2 = { version = "^1.1.0", path = "../../protocols/v2/framing-sv2" } -network_helpers_sv2 = { version = "2.0.0", path = "../roles-utils/network-helpers", features=["async_std", "with_buffer_pool"] } +framing_sv2 = { version = "^1.0.0", path = "../../protocols/v2/framing-sv2" } +network_helpers_sv2 = { version = "1.0.0", path = "../roles-utils/network-helpers", features=["async_std", "with_buffer_pool"] } once_cell = "1.12.0" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] } diff --git a/roles/translator/README.md b/roles/translator/README.md index e09e4fd304..ce8a075829 100644 --- a/roles/translator/README.md +++ b/roles/translator/README.md @@ -1,6 +1,4 @@ - # SV1 to SV2 Translator Proxy - This proxy is designed to sit in between a SV1 Downstream role (most typically Mining Device(s) running SV1 firmware) and a SV2 Upstream role (most typically a SV2 Pool Server with Extended Channel support). @@ -22,37 +20,36 @@ The most typical high level configuration is: ``` ## Setup - ### Configuration File - -`tproxy-config-local-jdc-example.toml` and `tproxy-config-local-pool-example.toml` are examples of configuration files for the Translator Proxy. +The `proxy-config-example.toml` is a configuration example which can be copy/paste into `/conf` directory by the party that is running the Translator Proxy (most +typically the mining farm/miner hobbyist) to address the most preferred customization. The configuration file contains the following information: 1. The SV2 Upstream connection information which includes the SV2 Pool authority public key (`upstream_authority_pubkey`) and the SV2 Pool connection address (`upstream_address`) and port (`upstream_port`). -2. The SV1 Downstream socket information which includes the listening IP address +1. The SV1 Downstream connection information which includes the SV1 Mining Device address (`downstream_address`) and port (`downstream_port`). -3. The maximum and minimum SRI versions (`max_supported_version` and `min_supported_version`) that +1. The maximum and minimum SV2 versions (`max_supported_version` and `min_supported_version`) that the Translator Proxy implementer wants to support. Currently the only available version is `2`. -4. The desired minimum `extranonce2` size that the Translator Proxy implementer wants to use +1. The desired minimum `extranonce2` size that the Translator Proxy implementer wants to use (`min_extranonce2_size`). The `extranonce2` size is ultimately decided by the SV2 Upstream role, but if the specified size meets the SV2 Upstream role's requirements, the size specified in this configuration file should be favored. -5. The downstream difficulty params such as: -- the hashrate (hashes/s) of the weakest Mining Device that will be connecting to the Translator Proxy (`min_individual_miner_hashrate`) -- the number of shares per minute that Mining Devices should be sending to the Translator Proxy (`shares_per_minute`). -6. The upstream difficulty params such as: -- the interval in seconds to elapse before updating channel hashrate with the pool (`channel_diff_update_interval`) -- the estimated aggregate hashrate of all SV1 Downstream roles (`channel_nominal_hashrate`) +1. The Job Declarator information which includes the Pool JD connection address (`jd_address`) and the Template Provider connection address to which to connect (`tp_address`). +1. The difficulty params such as the hashrate (hashes/s) of the weakest Mining Device that will be connecting to the Translator Proxy (`min_individual_miner_hashrate`), the number of shares needed before a mining.set_difficulty update (`miner_num_submits_before_update`) and the number of shares per minute that Mining Devices should be sending to the Translator Proxy (`shares_per_minute`). Ultimately, the estimated aggregate hashrate of all SV1 Downstream roles (Mining + Devices) (`channel_nominal_hashrate`), which is communicated to the SV2 Upstream to help it decide a proper difficulty target. ### Run - -There are two files in `roles/translator/config-examples`: -- `tproxy-config-local-jdc-example.toml` which assumes the Job Declaration protocol is used and a JD Client is deployed locally -- `tproxy-config-local-pool-example.toml` which assumes Job Declaration protocol is NOT used, and a Pool is deployed locally - -```bash -cd roles/translator/config-examples/ -cargo run -- -c tproxy-config-local-jdc-example.toml \ No newline at end of file +1. Copy the `proxy-config-example.toml` into `conf/` directory. +2. Edit it with custom desired configuration and rename it `proxy-config.toml` +3. Point the SV1 Downstream Mining Device(s) to the Translator Proxy IP address and port. +4. Run the Translator Proxy: + + ``` + cd roles/translator + ``` + ``` + cargo run -p translator_sv2 -- -c conf/proxy-config.toml + ``` diff --git a/roles/translator/config-examples/tproxy-config-hosted-pool-example.toml b/roles/translator/config-examples/tproxy-config-hosted-pool-example.toml deleted file mode 100644 index 47d4ea8758..0000000000 --- a/roles/translator/config-examples/tproxy-config-hosted-pool-example.toml +++ /dev/null @@ -1,36 +0,0 @@ -# Braiins Pool Upstream Connection -# upstream_authority_pubkey = "u95GEReVMjK6k5YqiSFNqqTnKU4ypU2Wm8awa6tmbmDmk1bWt" -# upstream_address = "18.196.32.109" -# upstream_port = 3336 - -# Hosted SRI Pool Upstream Connection -upstream_address = "75.119.150.111" -upstream_port = 34254 -upstream_authority_pubkey = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72" - -# Local Mining Device Downstream Connection -downstream_address = "0.0.0.0" -downstream_port = 34255 - -# Version support -max_supported_version = 2 -min_supported_version = 2 - -# Minimum extranonce2 size for downstream -# Max value: 16 (leaves 0 bytes for search space splitting of downstreams) -# Max value for CGminer: 8 -# Min value: 2 -min_extranonce2_size = 8 - -# Difficulty params -[downstream_difficulty_config] -# hashes/s of the weakest miner that will be connecting (e.g.: 10 Th/s = 10_000_000_000_000.0) -min_individual_miner_hashrate=10_000_000_000_000.0 -# target number of shares per minute the miner should be sending -shares_per_minute = 6.0 - -[upstream_difficulty_config] -# interval in seconds to elapse before updating channel hashrate with the pool -channel_diff_update_interval = 60 -# estimated accumulated hashrate of all downstream miners (e.g.: 10 Th/s = 10_000_000_000_000.0) -channel_nominal_hashrate = 10_000_000_000_000.0 diff --git a/roles/translator/config-examples/tproxy-config-local-jdc-example.toml b/roles/translator/config-examples/tproxy-config-local-jdc-example.toml index 5fe4a8eebd..a8bc389aab 100644 --- a/roles/translator/config-examples/tproxy-config-local-jdc-example.toml +++ b/roles/translator/config-examples/tproxy-config-local-jdc-example.toml @@ -21,6 +21,7 @@ min_supported_version = 2 # Max value for CGminer: 8 # Min value: 2 min_extranonce2_size = 8 +coinbase_reward_sat = 5_000_000_000 # Difficulty params [downstream_difficulty_config] diff --git a/roles/translator/config-examples/tproxy-config-local-pool-example.toml b/roles/translator/config-examples/tproxy-config-local-pool-example.toml index b4359d5ab4..d963ec945c 100644 --- a/roles/translator/config-examples/tproxy-config-local-pool-example.toml +++ b/roles/translator/config-examples/tproxy-config-local-pool-example.toml @@ -21,6 +21,7 @@ min_supported_version = 2 # Max value for CGminer: 8 # Min value: 2 min_extranonce2_size = 8 +coinbase_reward_sat = 5_000_000_000 # Difficulty params [downstream_difficulty_config] diff --git a/roles/translator/src/args.rs b/roles/translator/src/args.rs index bf5e51c19d..e2f8d4df93 100644 --- a/roles/translator/src/args.rs +++ b/roles/translator/src/args.rs @@ -44,16 +44,7 @@ impl Args { Some(ArgsResult::None) } }, - ArgsState::ExpectPath => { - let path = PathBuf::from(item.clone()); - if !path.exists() { - return Some(ArgsResult::Help(format!( - "Error: File '{}' does not exist!", - path.display() - ))); - } - Some(ArgsResult::Config(path)) - } + ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))), ArgsState::Done => None, } }) diff --git a/roles/translator/src/main.rs b/roles/translator/src/main.rs index c1307a5a2f..84acbdbbaa 100644 --- a/roles/translator/src/main.rs +++ b/roles/translator/src/main.rs @@ -41,7 +41,7 @@ async fn main() { let proxy_config = match process_cli_args() { Ok(p) => p, - Err(e) => panic!("failed to load config: {}", e), + Err(_) => return, }; info!("PC: {:?}", &proxy_config); diff --git a/test/message-generator/test/bad-pool-config-test/bad-pool-config-test.json b/test/message-generator/test/bad-pool-config-test.json similarity index 98% rename from test/message-generator/test/bad-pool-config-test/bad-pool-config-test.json rename to test/message-generator/test/bad-pool-config-test.json index d5bbcb52db..32a0603ed6 100644 --- a/test/message-generator/test/bad-pool-config-test/bad-pool-config-test.json +++ b/test/message-generator/test/bad-pool-config-test.json @@ -17,7 +17,8 @@ "actions": [ ], "setup_commands": [ - { "command": "cargo", + { + "command": "cargo", "args": [ "run", "../../test/message-generator/mock/template-provider-mock0.json" @@ -174,7 +175,7 @@ "cleanup_commands": [ { "command": "pkill", - "args": ["-f", "pool_sv2", "-SIGINT"], + "args": ["pool", "-SIGINT"], "conditions": "None" } ], diff --git a/test/message-generator/test/bad-pool-config-test/bad-pool-config-test.sh b/test/message-generator/test/bad-pool-config-test/bad-pool-config-test.sh deleted file mode 100755 index 76f3342d74..0000000000 --- a/test/message-generator/test/bad-pool-config-test/bad-pool-config-test.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/bad-pool-config-test/bad-pool-config-test.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/interop-jd-translator/interop-jd-translator.json b/test/message-generator/test/interop-jd-translator.json similarity index 100% rename from test/message-generator/test/interop-jd-translator/interop-jd-translator.json rename to test/message-generator/test/interop-jd-translator.json diff --git a/test/message-generator/test/interop-jd-translator/interop-jd-translator.sh b/test/message-generator/test/interop-jd-translator/interop-jd-translator.sh deleted file mode 100755 index 3387c40180..0000000000 --- a/test/message-generator/test/interop-jd-translator/interop-jd-translator.sh +++ /dev/null @@ -1,13 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 -cargo llvm-cov --no-report -p jd_server -cargo llvm-cov --no-report -p jd_client -cargo llvm-cov --no-report -p translator_sv2 -cargo build -p sv1-mining-device - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/interop-jd-translator/interop-jd-translator.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.json b/test/message-generator/test/interop-jdc-change-upstream.json similarity index 97% rename from test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.json rename to test/message-generator/test/interop-jdc-change-upstream.json index 344b8d6ce7..eafc41c55d 100644 --- a/test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.json +++ b/test/message-generator/test/interop-jdc-change-upstream.json @@ -169,7 +169,6 @@ { "output_string": "SUCCESS SubmitSharesSuccess", "output_location": "StdOut", - "late_condition": false, "condition": true } ], @@ -182,11 +181,6 @@ "execution_commands": [ ], "cleanup_commands": [ - { - "command": "pkill", - "args": ["-f", "mining_device", "-SIGINT"], - "conditions": "None" - }, { "command": "pkill", "args": ["-f", "jd_server", "-SIGINT"], diff --git a/test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.sh b/test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.sh deleted file mode 100755 index 514b2e79e1..0000000000 --- a/test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.sh +++ /dev/null @@ -1,12 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p jd_server -cargo llvm-cov --no-report -p jd_client -cargo llvm-cov --no-report -p mining_proxy_sv2 -cargo build -p --no-report mining-device - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/interop-jdc-change-upstream/interop-jdc-change-upstream.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.json b/test/message-generator/test/interop-proxy-with-multi-ups-extended.json similarity index 100% rename from test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.json rename to test/message-generator/test/interop-proxy-with-multi-ups-extended.json diff --git a/test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.sh b/test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.sh deleted file mode 100755 index 4173ac30cb..0000000000 --- a/test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.sh +++ /dev/null @@ -1,11 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 -cargo llvm-cov --no-report -p mining_proxy_sv2 -cargo build --no-report -p mining-device - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/interop-proxy-with-multi-ups-extended/interop-proxy-with-multi-ups-extended.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.json b/test/message-generator/test/interop-proxy-with-multi-ups.json similarity index 100% rename from test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.json rename to test/message-generator/test/interop-proxy-with-multi-ups.json diff --git a/test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.sh b/test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.sh deleted file mode 100755 index 080224419c..0000000000 --- a/test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.sh +++ /dev/null @@ -1,11 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 -cargo llvm-cov --no-report -p mining_proxy_sv2 -cargo build -p mining-device - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/interop-proxy-with-multi-ups/interop-proxy-with-multi-ups.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.json b/test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc.json similarity index 100% rename from test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.json rename to test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc.json diff --git a/test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.sh b/test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.sh deleted file mode 100755 index 4957309d96..0000000000 --- a/test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p jd_server - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/jds-do-not-fail-on-wrong-tsdatasucc/jds-do-not-fail-on-wrong-tsdatasucc.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.json b/test/message-generator/test/jds-do-not-panic-if-jdc-close-connection.json similarity index 100% rename from test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.json rename to test/message-generator/test/jds-do-not-panic-if-jdc-close-connection.json diff --git a/test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.sh b/test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.sh deleted file mode 100755 index 706f13a759..0000000000 --- a/test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p jd_server - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/jds-do-not-panic-if-jdc-close-connection/jds-do-not-panic-if-jdc-close-connection.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.json b/test/message-generator/test/jds-do-not-stackoverflow-when-no-token.json similarity index 100% rename from test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.json rename to test/message-generator/test/jds-do-not-stackoverflow-when-no-token.json diff --git a/test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.sh b/test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.sh deleted file mode 100755 index b3a253b517..0000000000 --- a/test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.sh +++ /dev/null @@ -1,11 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 -cargo llvm-cov --no-report -p jd_client -cargo llvm-cov --no-report -p mining_proxy_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/jds-do-not-stackoverflow-when-no-token/jds-do-not-stackoverflow-when-no-token.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.json b/test/message-generator/test/pool-sri-test-1-standard.json similarity index 78% rename from test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.json rename to test/message-generator/test/pool-sri-test-1-standard.json index 24ae109c50..4f338cda2b 100644 --- a/test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.json +++ b/test/message-generator/test/pool-sri-test-1-standard.json @@ -145,32 +145,53 @@ } }, { - "command": "cargo", - "args": [ - "llvm-cov", - "--no-report", - "run", - "-p", - "pool_sv2", - "--", - "-c", - "../test/config/pool-mock-tp.toml" - ], - "conditions": { - "WithConditions": { - "conditions": [ - { - "output_string": "Listening for encrypted connection on: 127.0.0.1:34254", - "output_location": "StdOut", - "late_condition": false, - "condition": true - } - ], - "timer_secs": 320, - "warn_no_panic": false - } - } - }, + "command": "cargo", + "args": [ + "run", + "../../../test/message-generator/mock/template-provider-mock0.json" + ], + "conditions": { + "WithConditions": { + "conditions": [ + { + "output_string": "Running `target/debug/message_generator_sv2 ../../../test/message-generator/mock/template-provider-mock0.json`", + "output_location": "StdErr", + "late_condition": false, + "condition": true + } + ], + "timer_secs": 320, + "warn_no_panic": false + } + } + }, + { + "command": "cargo", + "args": [ + "llvm-cov", + "--no-report", + "run", + "-p", + "pool_sv2", + "--", + "-c", + "../test/config/pool-mock-tp.toml" + ], + "conditions": { + "WithConditions": { + "conditions": [ + { + "output_string": "Listening for encrypted connection on: 127.0.0.1:34254", + "output_location": "StdOut", + "late_condition": false, + "condition": true + } + ], + "timer_secs": 320, + "warn_no_panic": false + } + } + }, { "command": "cargo", "args": [ diff --git a/test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.sh b/test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.sh deleted file mode 100755 index ca9ad35589..0000000000 --- a/test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/pool-sri-test-1-standard/pool-sri-test-1-standard.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.json b/test/message-generator/test/pool-sri-test-close-channel.json similarity index 96% rename from test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.json rename to test/message-generator/test/pool-sri-test-close-channel.json index 8529af950d..a30f1b3c69 100644 --- a/test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.json +++ b/test/message-generator/test/pool-sri-test-close-channel.json @@ -105,11 +105,6 @@ } ], "cleanup_commands": [ - { - "command": "pkill", - "args": ["-f", "translator_sv2", "-SIGINT"], - "conditions": "None" - } ], "role": "server", "upstream": { diff --git a/test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.sh b/test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.sh deleted file mode 100755 index 0b13c3c9bd..0000000000 --- a/test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo build -p translator_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/pool-sri-test-close-channel/pool-sri-test-close-channel.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.json b/test/message-generator/test/pool-sri-test-extended_0.json similarity index 100% rename from test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.json rename to test/message-generator/test/pool-sri-test-extended_0.json diff --git a/test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.sh b/test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.sh deleted file mode 100755 index a5f3d77230..0000000000 --- a/test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.sh +++ /dev/null @@ -1,7 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/pool-sri-test-extended_0/pool-sri-test-extended_0.json || { echo 'mg test failed' ; exit 1; } diff --git a/test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.json b/test/message-generator/test/pool-sri-test-extended_1.json similarity index 100% rename from test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.json rename to test/message-generator/test/pool-sri-test-extended_1.json diff --git a/test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.sh b/test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.sh deleted file mode 100755 index 5a53a75090..0000000000 --- a/test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/pool-sri-test-extended_1/pool-sri-test-extended_1.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.json b/test/message-generator/test/pool-sri-test-reject-auth.json similarity index 98% rename from test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.json rename to test/message-generator/test/pool-sri-test-reject-auth.json index f1e8cbc488..b12ec44243 100644 --- a/test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.json +++ b/test/message-generator/test/pool-sri-test-reject-auth.json @@ -105,7 +105,7 @@ "utils/|experimental/|protocols/", "--cobertura", "--output-path", - "target/pool-sri-test-reject-auth.xml", + "target/pool-sri-test-1-standard.xml", "report" ], "conditions": { diff --git a/test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.sh b/test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.sh deleted file mode 100755 index 0e1662fb83..0000000000 --- a/test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/pool-sri-test-reject-auth/pool-sri-test-reject-auth.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/standard-coverage-test/standard-coverage-test.json b/test/message-generator/test/standard-coverage-test.json similarity index 89% rename from test/message-generator/test/standard-coverage-test/standard-coverage-test.json rename to test/message-generator/test/standard-coverage-test.json index a9a8daa93b..0e237b5084 100644 --- a/test/message-generator/test/standard-coverage-test/standard-coverage-test.json +++ b/test/message-generator/test/standard-coverage-test.json @@ -181,6 +181,27 @@ } } }, + { + "command": "cargo", + "args": [ + "run", + "../../../test/message-generator/mock/template-provider-mock1.json" + ], + "conditions": { + "WithConditions": { + "conditions": [ + { + "output_string": "Running `target/debug/message_generator_sv2 ../../../test/message-generator/mock/template-provider-mock1.json`", + "output_location": "StdErr", + "late_condition": false, + "condition": true + } + ], + "timer_secs": 320, + "warn_no_panic": false + } + } + }, { "command": "cargo", "args": [ "llvm-cov", diff --git a/test/message-generator/test/standard-coverage-test/standard-coverage-test.sh b/test/message-generator/test/standard-coverage-test/standard-coverage-test.sh deleted file mode 100755 index 22befe8eb3..0000000000 --- a/test/message-generator/test/standard-coverage-test/standard-coverage-test.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo llvm-cov --no-report -p pool_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/standard-coverage-test/standard-coverage-test.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/sv1-test/sv1-test.json b/test/message-generator/test/sv1-test.json similarity index 94% rename from test/message-generator/test/sv1-test/sv1-test.json rename to test/message-generator/test/sv1-test.json index bd38929b34..90a1e36598 100644 --- a/test/message-generator/test/sv1-test/sv1-test.json +++ b/test/message-generator/test/sv1-test.json @@ -136,17 +136,6 @@ } ], "execution_commands": [ - { - "command": "pkill", - "args": ["-f", "translator_sv2", "-SIGINT"], - "conditions": "None" - }, - { - "command": "pkill", - "args": ["-f", "pool_sv2", "-SIGINT"], - "conditions": "None" - } - ], "cleanup_commands": [ ], diff --git a/test/message-generator/test/sv1-test/sv1-test.sh b/test/message-generator/test/sv1-test/sv1-test.sh deleted file mode 100755 index 99ce8a4c7f..0000000000 --- a/test/message-generator/test/sv1-test/sv1-test.sh +++ /dev/null @@ -1,10 +0,0 @@ -cd roles -cargo build -p pool_sv2 -cargo build -p translator_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/sv1-test/sv1-test.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.json b/test/message-generator/test/translation-proxy-broke-pool.json similarity index 95% rename from test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.json rename to test/message-generator/test/translation-proxy-broke-pool.json index caa1330b0f..2fb9026b0b 100644 --- a/test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.json +++ b/test/message-generator/test/translation-proxy-broke-pool.json @@ -91,12 +91,6 @@ "execution_commands": [ ], "cleanup_commands": [ - { - "command": "pkill", - "args": ["-f", "translator_sv2", "-SIGINT"], - "conditions": "None" - } - ], "role": "server", "upstream": { diff --git a/test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.sh b/test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.sh deleted file mode 100755 index a2a9077c4f..0000000000 --- a/test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd roles -cargo build -p translator_sv2 - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/translation-proxy-broke-pool/translation-proxy-broke-pool.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/test/message-generator/test/translation-proxy/translation-proxy.json b/test/message-generator/test/translation-proxy.json similarity index 96% rename from test/message-generator/test/translation-proxy/translation-proxy.json rename to test/message-generator/test/translation-proxy.json index d529dd2767..abdc7e6c5e 100644 --- a/test/message-generator/test/translation-proxy/translation-proxy.json +++ b/test/message-generator/test/translation-proxy.json @@ -192,16 +192,6 @@ } ], "cleanup_commands": [ - { - "command": "pkill", - "args": ["-f", "sv1-mining-device", "-SIGINT"], - "conditions": "None" - }, - { - "command": "pkill", - "args": ["-f", "translator_sv2", "-SIGINT"], - "conditions": "None" - } ], "role": "server", "upstream": { diff --git a/test/message-generator/test/translation-proxy/translation-proxy.sh b/test/message-generator/test/translation-proxy/translation-proxy.sh deleted file mode 100755 index 040fccfcc7..0000000000 --- a/test/message-generator/test/translation-proxy/translation-proxy.sh +++ /dev/null @@ -1,10 +0,0 @@ -cd roles -cargo build -p translator_sv2 -cargo build -p sv1-mining-device - -cd ../utils/message-generator/ -cargo build - -RUST_LOG=debug cargo run ../../test/message-generator/test/translation-proxy/translation-proxy.json || { echo 'mg test failed' ; exit 1; } - -sleep 10 diff --git a/utils/Cargo.lock b/utils/Cargo.lock index 3c7e5d36c4..7e69edbafe 100644 --- a/utils/Cargo.lock +++ b/utils/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.5.2" @@ -14,9 +29,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", @@ -45,9 +60,9 @@ checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -92,22 +107,193 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +dependencies = [ + "concurrent-queue", + "event-listener 5.0.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.3.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.2.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.2.0", + "async-executor", + "async-io 2.3.1", + "async-lock 3.3.0", + "blocking", + "futures-lite 2.2.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.2.0", + "parking", + "polling 3.4.0", + "rustix 0.38.31", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bech32" @@ -115,6 +301,24 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "binary_codec_sv2" +version = "1.0.0" +dependencies = [ + "buffer_sv2", +] + +[[package]] +name = "binary_sv2" +version = "1.0.0" +dependencies = [ + "binary_codec_sv2", + "derive_codec_sv2", + "serde", + "serde_sv2", + "tracing", +] + [[package]] name = "bip32_derivation" version = "1.0.0" @@ -131,22 +335,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ "bech32", - "bitcoin_hashes", + "bitcoin_hashes 0.11.0", "secp256k1 0.24.3", ] +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + [[package]] name = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "block-buffer" version = "0.9.0" @@ -156,6 +382,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.2.0", + "async-lock 3.3.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.2.0", + "piper", + "tracing", +] + [[package]] name = "bs58" version = "0.4.0" @@ -178,9 +420,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cast" @@ -190,9 +438,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -200,6 +451,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "cipher" version = "0.4.4" @@ -208,6 +483,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -216,11 +492,40 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "textwrap", "unicode-width", ] +[[package]] +name = "codec_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "buffer_sv2", + "const_sv2", + "framing_sv2", + "noise_sv2", + "serde", + "tracing", +] + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const_sv2" +version = "1.0.0" +dependencies = [ + "secp256k1 0.28.2", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -332,6 +637,13 @@ dependencies = [ "cipher", ] +[[package]] +name = "derive_codec_sv2" +version = "1.0.0" +dependencies = [ + "binary_codec_sv2", +] + [[package]] name = "digest" version = "0.9.0" @@ -343,14 +655,226 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] [[package]] name = "error_handling" version = "1.0.0" +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.0.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "framing_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "buffer_sv2", + "const_sv2", + "serde", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -363,9 +887,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -374,19 +898,56 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug", "polyval", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" -version = "1.8.3" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hashbrown" @@ -398,6 +959,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -407,12 +974,126 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iai" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + [[package]] name = "inout" version = "0.1.3" @@ -422,6 +1103,26 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.5", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -433,15 +1134,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -457,55 +1158,227 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "network_helpers" +version = "1.0.0" +dependencies = [ + "async-channel 1.9.0", + "async-std", + "binary_sv2", + "codec_sv2", + "const_sv2", + "futures", + "serde", + "tokio", + "tracing", +] + +[[package]] +name = "noise_sv2" +version = "1.1.0" +dependencies = [ + "aes-gcm", + "chacha20poly1305", + "const_sv2", + "rand", + "rand_chacha", + "secp256k1 0.28.2", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.5", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "libc" -version = "0.2.154" +name = "parking" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] -name = "log" -version = "0.4.21" +name = "parking_lot" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] [[package]] -name = "memchr" -version = "2.7.2" +name = "parking_lot_core" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] [[package]] -name = "num-traits" -version = "0.2.19" +name = "pin-project" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ - "autocfg", + "pin-project-internal", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "pin-project-internal" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] [[package]] -name = "oorandom" -version = "11.1.3" +name = "pin-project-lite" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] [[package]] name = "plotters" @@ -535,11 +1408,52 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.31", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", "cpufeatures", @@ -555,18 +1469,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -603,9 +1517,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -621,11 +1535,20 @@ dependencies = [ "crossbeam-utils", ] +[[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 = "regex" -version = "1.10.4" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -635,9 +1558,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -646,15 +1569,62 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rpc" +version = "1.0.0" +dependencies = [ + "base64", + "hex", + "http-body-util", + "hyper", + "hyper-util", + "serde", + "serde_json", + "stratum-common", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -665,13 +1635,19 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "secp256k1" version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.11.0", "secp256k1-sys 0.6.1", ] @@ -681,6 +1657,7 @@ version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ + "bitcoin_hashes 0.13.0", "rand", "secp256k1-sys 0.9.2", ] @@ -705,9 +1682,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] @@ -724,26 +1701,34 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_sv2" +version = "1.0.0" +dependencies = [ + "buffer_sv2", + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -757,22 +1742,65 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "slip132" -version = "0.10.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbc5035a82511d65570e5731ad66fc69893ad0adc3fbbf1a0bb7aa534e89fb" +checksum = "890b12cf298c4548739d6b1e53286576e43014ff1d3421751f2c26c80cc7a639" dependencies = [ "amplify", "bitcoin", ] +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "stratum-common" version = "1.0.0" dependencies = [ "bitcoin", - "secp256k1 0.28.2", ] [[package]] @@ -794,9 +1822,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.62" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f660c3bfcefb88c538776b6685a0c472e3128b51e74d48793dc2a488196e8eb" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -822,15 +1850,125 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "toml" version = "0.5.6" source = "git+https://github.com/diondokter/toml-rs?rev=c4161aa#c4161aa70202b3992dbec79b76e7a8659713b604" dependencies = [ - "hashbrown", + "hashbrown 0.7.2", "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -845,9 +1983,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "universal-hash" @@ -859,22 +1997,43 @@ dependencies = [ "subtle", ] +[[package]] +name = "value-bag" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "walkdir" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -883,9 +2042,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -893,24 +2052,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.48", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -918,28 +2089,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -963,11 +2134,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "windows-sys", + "winapi", ] [[package]] @@ -976,75 +2147,140 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" +name = "windows_i686_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/utils/key-utils/Cargo.toml b/utils/key-utils/Cargo.toml index 55c5bba15f..42fa67d8a1 100644 --- a/utils/key-utils/Cargo.toml +++ b/utils/key-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "key-utils" -version = "1.1.0" +version = "1.0.0" edition = "2021" description = "Key utils" license = "MIT OR Apache-2.0" diff --git a/utils/key-utils/src/lib.rs b/utils/key-utils/src/lib.rs index 9643b060bd..fdfc0c7de8 100644 --- a/utils/key-utils/src/lib.rs +++ b/utils/key-utils/src/lib.rs @@ -1,9 +1,6 @@ use bs58::{decode, decode::Error as Bs58DecodeError}; use core::convert::TryFrom; -use secp256k1::{ - schnorr::Signature, Keypair, Message as SecpMessage, Secp256k1, SecretKey, SignOnly, - VerifyOnly, XOnlyPublicKey, -}; +use secp256k1::{SecretKey, XOnlyPublicKey}; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; @@ -30,8 +27,6 @@ impl Display for Error { } } -impl std::error::Error for Error {} - impl From for Error { fn from(e: Bs58DecodeError) -> Self { Error::Bs58Decode(e) @@ -144,50 +139,6 @@ impl From for Secp256k1PublicKey { } } -pub struct SignatureService { - secp_sign: Secp256k1, - secp_verify: Secp256k1, -} - -impl SignatureService { - pub fn new() -> Self { - SignatureService { - secp_sign: Secp256k1::signing_only(), - secp_verify: Secp256k1::verification_only(), - } - } - - pub fn sign(&self, message: Vec, private_key: SecretKey) -> Signature { - let secret_key = private_key; - let kp = Keypair::from_secret_key(&self.secp_sign, &secret_key); - - self.secp_sign - .sign_schnorr(&SecpMessage::from_digest_slice(&message).unwrap(), &kp) - } - - pub fn verify( - &self, - message: Vec, - signature: secp256k1::schnorr::Signature, - public_key: XOnlyPublicKey, - ) -> Result<(), secp256k1::Error> { - let x_only_public_key = public_key; - - // Verify signature - self.secp_verify.verify_schnorr( - &signature, - &secp256k1::Message::from_digest_slice(&message)?, - &x_only_public_key, - ) - } -} - -impl Default for SignatureService { - fn default() -> Self { - Self::new() - } -} - #[cfg(test)] mod test { use super::*; diff --git a/utils/message-generator/Cargo.lock b/utils/message-generator/Cargo.lock new file mode 100644 index 0000000000..c2279ee98a --- /dev/null +++ b/utils/message-generator/Cargo.lock @@ -0,0 +1,1513 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "binary_codec_sv2" +version = "1.0.0" +dependencies = [ + "buffer_sv2", +] + +[[package]] +name = "binary_sv2" +version = "1.0.0" +dependencies = [ + "binary_codec_sv2", + "derive_codec_sv2", + "serde", + "serde_sv2", + "tracing", +] + +[[package]] +name = "bitcoin" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" +dependencies = [ + "bech32", + "bitcoin_hashes 0.11.0", + "secp256k1 0.24.3", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7a2e9773ee7ae7f2560f0426c938f57902dcb9e39321b0cbd608f47ed579a4" +dependencies = [ + "byteorder", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +dependencies = [ + "sha2", +] + +[[package]] +name = "buffer_sv2" +version = "1.0.0" +dependencies = [ + "aes-gcm", + "serde", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "codec_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "buffer_sv2", + "const_sv2", + "framing_sv2", + "noise_sv2", + "serde", + "tracing", +] + +[[package]] +name = "common_messages_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "const_sv2", + "serde", + "serde_repr", +] + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const_sv2" +version = "1.0.0" +dependencies = [ + "secp256k1 0.28.2", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_codec_sv2" +version = "1.0.0" +dependencies = [ + "binary_codec_sv2", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "framing_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "buffer_sv2", + "const_sv2", + "serde", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "job_declaration_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "const_sv2", + "serde", +] + +[[package]] +name = "key-utils" +version = "1.0.0" +dependencies = [ + "bs58", + "secp256k1 0.28.2", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "load_file" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31da4bce62428941030036a44d0d4b123f031b04080f8aeb44248b41de3e79cd" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "message_generator_sv2" +version = "1.0.0" +dependencies = [ + "arbitrary", + "async-channel", + "binary_sv2", + "codec_sv2", + "const_sv2", + "key-utils", + "load_file", + "network_helpers", + "rand", + "roles_logic_sv2", + "secp256k1 0.28.2", + "serde", + "serde_json", + "sv1_api", + "tokio", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "mining_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "const_sv2", + "serde", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "network_helpers" +version = "1.0.0" +dependencies = [ + "async-channel", + "binary_sv2", + "codec_sv2", + "const_sv2", + "futures", + "serde", + "tokio", + "tracing", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "noise_sv2" +version = "1.1.0" +dependencies = [ + "aes-gcm", + "chacha20poly1305", + "const_sv2", + "rand", + "rand_chacha", + "secp256k1 0.28.2", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "roles_logic_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "chacha20poly1305", + "common_messages_sv2", + "const_sv2", + "framing_sv2", + "job_declaration_sv2", + "mining_sv2", + "nohash-hasher", + "serde", + "siphasher", + "stratum-common", + "template_distribution_sv2", + "tracing", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "bitcoin_hashes 0.11.0", + "secp256k1-sys 0.6.1", +] + +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "bitcoin_hashes 0.13.0", + "rand", + "secp256k1-sys 0.9.2", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_sv2" +version = "1.0.0" +dependencies = [ + "buffer_sv2", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54ac45299ccbd390721be55b412d41931911f654fa99e2cb8bfb57184b2061fe" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stratum-common" +version = "1.0.0" +dependencies = [ + "bitcoin", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "sv1_api" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "bitcoin_hashes 0.3.2", + "byteorder", + "hex", + "log", + "pretty_env_logger", + "serde", + "serde_json", + "tracing", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "template_distribution_sv2" +version = "1.0.0" +dependencies = [ + "binary_sv2", + "const_sv2", + "serde", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/utils/message-generator/Cargo.toml b/utils/message-generator/Cargo.toml index b1a8a119d7..c6337be74c 100644 --- a/utils/message-generator/Cargo.toml +++ b/utils/message-generator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "message_generator_sv2" -version = "1.0.1" +version = "1.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -11,7 +11,7 @@ binary_sv2 = { version = "1.0.0", path = "../../protocols/v2/binary-sv2/binary-s codec_sv2 = { version = "1.0.0", path = "../../protocols/v2/codec-sv2", features = ["noise_sv2","with_buffer_pool","with_serde"] } const_sv2 = { version = "1.0.0", path = "../../protocols/v2/const-sv2" } load_file = "1.0.1" -network_helpers_sv2 = { version = "2.0.0", path = "../../roles/roles-utils/network-helpers", features = ["with_tokio","with_serde"] } +network_helpers_sv2 = { version = "1.0.0", path = "../../roles/roles-utils/network-helpers", features = ["with_tokio","with_serde"] } roles_logic_sv2 = { version = "1.0.0", path = "../../protocols/v2/roles-logic-sv2", features = ["with_serde"] } v1 = { version = "^1.0.0", path = "../../protocols/v1", package="sv1_api" } serde = { version = "*", features = ["derive", "alloc"], default-features = false } diff --git a/utils/message-generator/README.md b/utils/message-generator/README.md index e4d797ee26..0f9361b311 100644 --- a/utils/message-generator/README.md +++ b/utils/message-generator/README.md @@ -1,6 +1,5 @@ # Message Generator - Little utility to execute interoperability tests between SRI and other Sv2 complaint software. ## Try it diff --git a/utils/message-generator/src/main.rs b/utils/message-generator/src/main.rs index 695b3919cd..b996c002ea 100644 --- a/utils/message-generator/src/main.rs +++ b/utils/message-generator/src/main.rs @@ -26,7 +26,7 @@ use std::{ }, vec::Vec, }; -use tracing::{error, info}; +use tracing::info; use tracing_core::{Event, Subscriber}; use tracing_subscriber::{ filter::EnvFilter, @@ -371,13 +371,6 @@ where } } -fn load_file(path: &str) -> String { - std::fs::read_to_string(path).unwrap() -} -fn string_to_static_str(s: String) -> &'static str { - Box::leak(s.into_boxed_str()) -} - #[tokio::main] async fn main() { tracing_subscriber::fmt() @@ -390,11 +383,11 @@ async fn main() { info!("EXECUTING {}", test_path); info!(""); let mut _test_path = args[1].clone(); - //_test_path.insert_str(0, "../"); + _test_path.insert_str(0, "../"); let test_path_ = &_test_path; // Load contents of `test.json`, then parse - let test_static = string_to_static_str(load_file(test_path_)); - let test = parser::Parser::parse_test(test_static); + let test = load_str!(test_path_); + let test = parser::Parser::parse_test(test); let test_name: String = test_path .split('/') .collect::>() @@ -408,8 +401,7 @@ async fn main() { let pass = Arc::new(AtomicBool::new(false)); { let fail = fail.clone(); - std::panic::set_hook(Box::new(move |info| { - error!("{:#?}", info); + std::panic::set_hook(Box::new(move |_| { fail.store(true, Ordering::Relaxed); })); } @@ -431,7 +423,6 @@ async fn main() { }); } loop { - tokio::task::yield_now().await; if fail.load(Ordering::Relaxed) { clean_up(cleanup).await; let _ = std::panic::take_hook();