diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcea29ec..d96e138b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,6 @@ on: - 'release/**' - 'master' pull_request: - branches: - - 'master' - - '**' - types: [opened, synchronize, reopened] jobs: fmt: @@ -20,10 +16,8 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - # Toolchain file bug workaround: https://github.com/dtolnay/rust-toolchain/issues/153 - run: rustup component add rustfmt - - name: Run Fmt Check - run: cargo fmt --all -- --check + - run: cargo fmt --all -- --check clippy: name: Clippy @@ -33,226 +27,30 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: rustup component add clippy - - name: Run clippy - run: cargo clippy -- -D warnings -A clippy::uninlined_format_args - - build: - if: | - (github.event_name == 'push' || github.event_name == 'pull_request') && - github.actor != 'github-actions[bot]' && - ( - !(github.event_name == 'pull_request' && - startsWith(github.event.pull_request.head.ref, 'release/') && - github.event.pull_request.base.ref == 'master') || - (github.event_name == 'pull_request' && - (contains(github.event.pull_request.head.ref, '/merge') || - startsWith(github.event.pull_request.head.ref, 'merge'))) - ) && - !(github.ref == 'refs/heads/master' && - github.event_name == 'push' && - (contains(github.event.head_commit.message, 'Release v') || - contains(github.event.head_commit.message, 'release/'))) - name: ${{ matrix.target }} (${{ matrix.runner }}) - runs-on: ${{ matrix.runner }} - timeout-minutes: 240 - strategy: - fail-fast: false - matrix: - include: - - runner: ubuntu-22.04 - target: x86_64-unknown-linux-gnu - platform: linux - arch: amd64 - - runner: macos-15-intel - target: x86_64-apple-darwin - platform: darwin - arch: amd64 - - runner: macos-latest - target: aarch64-apple-darwin - platform: darwin - arch: arm64 - - runner: windows-latest - target: x86_64-pc-windows-msvc - platform: win32 - arch: amd64 - - env: - BUILD_TYPE: release + - run: cargo clippy -- -D warnings -A clippy::uninlined_format_args + test: + name: Test + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - with: - ref: ${{ github.event_name == 'pull_request' && format('refs/pull/{0}/merge', github.event.pull_request.number) || github.ref_name }} - - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - uses: Swatinem/rust-cache@v2 with: - key: ${{ matrix.target }} cache-on-failure: true - - - name: Apple M1 setup - if: matrix.target == 'aarch64-apple-darwin' - run: | - echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV - echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV - - - name: Linux ARM setup - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update -y - sudo apt-get install -y gcc-aarch64-linux-gnu - echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV - - - name: Install MSVC target - if: matrix.target == 'x86_64-pc-windows-msvc' - run: rustup target add x86_64-pc-windows-msvc - - - name: Install OpenSSL development libraries - if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'x86_64-unknown-linux-gnu' + - name: Install dependencies run: | sudo apt-get update -y sudo apt-get install -y libssl-dev pkg-config - - - name: Setup cross-compilation for pkg-config - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV - echo "PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu" >> $GITHUB_ENV - echo "PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig" >> $GITHUB_ENV - echo "PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig" >> $GITHUB_ENV - - - name: Extract version name - id: extract_version - shell: bash - run: echo "VERSION_NAME=${GITHUB_REF#refs/heads/release/}" >> $GITHUB_ENV - - - name: Install vcpkg on Windows - if: matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg - C:\vcpkg\bootstrap-vcpkg.bat - C:\vcpkg\vcpkg integrate install - echo "VCPKG_ROOT=C:\vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - echo "C:\vcpkg" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - - name: Install CMake on Windows - if: matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - choco install cmake --version=3.20.0 --installargs 'ADD_CMAKE_TO_PATH=System' - refreshenv - cmake --version - echo "CMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Install dependencies with vcpkg on Windows - if: matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - C:\vcpkg\vcpkg install openssl:x64-windows-static-md zlib:x64-windows-static-md - - - name: Build binaries - working-directory: crates/cli - env: - CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake - shell: bash - run: | - set -eo pipefail - target="${{ matrix.target }}" - flags=() - - if [[ "$target" != *msvc* && "$target" != "aarch64-unknown-linux-gnu" ]]; then - flags+=(--features jemalloc) - fi - - [[ "$target" == *windows* ]] && exe=".exe" - - if [[ "$target" == *windows* ]]; then - export PATH="$PATH:/c/vcpkg" - echo "CMAKE_TOOLCHAIN_FILE: $CMAKE_TOOLCHAIN_FILE" - ls -l "$CMAKE_TOOLCHAIN_FILE" || echo "Toolchain file not found!" - fi - - if [[ "${{ env.BUILD_TYPE }}" == "release" ]]; then - RUST_BACKTRACE=1 CMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN_FILE" cargo build --release --target "$target" "${flags[@]}" -vv - else - RUST_BACKTRACE=1 CMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN_FILE" cargo build --target "$target" "${flags[@]}" -vv - fi - - - name: Smoke Test - shell: bash - run: | - set -eo pipefail - target="${{ matrix.target }}" - build_type="${{ env.BUILD_TYPE }}" - binary_path="${{ github.workspace }}/target/$target/$build_type/rrelayer_cli" - - if [[ "$target" == *windows* ]]; then - binary_path+=".exe" - fi - - echo "Running smoke test for $binary_path" - "$binary_path" --version - "$binary_path" help - - - name: Archive binaries - id: artifacts - if: startsWith(github.ref, 'refs/heads/release/') - env: - PLATFORM_NAME: ${{ matrix.platform }} - TARGET: ${{ matrix.target }} - ARCH: ${{ matrix.arch }} - VERSION_NAME: ${{ env.VERSION_NAME }} - shell: bash - run: | - set -eo pipefail - BUILD_DIR="${{ github.workspace }}/target/${TARGET}/${{ env.BUILD_TYPE }}" - CLI_BINARY_NAME="rrelayer_cli" - [[ "$PLATFORM_NAME" == "win32" ]] && CLI_BINARY_NAME="rrelayer_cli.exe" - - # Create a temporary staging directory for creating the archive - STAGING_DIR="staging" - mkdir -p "$STAGING_DIR" - - # Copy binaries to the staging directory - echo "Copying $BUILD_DIR/$CLI_BINARY_NAME to $STAGING_DIR/" - cp "$BUILD_DIR/$CLI_BINARY_NAME" "$STAGING_DIR/" - - # Create the final archive - if [ "$PLATFORM_NAME" == "linux" ] || [ "$PLATFORM_NAME" == "darwin" ]; then - FILE_NAME="rrelayer_${PLATFORM_NAME}-${ARCH}.tar.gz" - tar -czvf "$FILE_NAME" -C "$STAGING_DIR" . - else - FILE_NAME="rrelayer_${PLATFORM_NAME}-${ARCH}.zip" - (cd "$STAGING_DIR" && 7z a -tzip "${{ github.workspace }}/$FILE_NAME" .) - fi - - echo "Created archive: $FILE_NAME" - echo "file_name=$FILE_NAME" >> $GITHUB_OUTPUT - - name: Run tests - shell: bash - run: | - set -eo pipefail - target="${{ matrix.target }}" - - cargo test --exclude rust-sdk-playground --workspace --release --target "$target" - - - name: Upload artifact - if: startsWith(github.ref, 'refs/heads/release/') - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.platform }}-${{ matrix.arch }} - path: ${{ steps.artifacts.outputs.file_name }} + run: cargo test --exclude rust-sdk-playground --workspace create_pr: name: Create Release PR runs-on: ubuntu-22.04 - needs: build + needs: test if: | - github.actor != 'github-actions[bot]' && + github.actor != 'github-actions[bot]' && startsWith(github.ref, 'refs/heads/release/') steps: - uses: actions/checkout@v4 @@ -261,172 +59,17 @@ jobs: fetch-depth: 0 - name: Extract version from branch name - shell: bash run: | VERSION=${GITHUB_REF#refs/heads/release/} echo "VERSION_NAME=$VERSION" >> $GITHUB_ENV - name: Update Cargo.toml versions - shell: bash run: | sed -i 's/^version = ".*"/version = "${{ env.VERSION_NAME }}"/' crates/cli/Cargo.toml sed -i 's/^version = ".*"/version = "${{ env.VERSION_NAME }}"/' crates/core/Cargo.toml sed -i 's/^version = ".*"/version = "${{ env.VERSION_NAME }}"/' crates/sdk/Cargo.toml sed -i 's/^version = ".*"/version = "${{ env.VERSION_NAME }}"/' Cargo.toml - # Temporarily commented out changelog update for release process - # - name: Update Changelog - # shell: bash - # run: | - # CHANGELOG_FILE="documentation/rrelayer/docs/pages/changelog.mdx" - # DAY=$(date '+%d' | sed 's/^0*//') - # MONTH=$(date '+%B') - # YEAR=$(date '+%Y') - # - # # Add ordinal suffix - # case $DAY in - # 1|21|31) SUFFIX="st";; - # 2|22) SUFFIX="nd";; - # 3|23) SUFFIX="rd";; - # *) SUFFIX="th";; - # esac - # - # DATE="$DAY$SUFFIX $MONTH $YEAR" - # - # echo "Updating changelog for version ${{ env.VERSION_NAME }}" - # - # # Create changelog if it doesn't exist - # if [[ ! -f "$CHANGELOG_FILE" ]]; then - # cat > "$CHANGELOG_FILE" << EOF - # # Changelog - # - # ## Changes Not Deployed - # ------------------------------------------------- - # - # ### Features - # ------------------------------------------------- - # - # ### Bug fixes - # ------------------------------------------------- - # - # ### Breaking changes - # ------------------------------------------------- - # - # ## Releases - # ------------------------------------------------- - # - # all release branches are deployed through \`release/VERSION_NUMBER\` branches - # - # EOF - # fi - # - # # Create a temporary file to work with - # cp "$CHANGELOG_FILE" changelog_temp.md - # - # # Extract just the bug fixes line directly from Changes Not Deployed section - # BUG_FIXES=$(sed -n '/^## Changes Not Deployed/,/^## Releases/p' changelog_temp.md | grep "^- fix:" | head -5) - # - # # Use the simple extraction for now - # FEATURES="" - # BUG_FIXES="$BUG_FIXES" - # BREAKING_CHANGES="" - # - # # Save the extracted content for PR creation - # { - # echo "### Changes in this release:" - # echo "-------------------------------------------------" - # echo "### Features" - # echo "-------------------------------------------------" - # if [[ -n "$FEATURES" ]]; then - # echo "$FEATURES" - # fi - # echo "" - # echo "### Bug fixes" - # echo "-------------------------------------------------" - # if [[ -n "$BUG_FIXES" ]]; then - # echo "$BUG_FIXES" - # fi - # echo "" - # echo "### Breaking changes" - # echo "-------------------------------------------------" - # if [[ -n "$BREAKING_CHANGES" ]]; then - # echo "$BREAKING_CHANGES" - # fi - # } > pr_body_content.txt - # - # # Save to environment variable - # echo "PR_BODY_CONTENT<> $GITHUB_ENV - # cat pr_body_content.txt >> $GITHUB_ENV - # echo "EOF" >> $GITHUB_ENV - # - # # Create new release entry - # cat > new_release.txt << EOF - # # ${{ env.VERSION_NAME }}-beta - $DATE - # - # github branch - https://github.com/joshstevens19/rrelayer/tree/release/${{ env.VERSION_NAME }} - # - # - linux binary - https://github.com/joshstevens19/rrelayer/releases/download/v${{ env.VERSION_NAME }}/rrelayer_linux-amd64.tar.gz - # - mac apple silicon binary - https://github.com/joshstevens19/rrelayer/releases/download/v${{ env.VERSION_NAME }}/rrelayer_darwin-arm64.tar.gz - # - mac apple intel binary - https://github.com/joshstevens19/rrelayer/releases/download/v${{ env.VERSION_NAME }}/rrelayer_darwin-amd64.tar.gz - # - windows binary - https://github.com/joshstevens19/rrelayer/releases/download/v${{ env.VERSION_NAME }}/rrelayer_win32-amd64.zip - # EOF - # - # # Add sections if they have content - # if [[ -n "$FEATURES" && "$FEATURES" =~ [^[:space:]] ]]; then - # echo "" >> new_release.txt - # echo "### Features" >> new_release.txt - # echo "-------------------------------------------------" >> new_release.txt - # echo "$FEATURES" >> new_release.txt - # fi - # - # if [[ -n "$BUG_FIXES" && "$BUG_FIXES" =~ [^[:space:]] ]]; then - # echo "" >> new_release.txt - # echo "### Bug fixes" >> new_release.txt - # echo "-------------------------------------------------" >> new_release.txt - # echo "$BUG_FIXES" >> new_release.txt - # fi - # - # if [[ -n "$BREAKING_CHANGES" && "$BREAKING_CHANGES" =~ [^[:space:]] ]]; then - # echo "" >> new_release.txt - # echo "### Breaking changes" >> new_release.txt - # echo "-------------------------------------------------" >> new_release.txt - # echo "$BREAKING_CHANGES" >> new_release.txt - # fi - # - # # Get existing releases (everything after "## Releases") - # EXISTING_RELEASES=$(awk '/^## Releases/,0' changelog_temp.md | tail -n +5) - # - # # Create new changelog - # cat > "$CHANGELOG_FILE" << EOF - # # Changelog - # - # ## Changes Not Deployed - # ------------------------------------------------- - # - # ### Features - # ------------------------------------------------- - # - # ### Bug fixes - # ------------------------------------------------- - # - # ### Breaking changes - # ------------------------------------------------- - # - # ## Releases - # ------------------------------------------------- - # - # all release branches are deployed through \`release/VERSION_NUMBER\` branches - # - # $(cat new_release.txt) - # - # $EXISTING_RELEASES - # EOF - # - # # Clean up temporary files - # rm -f changelog_temp.md new_release.txt pr_body_content.txt - # - # echo "Changelog updated successfully" - - name: Commit changes run: | git config --local user.email "action@github.com" @@ -443,10 +86,8 @@ jobs: PR_EXISTS=$(gh pr list --base master --head release/${{ env.VERSION_NAME }} --json number --jq length) if [ "$PR_EXISTS" -gt 0 ]; then echo "pr_exists=true" >> $GITHUB_OUTPUT - echo "PR already exists, skipping creation" else echo "pr_exists=false" >> $GITHUB_OUTPUT - echo "No PR exists, will create one" fi - name: Create Pull Request @@ -459,334 +100,43 @@ jobs: --body "## Release v${{ env.VERSION_NAME }} This PR contains: - - ✅ Version bump to ${{ env.VERSION_NAME }} - - ✅ Changelog updated with release notes - - ✅ Ready for release + - Version bump to ${{ env.VERSION_NAME }} - **Merging this PR will automatically create a GitHub Release with binaries.** - - ${{ env.PR_BODY_CONTENT }}" \ + **Merging this PR will automatically create a GitHub Release and build Docker images.**" \ --base master \ --head release/${{ env.VERSION_NAME }} - release_build: - name: Build Release Binaries - runs-on: ${{ matrix.runner }} - if: | - github.actor != 'github-actions[bot]' && - github.ref == 'refs/heads/master' && - github.event_name == 'push' - timeout-minutes: 240 - strategy: - fail-fast: false - matrix: - include: - - runner: ubuntu-22.04 - target: x86_64-unknown-linux-gnu - platform: linux - arch: amd64 - - runner: macos-15-intel - target: x86_64-apple-darwin - platform: darwin - arch: amd64 - - runner: macos-latest - target: aarch64-apple-darwin - platform: darwin - arch: arm64 - - runner: windows-latest - target: x86_64-pc-windows-msvc - platform: win32 - arch: amd64 - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Check if this is a release commit and extract version - id: check_release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - echo "=== DEBUG: Checking recent commits ===" - git log --oneline -10 --pretty=format:"%H %s" - echo "" - echo "=== DEBUG: Checking for release pattern ===" - - # Check the most recent commit (HEAD) for release pattern - RECENT_COMMIT_MSG=$(git log --oneline -1 --pretty=format:"%s") - echo "Most recent commit: '$RECENT_COMMIT_MSG'" - - # Try to extract version from Release v pattern (including PR number) - VERSION_FROM_RELEASE=$(echo "$RECENT_COMMIT_MSG" | grep -o 'Release v[0-9]*\.[0-9]*\.[0-9]*' | sed 's/Release v//' || echo "") - echo "VERSION_FROM_RELEASE: '$VERSION_FROM_RELEASE'" - - if [[ -n "$VERSION_FROM_RELEASE" ]]; then - echo "VERSION_NAME=$VERSION_FROM_RELEASE" >> $GITHUB_ENV - echo "is_release=true" >> $GITHUB_OUTPUT - echo "Found release from commit title: Release v$VERSION_FROM_RELEASE" - else - echo "Not a release commit" - echo "is_release=false" >> $GITHUB_OUTPUT - fi - - - name: Skip if not a release - if: steps.check_release.outputs.is_release != 'true' - run: | - echo "Skipping release build - not a release commit" - exit 0 - - - name: Checkout release branch - if: steps.check_release.outputs.is_release == 'true' - uses: actions/checkout@v4 - with: - ref: release/${{ env.VERSION_NAME }} - fetch-depth: 0 - - - uses: dtolnay/rust-toolchain@stable - if: steps.check_release.outputs.is_release == 'true' - with: - targets: ${{ matrix.target }} - - - uses: Swatinem/rust-cache@v2 - if: steps.check_release.outputs.is_release == 'true' - with: - key: ${{ matrix.target }} - cache-on-failure: true - - - name: Apple M1 setup - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'aarch64-apple-darwin' - run: | - echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV - echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV - - - name: Install MSVC target - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'x86_64-pc-windows-msvc' - run: rustup target add x86_64-pc-windows-msvc - - - name: Install OpenSSL development libraries - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'x86_64-unknown-linux-gnu' - run: | - sudo apt-get update -y - sudo apt-get install -y libssl-dev pkg-config - - - name: Install vcpkg on Windows - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg - C:\vcpkg\bootstrap-vcpkg.bat - C:\vcpkg\vcpkg integrate install - echo "VCPKG_ROOT=C:\vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - echo "C:\vcpkg" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - - name: Install CMake on Windows - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - choco install cmake --version=3.20.0 --installargs 'ADD_CMAKE_TO_PATH=System' - refreshenv - cmake --version - echo "CMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Install dependencies with vcpkg on Windows - if: steps.check_release.outputs.is_release == 'true' && matrix.target == 'x86_64-pc-windows-msvc' - shell: pwsh - run: | - C:\vcpkg\vcpkg install openssl:x64-windows-static-md zlib:x64-windows-static-md - - - name: Build binaries - if: steps.check_release.outputs.is_release == 'true' - working-directory: crates/cli - env: - CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake - shell: bash - run: | - set -eo pipefail - target="${{ matrix.target }}" - - if [[ "$target" != *msvc* && "$target" != "aarch64-unknown-linux-gnu" ]]; then - flags+=(--features jemalloc) - fi - - if [[ "$target" == *windows* ]]; then - export PATH="$PATH:/c/vcpkg" - echo "CMAKE_TOOLCHAIN_FILE: $CMAKE_TOOLCHAIN_FILE" - ls -l "$CMAKE_TOOLCHAIN_FILE" || echo "Toolchain file not found!" - fi - - RUST_BACKTRACE=1 CMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN_FILE" cargo build --release --target "$target" -vv - - - name: Smoke Test - if: steps.check_release.outputs.is_release == 'true' - shell: bash - run: | - set -eo pipefail - target="${{ matrix.target }}" - binary_path="${{ github.workspace }}/target/$target/release/rrelayer_cli" - - if [[ "$target" == *windows* ]]; then - binary_path+=".exe" - fi - - echo "Running smoke test for $binary_path" - "$binary_path" --version - "$binary_path" help - - - name: Archive binaries - if: steps.check_release.outputs.is_release == 'true' - id: artifacts - env: - PLATFORM_NAME: ${{ matrix.platform }} - TARGET: ${{ matrix.target }} - ARCH: ${{ matrix.arch }} - VERSION_NAME: ${{ env.VERSION_NAME }} - shell: bash - run: | - set -eo pipefail - BUILD_DIR="${{ github.workspace }}/target/${TARGET}/release" - CLI_BINARY_NAME="rrelayer_cli" - [[ "$PLATFORM_NAME" == "win32" ]] && CLI_BINARY_NAME="rrelayer_cli.exe" - - # Create a temporary staging directory for creating the archive - STAGING_DIR="staging" - mkdir -p "$STAGING_DIR" - - # Copy binaries to the staging directory - echo "Copying $BUILD_DIR/$CLI_BINARY_NAME to $STAGING_DIR/" - cp "$BUILD_DIR/$CLI_BINARY_NAME" "$STAGING_DIR/" - - # Create the final archive - if [ "$PLATFORM_NAME" == "linux" ] || [ "$PLATFORM_NAME" == "darwin" ]; then - FILE_NAME="rrelayer_${PLATFORM_NAME}-${ARCH}.tar.gz" - tar -czvf "$FILE_NAME" -C "$STAGING_DIR" . - else - FILE_NAME="rrelayer_${PLATFORM_NAME}-${ARCH}.zip" - (cd "$STAGING_DIR" && 7z a -tzip "${{ github.workspace }}/$FILE_NAME" .) - fi - - echo "Created archive: $FILE_NAME" - echo "file_name=$FILE_NAME" >> $GITHUB_OUTPUT - - - name: Upload artifact - if: steps.check_release.outputs.is_release == 'true' - uses: actions/upload-artifact@v4 - with: - name: release-${{ matrix.platform }}-${{ matrix.arch }} - path: ${{ steps.artifacts.outputs.file_name }} - release: name: Create GitHub Release runs-on: ubuntu-22.04 - needs: release_build + needs: [fmt, clippy, test] if: | - github.actor != 'github-actions[bot]' && - github.ref == 'refs/heads/master' && + github.actor != 'github-actions[bot]' && + github.ref == 'refs/heads/master' && github.event_name == 'push' - outputs: - version: ${{ steps.check_release.outputs.version }} - is_release: ${{ steps.check_release.outputs.is_release }} steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Check if this is a release commit and extract version + - name: Check if this is a release commit id: check_release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash run: | - echo "=== DEBUG: Checking recent commits ===" - git log --oneline -10 --pretty=format:"%H %s" - echo "" - echo "=== DEBUG: Checking for release pattern ===" - - # Check the most recent commit (HEAD) for release pattern - RECENT_COMMIT_MSG=$(git log --oneline -1 --pretty=format:"%s") - echo "Most recent commit: '$RECENT_COMMIT_MSG'" - - # Try to extract version from Release v pattern (including PR number) - VERSION_FROM_RELEASE=$(echo "$RECENT_COMMIT_MSG" | grep -o 'Release v[0-9]*\.[0-9]*\.[0-9]*' | sed 's/Release v//' || echo "") - echo "VERSION_FROM_RELEASE: '$VERSION_FROM_RELEASE'" - - if [[ -n "$VERSION_FROM_RELEASE" ]]; then - echo "VERSION_NAME=$VERSION_FROM_RELEASE" >> $GITHUB_ENV + COMMIT_MSG=$(git log --oneline -1 --pretty=format:"%s") + VERSION=$(echo "$COMMIT_MSG" | grep -o 'Release v[0-9]*\.[0-9]*\.[0-9]*' | sed 's/Release v//' || echo "") + if [[ -n "$VERSION" ]]; then + echo "version=$VERSION" >> $GITHUB_OUTPUT echo "is_release=true" >> $GITHUB_OUTPUT - echo "version=$VERSION_FROM_RELEASE" >> $GITHUB_OUTPUT - echo "Found release from commit title: Release v$VERSION_FROM_RELEASE" else - echo "Not a release commit" echo "is_release=false" >> $GITHUB_OUTPUT - echo "version=" >> $GITHUB_OUTPUT fi - - name: Skip if not a release - if: steps.check_release.outputs.is_release != 'true' - run: | - echo "Skipping release creation - not a release commit" - exit 0 - - - name: Download release artifacts - if: steps.check_release.outputs.is_release == 'true' - uses: actions/download-artifact@v4 - with: - path: ./release-artifacts - - - name: Display structure of downloaded files - if: steps.check_release.outputs.is_release == 'true' - run: ls -la ./release-artifacts/ - - name: Create GitHub Release - if: steps.check_release.outputs.is_release == 'true' - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ env.VERSION_NAME }} - release_name: Release v${{ env.VERSION_NAME }} - draft: false - prerelease: false - body: | - Release v${{ env.VERSION_NAME }} - - ## Installation - ```bash - # Latest version - curl -sSfL https://docs.rrelayer.com/install.sh | bash - - # Specific version - curl -sSfL https://docs.rrelayer.com/install.sh | bash -s -- --version ${{ env.VERSION_NAME }} - ``` - continue-on-error: true - - - name: Upload Release Assets if: steps.check_release.outputs.is_release == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - for platform_dir in ./release-artifacts/*/; do - for file in "$platform_dir"*; do - if [[ -f "$file" ]]; then - filename=$(basename "$file") - echo "Uploading $filename" - gh release upload v${{ env.VERSION_NAME }} "$file" --clobber - fi - done - done - - docker: - name: Build and Publish Docker Image - needs: release - if: | - github.actor != 'github-actions[bot]' && - github.ref == 'refs/heads/master' && - github.event_name == 'push' - uses: ./.github/workflows/docker.yml - with: - version: ${{ needs.release.outputs.version }} - secrets: inherit + VERSION="${{ steps.check_release.outputs.version }}" + gh release create "v${VERSION}" \ + --title "Release v${VERSION}" \ + --generate-notes diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9ee58659..ba379f5e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,13 +4,7 @@ on: workflow_dispatch: inputs: version: - description: 'Release version (e.g., 1.2.3) - leave empty for master build' - required: false - type: string - workflow_call: - inputs: - version: - description: 'Release version (e.g., 1.2.3)' + description: 'Release version (e.g., 1.2.3) - leave empty for edge build' required: false type: string release: @@ -28,19 +22,13 @@ jobs: contents: read packages: write steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Create docker-binary directory - run: mkdir -p docker-binary - - - name: Set up Rust toolchain - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-gnu - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@v2 with: key: x86_64-unknown-linux-gnu-docker @@ -53,8 +41,7 @@ jobs: working-directory: crates/cli env: RUSTFLAGS: '-C target-cpu=x86-64-v2' - run: | - cargo build --release --target x86_64-unknown-linux-gnu --features jemalloc + run: cargo build --release --target x86_64-unknown-linux-gnu --features jemalloc - name: Prepare binary for Docker run: | @@ -62,23 +49,22 @@ jobs: cp target/x86_64-unknown-linux-gnu/release/rrelayer_cli docker-binary/rrelayer_cli chmod +x docker-binary/rrelayer_cli - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - - name: Log into registry ${{ env.REGISTRY }} + - name: Log into registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Generate SHA-based internal tag + - name: Generate tag id: tags run: | SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) echo "tag=${{ env.IMAGE }}:sha-${SHORT_SHA}-amd64" >> $GITHUB_OUTPUT - - name: Build and push AMD64 Docker image + - name: Build and push AMD64 image uses: docker/build-push-action@v6 with: context: . @@ -88,8 +74,8 @@ jobs: platforms: linux/amd64 provenance: mode=max sbom: true - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=docker-amd64 + cache-to: type=gha,mode=max,scope=docker-amd64 build-arm64: name: Build ARM64 Docker Image @@ -98,19 +84,13 @@ jobs: contents: read packages: write steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Create docker-binary directory - run: mkdir -p docker-binary + - uses: actions/checkout@v4 - - name: Set up Rust toolchain - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@stable with: targets: aarch64-unknown-linux-gnu - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@v2 with: key: aarch64-unknown-linux-gnu-docker @@ -123,8 +103,7 @@ jobs: working-directory: crates/cli env: RUSTFLAGS: '-C target-cpu=neoverse-n1' - run: | - cargo build --release --target aarch64-unknown-linux-gnu + run: cargo build --release --target aarch64-unknown-linux-gnu - name: Prepare binary for Docker run: | @@ -132,23 +111,22 @@ jobs: cp target/aarch64-unknown-linux-gnu/release/rrelayer_cli docker-binary/rrelayer_cli chmod +x docker-binary/rrelayer_cli - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - - name: Log into registry ${{ env.REGISTRY }} + - name: Log into registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Generate SHA-based internal tag + - name: Generate tag id: tags run: | SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) echo "tag=${{ env.IMAGE }}:sha-${SHORT_SHA}-arm64" >> $GITHUB_OUTPUT - - name: Build and push ARM64 Docker image + - name: Build and push ARM64 image uses: docker/build-push-action@v6 with: context: . @@ -158,8 +136,8 @@ jobs: platforms: linux/arm64 provenance: mode=max sbom: true - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=docker-arm64 + cache-to: type=gha,mode=max,scope=docker-arm64 create-manifest: name: Create Multi-Arch Manifest @@ -169,49 +147,37 @@ jobs: contents: read packages: write steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - - name: Log into registry ${{ env.REGISTRY }} + - name: Log into registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Determine version + id: version + run: | + if [ "${{ github.event_name }}" = "release" ]; then + VERSION="${{ github.event.release.tag_name }}" + echo "version=${VERSION#v}" >> $GITHUB_OUTPUT + elif [ -n "${{ inputs.version }}" ]; then + echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "version=" >> $GITHUB_OUTPUT + fi + - name: Create and push multi-arch manifest run: | SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) - AMD64_IMAGE="${{ env.IMAGE }}:sha-${SHORT_SHA}-amd64" - ARM64_IMAGE="${{ env.IMAGE }}:sha-${SHORT_SHA}-arm64" - - echo "Source images:" - echo " AMD64: $AMD64_IMAGE" - echo " ARM64: $ARM64_IMAGE" - - VERSION="${{ inputs.version }}" - + AMD64="${{ env.IMAGE }}:sha-${SHORT_SHA}-amd64" + ARM64="${{ env.IMAGE }}:sha-${SHORT_SHA}-arm64" + VERSION="${{ steps.version.outputs.version }}" + if [ -n "$VERSION" ]; then - # Release build: create version tag and latest tag - echo "Creating release manifests for version: $VERSION" - - # Version tag (e.g., 1.2.3) - echo "Creating manifest for tag: $VERSION" - docker buildx imagetools create -t "${{ env.IMAGE }}:$VERSION" \ - "$AMD64_IMAGE" \ - "$ARM64_IMAGE" - - # Latest tag - echo "Creating manifest for tag: latest" - docker buildx imagetools create -t "${{ env.IMAGE }}:latest" \ - "$AMD64_IMAGE" \ - "$ARM64_IMAGE" + docker buildx imagetools create -t "${{ env.IMAGE }}:${VERSION}" "$AMD64" "$ARM64" + docker buildx imagetools create -t "${{ env.IMAGE }}:latest" "$AMD64" "$ARM64" else - # Non-release build (master): create master tag only - echo "Creating master manifest" - docker buildx imagetools create -t "${{ env.IMAGE }}:master" \ - "$AMD64_IMAGE" \ - "$ARM64_IMAGE" + docker buildx imagetools create -t "${{ env.IMAGE }}:edge" "$AMD64" "$ARM64" fi - - echo "Manifests created successfully" diff --git a/Cargo.toml b/Cargo.toml index bdc8b63e..ef855207 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,25 @@ members = [ [workspace.dependencies] serde = { version = "1", features = ["derive"] } -serde_json = "1.0" -anyhow = "1.0.98" -alloy = { version = "1.1.3", features = ["full", "signer-mnemonic", "signer-keystore", "eips", "eip712"] } -alloy-rlp = "0.3.12" -alloy-eips = "1.1.3" +serde_json = "1" +serde_yaml = "0.9" +anyhow = "1" +thiserror = "2.0" +alloy = { version = "1.7", features = ["full", "signer-mnemonic", "signer-keystore", "eips", "eip712"] } +reqwest = { version = "0.13.2", features = ["json", "query"] } +dotenvy = "0.15.7" +tokio = { version = "1", features = ["full"] } +tokio-postgres = { version = "0.7", features = ["with-uuid-1", "with-chrono-0_4", "with-serde_json-1"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +async-trait = "0.1" +chrono = "0.4" +hex = "0.4" +base64 = "0.22" +rand = "0.10" +hmac = "0.12" +sha2 = "0.10" +regex = "1" [profile.release] lto = "fat" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index da537f45..604c2525 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -11,26 +11,24 @@ rrelayer = { path = "../sdk" } # external dependencies clap = { version = "4.4.11", features = ["derive"] } dialoguer = "0.11" -regex = "1.5.4" +regex = { workspace = true } colored = "2.0" -tokio = "1.35.1" -serde = { version = "1.0.204", features = ["derive"] } -serde_json = "1.0.120" -serde_yaml = "0.9.34" -thiserror = "1.0" +tokio = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = { workspace = true } +thiserror = { workspace = true } prettytable = "0.10.0" -chrono = "0.4.41" -hex = "0.4.3" +chrono = { workspace = true } +hex = { workspace = true } rpassword = "7.3" alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712", "signer-keystore"] } -alloy-rlp = { workspace = true } -alloy-eips = { workspace = true } # build tikv-jemalloc-ctl = { version = "0.6.0", optional = true } tikv-jemallocator = { version = "0.6.0", optional = true } -rand = "0.8.5" +rand = { workspace = true } [features] -jemalloc = ["dep:tikv-jemallocator", "dep:tikv-jemalloc-ctl"] +jemalloc = ["dep:tikv-jemallocator", "dep:tikv-jemalloc-ctl"] \ No newline at end of file diff --git a/crates/cli/src/commands/auth.rs b/crates/cli/src/commands/auth.rs index cfed4623..4e076a92 100644 --- a/crates/cli/src/commands/auth.rs +++ b/crates/cli/src/commands/auth.rs @@ -3,8 +3,7 @@ use crate::credentials::{self}; use crate::error::CliError; use clap::Subcommand; // use dialoguer::{Input, Password}; -use rand::Rng; -use rand::distributions::Alphanumeric; +use rand::distr::{Alphanumeric, SampleString}; #[derive(Subcommand)] pub enum AuthCommand { @@ -46,11 +45,7 @@ pub async fn handle_auth_command(cmd: &AuthCommand) -> Result<(), CliError> { list_profiles().await?; } AuthCommand::GenApiKey => { - let key = rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(8) - .map(char::from) - .collect::(); + let key = Alphanumeric.sample_string(&mut rand::rng(), 8); println!( "API key generated - note you have to config it in the networks yaml - {}", key diff --git a/crates/cli/src/commands/new.rs b/crates/cli/src/commands/new.rs index 668f1d6c..89b5ea9d 100644 --- a/crates/cli/src/commands/new.rs +++ b/crates/cli/src/commands/new.rs @@ -3,8 +3,7 @@ use std::{fs, path::Path}; use crate::project_location::ProjectLocation; use crate::{commands::error::InitError, print_error_message, print_success_message}; use dialoguer::{Confirm, Input}; -use rand::Rng; -use rand::distributions::Alphanumeric; +use rand::distr::{Alphanumeric, SampleString}; use rrelayer_core::network::ChainId; use rrelayer_core::{ ApiConfig, NetworkSetupConfig, RawSigningProviderConfig, SetupConfig, SigningProvider, @@ -25,11 +24,9 @@ fn write_gitignore(path: &Path) -> Result<(), WriteFileError> { } fn generate_random_credentials() -> (String, String) { - let username: String = - rand::thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect(); - - let password: String = - rand::thread_rng().sample_iter(&Alphanumeric).take(16).map(char::from).collect(); + let mut rng = rand::rng(); + let username = Alphanumeric.sample_string(&mut rng, 8); + let password = Alphanumeric.sample_string(&mut rng, 16); (format!("development_username_{}", username), format!("development_password_{}", password)) } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 094b2b25..fbbbd05d 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -18,50 +18,50 @@ include = [ ] [dependencies] -tokio-postgres = { version = "0.7", features = ["with-uuid-1", "with-chrono-0_4", "with-serde_json-1"] } -tokio = { version = "1", features = ["full"] } -axum = "0.7" -tower-http = { version = "0.5", features = ["cors"] } -dotenv = "0.15.0" +tokio-postgres = { workspace = true } +tokio = { workspace = true } +axum = "0.8" +tower-http = { version = "0.6", features = ["cors"] } +dotenvy = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -serde_yaml = "0.9.30" -async-trait = "0.1" -reqwest = { version = "0.12", features = ["json"] } +serde_yaml = { workspace = true } +async-trait = { workspace = true } +reqwest = { workspace = true } alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712", "signer-keystore", "signer-aws", "json-rpc"] } -alloy-rlp = { workspace = true } -alloy-eips = { workspace = true } uuid = { version = "1.0", features = ["v4", "serde"] } -rand = "0.8" +rand = { workspace = true } +rand_core = "0.6" aws-sdk-secretsmanager = "1.14.0" aws-sdk-kms = "1.14.0" aws-sdk-sts = "1.14.0" aws-config = "1.1.4" -base64 = "0.22.0" -chrono = "0.4.19" +base64 = { workspace = true } +chrono = { workspace = true } bytes = "1.5.0" -regex = "1.5.4" -thiserror = "1.0" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "time"] } +regex = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "time"] } once_cell = "1.20.2" native-tls = "0.2.12" -bb8 = "0.8.3" -bb8-postgres = "0.8.1" +bb8 = "0.9" +bb8-postgres = "0.9" postgres-native-tls = "0.5" -hex = "0.4.3" -anyhow = "1.0.98" +hex = { workspace = true } +anyhow = { workspace = true } rust_decimal = { version = "1.35.0", features = ["db-tokio-postgres"] } -google-secretmanager1 = "6.0" -hyper = "0.14" -hyper-rustls = "0.24" +google-secretmanager1 = { version = "7.0", features = ["yup-oauth2-service-account"] } +yup-oauth2 = { version = "12", default-features = false, features = ["service-account", "hyper-rustls", "ring"] } +hyper = "1.8" +hyper-rustls = "0.27" rustls = { version = "0.23.35", features = ["ring"]} -hmac = "0.12" -sha2 = "0.10" +hmac = { workspace = true } +sha2 = { workspace = true } p256 = { version = "0.13", features = ["ecdsa"] } tower = "0.5.2" subtle = "2.6.1" -cryptoki = "0.10" -secrecy = "0.8" -jsonwebtoken = "9.3" -rsa = "0.9" +cryptoki = "0.12" +secrecy = "0.10" +jsonwebtoken = "10" +rsa = "0.9" \ No newline at end of file diff --git a/crates/core/src/authentication/basic_auth.rs b/crates/core/src/authentication/basic_auth.rs index c9811ae8..5b5ab7ca 100644 --- a/crates/core/src/authentication/basic_auth.rs +++ b/crates/core/src/authentication/basic_auth.rs @@ -5,7 +5,6 @@ use axum::extract::Request; use axum::middleware::Next; use axum::response::Response; use axum::{ - async_trait, extract::FromRequestParts, http::{request::Parts, HeaderMap, StatusCode}, }; @@ -89,7 +88,6 @@ impl BasicAuthCredentials { pub struct Authenticated; /// Basic auth extractor that validates server-wide credentials -#[async_trait] impl FromRequestParts for Authenticated where S: Send + Sync, diff --git a/crates/core/src/environment.rs b/crates/core/src/environment.rs index 74504b45..f169b966 100644 --- a/crates/core/src/environment.rs +++ b/crates/core/src/environment.rs @@ -1,6 +1,6 @@ use std::path::Path; -use dotenv::{dotenv, from_path}; +use dotenvy::{dotenv, from_path}; pub fn load_env_from_project_path(project_path: &Path) { if from_path(project_path.join(".env")).is_err() { diff --git a/crates/core/src/middleware/authenticated.rs b/crates/core/src/middleware/authenticated.rs index e8558114..7aaed35d 100644 --- a/crates/core/src/middleware/authenticated.rs +++ b/crates/core/src/middleware/authenticated.rs @@ -1,5 +1,4 @@ use axum::{ - async_trait, extract::FromRequestParts, http::{request::Parts, StatusCode}, }; @@ -20,7 +19,6 @@ use tracing::error; #[allow(dead_code)] pub struct Authenticated; -#[async_trait] impl FromRequestParts for Authenticated where S: Send + Sync, diff --git a/crates/core/src/network/api/mod.rs b/crates/core/src/network/api/mod.rs index a7038dfe..bbd4b3b2 100644 --- a/crates/core/src/network/api/mod.rs +++ b/crates/core/src/network/api/mod.rs @@ -11,6 +11,6 @@ mod networks; pub fn create_network_routes() -> Router> { Router::new() .route("/", get(networks::networks)) - .route("/:chain_id", get(network::network)) - .route("/gas/price/:chain_id", get(get_gas_price::get_gas_price)) + .route("/{chain_id}", get(network::network)) + .route("/gas/price/{chain_id}", get(get_gas_price::get_gas_price)) } diff --git a/crates/core/src/postgres.rs b/crates/core/src/postgres.rs index 22c4bb1c..e5a639f1 100644 --- a/crates/core/src/postgres.rs +++ b/crates/core/src/postgres.rs @@ -4,7 +4,7 @@ use crate::rrelayer_error; use bb8::{Pool, RunError}; use bb8_postgres::PostgresConnectionManager; use bytes::Buf; -use dotenv::dotenv; +use dotenvy::dotenv; use native_tls::TlsConnector; use postgres_native_tls::MakeTlsConnector; use tokio::{task, time::timeout}; diff --git a/crates/core/src/provider/evm_provider.rs b/crates/core/src/provider/evm_provider.rs index 7036f38c..c307ef75 100644 --- a/crates/core/src/provider/evm_provider.rs +++ b/crates/core/src/provider/evm_provider.rs @@ -21,6 +21,7 @@ use crate::{ NetworkSetupConfig, }; use alloy::consensus::{SignableTransaction, TxEnvelope}; +use alloy::eips::eip2718::Encodable2718; use alloy::network::{AnyNetwork, AnyTransactionReceipt}; use alloy::rpc::client::RpcClient; use alloy::rpc::types::serde_helpers::WithOtherFields; @@ -40,8 +41,7 @@ use alloy::{ RpcError, TransportErrorKind, }, }; -use alloy_eips::eip2718::Encodable2718; -use rand::{thread_rng, Rng}; +use rand::RngExt; use reqwest::Url; use std::sync::Arc; use std::time::Duration; @@ -282,8 +282,8 @@ impl EvmProvider { } pub fn rpc_client(&self) -> Arc { - let mut rng = thread_rng(); - let index = rng.gen_range(0..self.rpc_clients.len()); + let mut rng = rand::rng(); + let index = rng.random_range(0..self.rpc_clients.len()); self.rpc_clients[index].clone() } diff --git a/crates/core/src/relayer/api/mod.rs b/crates/core/src/relayer/api/mod.rs index b1dec1ee..9749f366 100644 --- a/crates/core/src/relayer/api/mod.rs +++ b/crates/core/src/relayer/api/mod.rs @@ -40,15 +40,15 @@ use update_relay_max_gas_price::update_relay_max_gas_price; pub fn create_relayer_routes() -> Router> { // All routes handle authentication internally via validate_allowed_passed_basic_auth + validate_auth_basic_or_api_key Router::new() - .route("/:chain_id/new", post(create_relayer)) - .route("/:chain_id/import", post(import_relayer)) + .route("/{chain_id}/new", post(create_relayer)) + .route("/{chain_id}/import", post(import_relayer)) .route("/", get(get_relayers)) - .route("/:relayer_id", get(get_relayer_api)) - .route("/:relayer_id", delete(delete_relayer)) - .route("/:relayer_id/pause", put(pause_relayer)) - .route("/:relayer_id/unpause", put(unpause_relayer)) - .route("/:relayer_id/gas/max/:cap", put(update_relay_max_gas_price)) - .route("/:relayer_id/clone", post(clone_relayer)) - .route("/:relayer_id/allowlists", get(get_allowlist_addresses)) - .route("/:relayer_id/gas/eip1559/:enabled", put(update_relay_eip1559_status)) + .route("/{relayer_id}", get(get_relayer_api)) + .route("/{relayer_id}", delete(delete_relayer)) + .route("/{relayer_id}/pause", put(pause_relayer)) + .route("/{relayer_id}/unpause", put(unpause_relayer)) + .route("/{relayer_id}/gas/max/{cap}", put(update_relay_max_gas_price)) + .route("/{relayer_id}/clone", post(clone_relayer)) + .route("/{relayer_id}/allowlists", get(get_allowlist_addresses)) + .route("/{relayer_id}/gas/eip1559/{enabled}", put(update_relay_eip1559_status)) } diff --git a/crates/core/src/shared/utils.rs b/crates/core/src/shared/utils.rs index 861b2a88..d4f81302 100644 --- a/crates/core/src/shared/utils.rs +++ b/crates/core/src/shared/utils.rs @@ -2,8 +2,8 @@ use crate::network::ChainId; use crate::shared::{bad_request, HttpError}; use crate::transaction::types::TransactionBlob; use crate::{create_retry_client, rrelayer_error}; +use alloy::eips::eip4844::Blob; use alloy::primitives::U256; -use alloy_eips::eip4844::Blob; use std::time::Duration; use tokio::time::sleep; diff --git a/crates/core/src/signing/api/mod.rs b/crates/core/src/signing/api/mod.rs index 2436aa83..64175e4c 100644 --- a/crates/core/src/signing/api/mod.rs +++ b/crates/core/src/signing/api/mod.rs @@ -18,22 +18,22 @@ pub use sign_typed_data::SignTypedDataResult; pub fn create_signing_routes() -> Router> { // All signing routes handle authentication internally via validate_allowed_passed_basic_auth + validate_auth_basic_or_api_key Router::new() - .route("/relayers/:relayer_id/message", post(sign_text::sign_text)) - .route("/relayers/:relayer_id/typed-data", post(sign_typed_data::sign_typed_data)) + .route("/relayers/{relayer_id}/message", post(sign_text::sign_text)) + .route("/relayers/{relayer_id}/typed-data", post(sign_typed_data::sign_typed_data)) .route( - "/relayers/:relayer_id/text-history", + "/relayers/{relayer_id}/text-history", get(get_signed_text_history::get_signed_text_history), ) .route( - "/relayers/:relayer_id/typed-data-history", + "/relayers/{relayer_id}/typed-data-history", get(get_signed_typed_data_history::get_signed_typed_data_history), ) // @deprecated TODO: remove in a few months - .route("/:relayer_id/message", post(sign_text::sign_text)) - .route("/:relayer_id/typed-data", post(sign_typed_data::sign_typed_data)) - .route("/:relayer_id/text-history", get(get_signed_text_history::get_signed_text_history)) + .route("/{relayer_id}/message", post(sign_text::sign_text)) + .route("/{relayer_id}/typed-data", post(sign_typed_data::sign_typed_data)) + .route("/{relayer_id}/text-history", get(get_signed_text_history::get_signed_text_history)) .route( - "/:relayer_id/typed-data-history", + "/{relayer_id}/typed-data-history", get(get_signed_typed_data_history::get_signed_typed_data_history), ) } diff --git a/crates/core/src/startup.rs b/crates/core/src/startup.rs index 1efcc8ab..e39367ba 100644 --- a/crates/core/src/startup.rs +++ b/crates/core/src/startup.rs @@ -37,7 +37,7 @@ use axum::{ routing::get, Json, Router, }; -use dotenv::dotenv; +use dotenvy::dotenv; use rustls::crypto::ring::default_provider; use rustls::crypto::CryptoProvider; use std::collections::HashMap; diff --git a/crates/core/src/transaction/api/mod.rs b/crates/core/src/transaction/api/mod.rs index 1c9c213f..05059cbd 100644 --- a/crates/core/src/transaction/api/mod.rs +++ b/crates/core/src/transaction/api/mod.rs @@ -27,27 +27,27 @@ pub use types::TransactionSpeed; pub fn create_transactions_routes() -> Router> { // All transaction routes handle authentication internally via validate_allowed_passed_basic_auth + validate_auth_basic_or_api_key Router::new() - .route("/hash/:tx_hash", get(get_transaction_by_tx_hash::get_transaction_by_tx_hash_api)) + .route("/hash/{tx_hash}", get(get_transaction_by_tx_hash::get_transaction_by_tx_hash_api)) .route( - "/external/:external_id", + "/external/{external_id}", get(get_transaction_by_external_id::get_transaction_by_external_id_api), ) - .route("/:id", get(get_transaction_by_id::get_transaction_by_id_api)) - .route("/status/:id", get(get_transaction_status::get_transaction_status)) - .route("/relayers/:relayer_id/send", post(send_transaction::handle_send_transaction)) + .route("/{id}", get(get_transaction_by_id::get_transaction_by_id_api)) + .route("/status/{id}", get(get_transaction_status::get_transaction_status)) + .route("/relayers/{relayer_id}/send", post(send_transaction::handle_send_transaction)) .route( - "/relayers/:chain_id/send-random", + "/relayers/{chain_id}/send-random", post(send_random_transaction::send_transaction_random), ) - .route("/replace/:transaction_id", put(replace_transaction::replace_transaction)) - .route("/cancel/:transaction_id", put(cancel_transaction::cancel_transaction)) - .route("/relayers/:relayer_id", get(get_relayer_transactions::get_relayer_transactions)) + .route("/replace/{transaction_id}", put(replace_transaction::replace_transaction)) + .route("/cancel/{transaction_id}", put(cancel_transaction::cancel_transaction)) + .route("/relayers/{relayer_id}", get(get_relayer_transactions::get_relayer_transactions)) .route( - "/relayers/:relayer_id/pending/count", + "/relayers/{relayer_id}/pending/count", get(get_transactions_pending_count::get_transactions_pending_count), ) .route( - "/relayers/:relayer_id/inmempool/count", + "/relayers/{relayer_id}/inmempool/count", get(get_transactions_inmempool_count::get_transactions_inmempool_count), ) } diff --git a/crates/core/src/transaction/api/send_random_transaction.rs b/crates/core/src/transaction/api/send_random_transaction.rs index 55fc8b54..cccfcff4 100644 --- a/crates/core/src/transaction/api/send_random_transaction.rs +++ b/crates/core/src/transaction/api/send_random_transaction.rs @@ -9,7 +9,7 @@ use axum::{ http::HeaderMap, Json, }; -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; use std::sync::Arc; /// Handles random relayer selection for transaction requests @@ -44,7 +44,7 @@ async fn select_random_relayer( return Err(not_found(format!("No relayers found for chain {}", chain_id))); } - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); // TODO: it should be smart enough to also only pick the one with enough native funds to send the tx let available_relayers: Vec<_> = relayers .into_iter() diff --git a/crates/core/src/transaction/types/transaction.rs b/crates/core/src/transaction/types/transaction.rs index 96d43b45..7346f1c8 100644 --- a/crates/core/src/transaction/types/transaction.rs +++ b/crates/core/src/transaction/types/transaction.rs @@ -1,5 +1,10 @@ use std::fmt::Display; +use alloy::eips::eip4844::{ + builder::{SidecarBuilder, SimpleCoder}, + BlobTransactionSidecar, +}; +use alloy::eips::eip7594::BlobTransactionSidecarVariant; use alloy::{ consensus::{ TxEip1559, TxEip4844, TxEip4844Variant, TxEip4844WithSidecar, TxLegacy, TypedTransaction, @@ -7,11 +12,6 @@ use alloy::{ eips::eip2930::AccessList, primitives::TxKind, }; -use alloy_eips::eip4844::{ - builder::{SidecarBuilder, SimpleCoder}, - BlobTransactionSidecar, -}; -use alloy_eips::eip7594::BlobTransactionSidecarVariant; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use thiserror::Error; diff --git a/crates/core/src/transaction/types/transaction_blob.rs b/crates/core/src/transaction/types/transaction_blob.rs index 5a04aa85..c0a031a8 100644 --- a/crates/core/src/transaction/types/transaction_blob.rs +++ b/crates/core/src/transaction/types/transaction_blob.rs @@ -1,5 +1,5 @@ +use alloy::eips::eip4844::{Blob, BYTES_PER_BLOB}; use alloy::primitives::FixedBytes; -use alloy_eips::eip4844::{Blob, BYTES_PER_BLOB}; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use std::fmt::Display; diff --git a/crates/core/src/wallet/mnemonic_wallet_manager.rs b/crates/core/src/wallet/mnemonic_wallet_manager.rs index 44ac1163..ab2876cd 100644 --- a/crates/core/src/wallet/mnemonic_wallet_manager.rs +++ b/crates/core/src/wallet/mnemonic_wallet_manager.rs @@ -13,7 +13,6 @@ use alloy::signers::{ Signer, }; use async_trait::async_trait; -use rand::thread_rng; use std::collections::HashMap; use tokio::sync::Mutex; @@ -139,7 +138,7 @@ impl WalletManagerTrait for MnemonicWalletManager { /// Generates a new 24-word BIP39 mnemonic seed phrase. pub fn generate_seed_phrase() -> Result { - let mut rng = thread_rng(); + let mut rng = rand_core::OsRng; let mnemonic = Mnemonic::::new_with_count(&mut rng, 24) .map_err(|e| WalletError::MnemonicError(format!("Failed to generate mnemonic: {}", e)))?; let phrase = mnemonic.to_phrase(); diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 43b8162d..23b731ab 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -56,7 +56,7 @@ pub enum WalletError { StringEncodingError(#[from] std::string::FromUtf8Error), #[error("RLP decoding error: {0}")] - RlpError(#[from] alloy_rlp::Error), + RlpError(#[from] alloy::rlp::Error), #[error("Signature parsing error: {0}")] SignatureError(#[from] alloy::primitives::SignatureError), diff --git a/crates/core/src/wallet/pkcs11_wallet_manager.rs b/crates/core/src/wallet/pkcs11_wallet_manager.rs index 65d5a164..08525c21 100644 --- a/crates/core/src/wallet/pkcs11_wallet_manager.rs +++ b/crates/core/src/wallet/pkcs11_wallet_manager.rs @@ -6,12 +6,12 @@ use alloy::consensus::{SignableTransaction, TypedTransaction}; use alloy::dyn_abi::TypedData; use alloy::primitives::{keccak256, Address, Signature, B256, U256}; use async_trait::async_trait; -use cryptoki::context::{CInitializeArgs, Pkcs11}; +use cryptoki::context::{CInitializeArgs, CInitializeFlags, Pkcs11}; use cryptoki::mechanism::Mechanism; use cryptoki::object::{Attribute, AttributeType, ObjectClass, ObjectHandle}; use cryptoki::session::{Session, UserType}; use cryptoki::slot::Slot; -use secrecy::Secret; +use cryptoki::types::AuthPin; use std::collections::HashMap; use std::path::Path; use tokio::sync::Mutex; @@ -40,7 +40,7 @@ impl Pkcs11WalletManager { WalletError::GenericSignerError(format!("Failed to load PKCS#11 library: {}", e)) })?; - match ctx.initialize(CInitializeArgs::OsThreads) { + match ctx.initialize(CInitializeArgs::new(CInitializeFlags::OS_LOCKING_OK)) { Ok(_) => debug!("PKCS#11 library initialized successfully"), Err(e) => { let error_str = e.to_string().to_lowercase(); @@ -87,7 +87,7 @@ impl Pkcs11WalletManager { })?; if let Some(pin) = &self.config.pin { - let secret_pin = Secret::new(pin.clone()); + let secret_pin = AuthPin::from(pin.clone()); match session.login(UserType::User, Some(&secret_pin)) { Ok(_) => debug!("Successfully authenticated with PKCS#11 token"), Err(e) => { diff --git a/crates/core/src/wallet/privy_wallet_manager.rs b/crates/core/src/wallet/privy_wallet_manager.rs index dd968500..e62677e9 100644 --- a/crates/core/src/wallet/privy_wallet_manager.rs +++ b/crates/core/src/wallet/privy_wallet_manager.rs @@ -3,7 +3,7 @@ use crate::wallet::{WalletError, WalletManagerChainId, WalletManagerTrait}; use alloy::consensus::{TxEnvelope, TypedTransaction}; use alloy::dyn_abi::TypedData; use alloy::primitives::Signature; -use alloy_rlp::Decodable; +use alloy::rlp::Decodable; use async_trait::async_trait; use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/crates/core/src/wallet/turnkey_wallet_manager.rs b/crates/core/src/wallet/turnkey_wallet_manager.rs index a01c324c..be6f43bf 100644 --- a/crates/core/src/wallet/turnkey_wallet_manager.rs +++ b/crates/core/src/wallet/turnkey_wallet_manager.rs @@ -4,13 +4,10 @@ use crate::yaml::TurnkeySigningProviderConfig; use alloy::consensus::{TxEnvelope, TypedTransaction}; use alloy::dyn_abi::TypedData; use alloy::primitives::{keccak256, Signature}; -use alloy_rlp::Decodable; +use alloy::rlp::Decodable; use async_trait::async_trait; use base64::{engine::general_purpose, Engine as _}; -use p256::{ - ecdsa::{signature::Signer, Signature as EcdsaSignature, SigningKey}, - SecretKey, -}; +use p256::ecdsa::{signature::Signer, Signature as EcdsaSignature, SigningKey}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::str::FromStr; @@ -134,13 +131,11 @@ impl TurnkeyWalletManager { WalletError::ApiError { message: format!("Failed to decode private key: {}", e) } })?; - let secret_key = SecretKey::from_slice(&private_key_bytes).map_err(|e| { + let signing_key = SigningKey::from_slice(&private_key_bytes).map_err(|e| { error!("Failed to create secret key from bytes: {}", e); WalletError::ApiError { message: format!("Failed to create secret key: {}", e) } })?; - let signing_key = SigningKey::from(&secret_key); - let signature: EcdsaSignature = signing_key.sign(body.as_bytes()); let signature_bytes = signature.to_der(); let signature_hex = hex::encode(&signature_bytes); @@ -392,7 +387,7 @@ impl WalletManagerTrait for TurnkeyWalletManager { access_list: tx.access_list.clone(), }; - let encoded = alloy_rlp::encode(&unsigned_tx); + let encoded = alloy::rlp::encode(&unsigned_tx); format!("0x02{}", hex::encode(&encoded)) } TypedTransaction::Legacy(tx) => { @@ -406,7 +401,7 @@ impl WalletManagerTrait for TurnkeyWalletManager { input: tx.input.clone(), }; - let encoded = alloy_rlp::encode(&unsigned_tx); + let encoded = alloy::rlp::encode(&unsigned_tx); format!("0x{}", hex::encode(&encoded)) } TypedTransaction::Eip2930(tx) => { @@ -421,7 +416,7 @@ impl WalletManagerTrait for TurnkeyWalletManager { access_list: tx.access_list.clone(), }; - let encoded = alloy_rlp::encode(&unsigned_tx); + let encoded = alloy::rlp::encode(&unsigned_tx); format!("0x01{}", hex::encode(&encoded)) } TypedTransaction::Eip4844(tx_variant) => { @@ -448,7 +443,7 @@ impl WalletManagerTrait for TurnkeyWalletManager { max_fee_per_blob_gas: tx.max_fee_per_blob_gas, }; - let encoded = alloy_rlp::encode(&unsigned_tx); + let encoded = alloy::rlp::encode(&unsigned_tx); format!("0x03{}", hex::encode(&encoded)) } _ => { diff --git a/crates/e2e-tests/Cargo.toml b/crates/e2e-tests/Cargo.toml index 2d9cbb07..ce477fc8 100644 --- a/crates/e2e-tests/Cargo.toml +++ b/crates/e2e-tests/Cargo.toml @@ -10,23 +10,21 @@ path = "src/main.rs" [dependencies] # Core dependencies -tokio = { version = "1.0", features = ["full"] } -anyhow = "1.0" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_yaml = "0.9" +tokio = { workspace = true } +anyhow = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = { workspace = true } alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712", "signer-keystore", "signer-aws"] } -alloy-rlp = { workspace = true } -alloy-eips = { workspace = true } # HTTP client -reqwest = { version = "0.11", features = ["json"] } +reqwest = { workspace = true } # Database client for schema reset -tokio-postgres = "0.7" +tokio-postgres = { workspace = true } # Test framework assert_matches = "1.5" @@ -35,23 +33,20 @@ assert_matches = "1.5" rrelayer_core = { path = "../core" } rrelayer = { path = "../sdk" } -# Process management for Anvil -# tokio-process = "0.2" # Not needed, using tokio::process - # Time utilities -chrono = { version = "0.4", features = ["serde"] } -dotenv = "0.15" +chrono = { workspace = true, features = ["serde"] } +dotenvy = { workspace = true } futures = "0.3" # Temporary files tempfile = "3.8" # Simple HTTP server for gas API warp = "0.3" -rand = "0.9.2" +rand = { workspace = true } # Webhook testing dependencies -hmac = "0.12" -sha2 = "0.10" -hex = "0.4" +hmac = { workspace = true } +sha2 = { workspace = true } +hex = { workspace = true } [dev-dependencies] \ No newline at end of file diff --git a/crates/e2e-tests/src/main.rs b/crates/e2e-tests/src/main.rs index 472cf30f..e7aaacca 100644 --- a/crates/e2e-tests/src/main.rs +++ b/crates/e2e-tests/src/main.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use dotenv::dotenv; +use dotenvy::dotenv; use std::env; use tracing::{error, info}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 5ea9f5fd..ec5515bf 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -19,14 +19,14 @@ include = [ ] [dependencies] -reqwest = { version = "0.12.15", features = ["json", "native-tls", "cookies"] } +reqwest = { workspace = true, features = ["native-tls", "cookies"] } serde = { workspace = true } serde_json = { workspace = true } anyhow = { workspace = true } -thiserror = "2.0.6" +thiserror = { workspace = true } alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712"] } -base64 = "0.22.0" +base64 = { workspace = true } rrelayer_core = { path = "../core" } -tokio = { version = "1", features = ["time"] } -async-trait = "0.1" -hex = "0.4" +tokio = { workspace = true, features = ["time"] } +async-trait = { workspace = true } +hex = { workspace = true } \ No newline at end of file diff --git a/documentation/rrelayer/docs/pages/changelog.mdx b/documentation/rrelayer/docs/pages/changelog.mdx index 32801244..4049e352 100644 --- a/documentation/rrelayer/docs/pages/changelog.mdx +++ b/documentation/rrelayer/docs/pages/changelog.mdx @@ -10,10 +10,15 @@ ### Bug fixes +- chore: simplify CI/CD pipeline — Linux-only PR testing, Docker-only releases (no mac/windows binaries) + --- ### Breaking changes +- chore: bump dependencies across the workspace — `dotenv` replaced with `dotenvy`, `reqwest` 0.12 → 0.13, `thiserror` 1.0 → 2.0, `rand` 0.8 → 0.10, `axum` 0.7 → 0.8, `secrecy` 0.8 → 0.10, `cryptoki` 0.10 → 0.12, `google-secretmanager1` 6.0 → 7.0, `bb8`/`bb8-postgres` 0.8 → 0.9, `tower-http` 0.5 → 0.6, `hyper` 0.14 → 1.8, `jsonwebtoken` 9 → 10 +- chore: extract common dependencies to `[workspace.dependencies]` for consistent versioning + --- ## Releases diff --git a/playground/rust-sdk-playground/Cargo.toml b/playground/rust-sdk-playground/Cargo.toml index 5384033e..c04e573d 100644 --- a/playground/rust-sdk-playground/Cargo.toml +++ b/playground/rust-sdk-playground/Cargo.toml @@ -14,12 +14,12 @@ path = "src/lib.rs" [dependencies] rrelayer = { path = "../../crates/sdk" } eyre = "0.6" -anyhow = "1.0" -tokio = "1.47.1" -serde_json = "1.0.142" -serde = { version = "1.0", features = ["derive"] } +anyhow = { workspace = true } +tokio = { workspace = true } +serde_json = { workspace = true } +serde = { workspace = true } alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712"] } -hex = "0.4" -async-trait = "0.1" -thiserror = "1.0" +hex = { workspace = true } +async-trait = { workspace = true } +thiserror = { workspace = true } futures-util = "0.3" \ No newline at end of file