diff --git a/.github/workflows/check_lint_build.yaml b/.github/workflows/check_lint_build.yaml index 4d8a6d3..e347db3 100644 --- a/.github/workflows/check_lint_build.yaml +++ b/.github/workflows/check_lint_build.yaml @@ -25,6 +25,7 @@ name: Check, Lint, Build env: CARGO_TERM_COLOR: always + ELECTRS_VERSION: v3.2.0 jobs: check-lint: @@ -41,11 +42,23 @@ jobs: toolchain: nightly components: rustfmt, clippy - - name: Rust Cache + - name: Restore Rust cache + id: restore-rust-cache + uses: Swatinem/rust-cache@v2.9.1 + with: + cache-all-crates: "true" + prefix-key: "v0-rust-nightly" + save-if: "false" + shared-key: debug-x86_64-unknown-linux-gnu + + - name: Save Rust cache + if: steps.restore-rust-cache.outputs.cache-hit != 'true' uses: Swatinem/rust-cache@v2.9.1 with: - cache-bin: false - shared-key: x86_64-unknown-linux-gnu + cache-all-crates: "true" + lookup-only: "true" + prefix-key: "v0-rust-nightly" + shared-key: debug-x86_64-unknown-linux-gnu - name: Rustfmt run: cargo fmt --all -- --check @@ -74,10 +87,38 @@ jobs: (github.event_name == 'workflow_dispatch' && inputs.cargo_deny_check == 'auto' && (steps.changed-files.outputs.cargo_lock == 'true' || steps.changed-files.outputs.deny_toml == 'true')) uses: EmbarkStudios/cargo-deny-action@v2 + cache-electrs: + name: Build electrs if not cached + runs-on: ubuntu-latest + steps: + - name: Check cache + id: check-cache + uses: actions/cache/restore@v6 + with: + lookup-only: true + path: ${{ runner.temp }}/electrs/target/release/electrs + key: electrs-${{ env.ELECTRS_VERSION }} + + - name: Build electrs + if: steps.check-cache.outputs.cache-hit != 'true' + run: | + git clone --branch ${{ env.ELECTRS_VERSION }} --depth 1 https://github.com/mempool/electrs.git ${{ runner.temp }}/electrs + pushd ${{ runner.temp }}/electrs + cargo build --locked --release + popd + + - name: Save cache + if: steps.check-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + path: ${{ runner.temp }}/electrs/target/release/electrs + key: electrs-${{ env.ELECTRS_VERSION }} + + integration-test: name: Integration test runs-on: ubuntu-latest - needs: [check-lint] + needs: [cache-electrs, check-lint] steps: - name: Download latest bitcoin-patched run: | @@ -111,43 +152,31 @@ jobs: chmod +x bip300301-enforcer popd - - name: Checkout electrs - run: | - pushd .. - git clone https://github.com/mempool/electrs.git - popd - - - name: Install latest nightly toolchain - uses: dtolnay/rust-toolchain@master - with: - toolchain: nightly - target: x86_64-pc-windows-gnu - - - name: Rust Cache (electrs) - uses: Swatinem/rust-cache@v2.9.1 + - name: Restore electrs from cache + uses: actions/cache/restore@v6 with: - cache-bin: false - prefix-key: "v0-rust-electrs" - workspaces: ../electrs -> target - - - name: Install electrs - run: | - pushd ../electrs - cargo build --locked --release - popd + fail-on-cache-miss: true + path: ${{ runner.temp }}/electrs/target/release/electrs + key: electrs-${{ env.ELECTRS_VERSION }} - uses: actions/checkout@v6 with: submodules: "recursive" + - name: Install latest nightly toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly + - name: Rust Cache uses: Swatinem/rust-cache@v2.9.1 with: - cache-bin: false - shared-key: x86_64-unknown-linux-gnu + cache-all-crates: "true" + prefix-key: "v0-rust-nightly" + shared-key: debug-x86_64-unknown-linux-gnu - name: Build (debug) - run: cargo build + run: cargo build --bin thunder_app --example integration_tests - name: Run integration tests id: runIntegrationTests @@ -156,9 +185,9 @@ jobs: export BITCOIND='../bitcoin-patched-bins/bitcoind' export BITCOIND_UNPATCHED='../bitcoin-unpatched-bins/bitcoind' export BITCOIN_CLI='../bitcoin-patched-bins/bitcoin-cli' - export ELECTRS='../electrs/target/release/electrs' + export ELECTRS='${{ runner.temp }}/electrs/target/release/electrs' export THUNDER_APP='target/debug/thunder_app' - cargo run --example integration_tests + target/debug/examples/integration_tests test-build-release: strategy: @@ -187,6 +216,10 @@ jobs: contents: write timeout-minutes: 20 steps: + - name: Install windows-specific deps + run: sudo apt install mingw-w64 + if: ${{ matrix.name == 'x86_64-pc-windows-gnu' }} + - uses: actions/checkout@v6 with: submodules: recursive @@ -200,12 +233,9 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2.9.1 with: - cache-bin: false - key: ${{ matrix.name }} - - - name: Install windows-specific deps - run: sudo apt install mingw-w64 - if: ${{ matrix.name == 'x86_64-pc-windows-gnu' }} + cache-all-crates: "true" + prefix-key: "v0-rust-nightly" + shared-key: ${{ matrix.name }} - name: Test run: cargo test --tests diff --git a/.github/workflows/clean-gh-actions-caches-closed-pr-branch.yaml b/.github/workflows/clean-gh-actions-caches-closed-pr-branch.yaml new file mode 100644 index 0000000..934cccd --- /dev/null +++ b/.github/workflows/clean-gh-actions-caches-closed-pr-branch.yaml @@ -0,0 +1,30 @@ +name: Evict GitHub actions caches for closed/merged PR branches +on: + pull_request: + types: + - closed + workflow_dispatch: + +jobs: + cleanup: + permissions: + actions: write + runs-on: ubuntu-latest + steps: + - name: Cleanup + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge + run: | + echo "Fetching list of cache keys" + BRANCH_CACHE_KEYS=$(gh cache list --ref $BRANCH --json id --jq '.[].id') + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + echo "Deleting caches..." + for CACHE_KEY in $BRANCH_CACHE_KEYS + do + gh cache delete $CACHE_KEY + done + echo "Done" diff --git a/.github/workflows/clean-gh-actions-caches-nightly-rust.yaml b/.github/workflows/clean-gh-actions-caches-nightly-rust.yaml new file mode 100644 index 0000000..e95c38c --- /dev/null +++ b/.github/workflows/clean-gh-actions-caches-nightly-rust.yaml @@ -0,0 +1,31 @@ +name: Evict stale nightly Rust caches +on: + schedule: + # every 12 hours + - cron: "0 */12 * * *" + workflow_dispatch: + +jobs: + cleanup: + permissions: + actions: write + runs-on: ubuntu-latest + steps: + - name: Delete nightly Rust caches older than 48h + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + CUTOFF=$(date -u -d '48 hours ago' +%s) + + CACHE_IDS=$(gh cache list --repo "$REPO" --limit 500 \ + --json id,key,createdAt \ + --jq --argjson cutoff "$CUTOFF" \ + '.[] | select(.key | startswith("v0-rust-nightly")) + | select((.createdAt | sub("\\.[0-9]+"; "") | fromdateiso8601) < $cutoff) + | .id') + + for CACHE_ID in $CACHE_IDS; do + echo "Deleting cache $CACHE_ID" + gh cache delete "$CACHE_ID" --repo "$REPO" + done diff --git a/lib/net/error.rs b/lib/net/error.rs index 5710f06..b92b41b 100644 --- a/lib/net/error.rs +++ b/lib/net/error.rs @@ -41,6 +41,35 @@ pub enum AcceptConnection { ServerEndpointClosed, } +pub(in crate::net) mod configure_client { + use thiserror::Error; + + #[derive(Debug, Error)] + pub(in crate::net) enum Inner { + #[error(transparent)] + NoInitialCipherSuite( + #[from] quinn::crypto::rustls::NoInitialCipherSuite, + ), + #[error("rustls error")] + Rustls(#[source] rustls::Error), + } + + #[derive(Debug, Error)] + #[error("failed to configure p2p client")] + #[repr(transparent)] + pub struct Error(#[source] Inner); + + impl From for Error + where + Inner: From, + { + fn from(err: E) -> Self { + Self(err.into()) + } + } +} +pub use configure_client::Error as ConfigureClient; + #[allow(clippy::duplicated_attributes)] #[derive(Debug, Error, Transitive)] #[transitive(from(db::error::Put, db::Error))] @@ -58,6 +87,8 @@ pub enum Error { AlreadyConnected(#[from] AlreadyConnected), #[error("bincode error")] Bincode(#[from] bincode::Error), + #[error(transparent)] + ConfigureClient(#[from] ConfigureClient), #[error("connect error")] Connect(#[from] quinn::ConnectError), #[error(transparent)] @@ -74,8 +105,6 @@ pub enum Error { /// `0.0.0.0` is one example of an "unspecified" IP. #[error("unspecified peer ip address (cannot connect to '{0}')")] UnspecfiedPeerIP(IpAddr), - #[error(transparent)] - NoInitialCipherSuite(#[from] quinn::crypto::rustls::NoInitialCipherSuite), #[error("peer connection")] PeerConnection(#[source] Box), #[error("quinn rustls error")] diff --git a/lib/net/mod.rs b/lib/net/mod.rs index 1620a38..fe7a720 100644 --- a/lib/net/mod.rs +++ b/lib/net/mod.rs @@ -100,9 +100,11 @@ impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { } } -fn configure_client() --> Result { - let crypto = rustls::ClientConfig::builder() +fn configure_client() -> Result { + let crypto_provider = Arc::new(rustls::crypto::ring::default_provider()); + let crypto = rustls::ClientConfig::builder_with_provider(crypto_provider) + .with_safe_default_protocol_versions() + .map_err(error::configure_client::Inner::Rustls)? .dangerous() .with_custom_certificate_verifier(SkipServerVerification::new()) .with_no_client_auth();