diff --git a/.changeset/.gitkeep b/.changeset/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/clippy.toml b/.clippy.toml similarity index 100% rename from clippy.toml rename to .clippy.toml diff --git a/.commitlintrc.yaml b/.commitlintrc.yaml new file mode 100644 index 0000000..763206d --- /dev/null +++ b/.commitlintrc.yaml @@ -0,0 +1,7 @@ +extends: ['@commitlint/config-conventional'] + +rules: + type-enum: + - 2 + - always + - [arch, build, ci, docs, feat, fix, perf, refactor, test] diff --git a/.cz.toml b/.cz.toml deleted file mode 100644 index 5ac0af5..0000000 --- a/.cz.toml +++ /dev/null @@ -1,7 +0,0 @@ -[tool.commitizen] -name = "cz_conventional_commits" -tag_format = "$version" -version_scheme = "semver" -version_provider = "cargo" -update_changelog_on_bump = true -major_version_zero = true diff --git a/.github/actions/setup-node/action.yaml b/.github/actions/setup-node/action.yaml new file mode 100644 index 0000000..47dc0af --- /dev/null +++ b/.github/actions/setup-node/action.yaml @@ -0,0 +1,29 @@ +name: Setup Node & PNPM +description: Install NodeJS and PNPM tooling + +runs: + using: composite + steps: + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: 9 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: |- + ${{ runner.os }}-pnpm-store- diff --git a/.github/actions/setup-rust/action.yaml b/.github/actions/setup-rust/action.yaml new file mode 100644 index 0000000..8ce1c50 --- /dev/null +++ b/.github/actions/setup-rust/action.yaml @@ -0,0 +1,43 @@ +name: Setup Rust +description: Install Rust tooling with Cache + +inputs: + target: + description: Rust target platforms + required: false + default: x86_64-unknown-linux-gnu + toolchain: + description: Rust toolchain version to install + required: true + default: stable + +runs: + using: composite + steps: + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ inputs.toolchain }} + target: ${{ inputs.target }} + components: clippy, rustfmt + + - name: Cache Rust toolchain + uses: actions/cache@v4 + with: + path: | + ~/.rustup + ~/.cargo/bin + key: ${{ runner.os }}-rust-${{ inputs.toolchain }}-${{ inputs.target }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-rust-${{ inputs.toolchain }}-${{ inputs.target }}- + + - name: Cache Cargo dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-rust-target-${{ inputs.toolchain }}-${{ inputs.target }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: |- + ${{ runner.os }}-rust-target-${{ inputs.toolchain }}-${{ inputs.target }}- diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 06a5b35..2b138c8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,11 +1,8 @@ name: CI -permissions: - contents: read - on: pull_request: - types: [opened, synchronize, edited, closed, reopened] + types: [opened, synchronize, edited, reopened] env: CARGO_TERM_COLOR: always @@ -17,13 +14,31 @@ concurrency: cancel-in-progress: true jobs: - validate-itle: + validate-title: name: Validate PR Title runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v4 + - uses: amannn/action-semantic-pull-request@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + requireScope: true + types: | + arch + build + ci + docs + feat + fix + perf + refactor + test + scopes: | + repo + release + data-stream + sdk-rust + sdk-ts lockfile: name: Validate Lockfile @@ -31,33 +46,57 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: ./.github/actions/setup-rust with: toolchain: stable + target: wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 - - name: Is lockfile updated? - run: cargo update --workspace --locked + - run: cargo update --workspace --locked - clippy: - name: Clippy + commitlint: + name: Validating commits runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable with: - toolchain: ${{ env.RUST_VERSION }} - targets: wasm32-unknown-unknown - components: clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --all-targets --all-features + fetch-depth: 0 + + - name: Setup Node && PNPM + uses: ./.github/actions/setup-node + + - name: Install commitlint + run: | + npm install @commitlint/config-conventional - pre-commit: - name: Linting & Formatting - permissions: - contents: read + - name: Validate current commit (last commit) with commitlint + if: github.event_name == 'push' + run: npx commitlint --last --verbose + + - name: Validate PR commits with commitlint + if: github.event_name == 'pull_request' + run: | + npx commitlint \ + --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} \ + --to ${{ github.event.pull_request.head.sha }} \ + --verbose + + lint: + name: Linting + if: "!startsWith(github.head_ref, 'releases/')" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - uses: pre-commit/action@v3.0.1 + - name: Install Rust + uses: ./.github/actions/setup-rust + with: + toolchain: nightly + target: wasm32-unknown-unknown + + - name: Install dependencies + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-sort@1.0.9 + + - name: Running linting + run: make lint diff --git a/.github/workflows/prepare_release.yaml b/.github/workflows/prepare_release.yaml new file mode 100644 index 0000000..b85cc97 --- /dev/null +++ b/.github/workflows/prepare_release.yaml @@ -0,0 +1,68 @@ +name: Open Release PR + +on: + push: + branches: [main, staging, release] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + CLICOLOR: 1 + RUST_VERSION: 1.78.0 + +jobs: + setup: + if: "!startsWith(github.event.head_commit.message, 'ci(release)')" + runs-on: ubuntu-latest + outputs: + branch: ${{ steps.set-vars.outputs.branch }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check for pre-release configuration + id: set-vars + run: | + echo "branch=changeset/release-main" >> $GITHUB_OUTPUT + + prepare-release: + if: "!startsWith(github.event.head_commit.message, 'ci(release)')" + needs: setup + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.REPO_TOKEN }} + + - name: Configure Git + run: | + git config --global user.name GitHub Actions + git config user.email github-actions@github.com + + - name: Install Rust + uses: ./.github/actions/setup-rust + with: + toolchain: nightly + + - uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-sort@1.0.9 + + - uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-edit@0.12.3 + + - uses: knope-dev/action@v2.1.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run knope prepare release + env: + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} + RELEASE_BRANCH: ${{ needs.setup.outputs.branch }} + run: knope prepare-release --verbose diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bed4b99..67b22c2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,121 +1,76 @@ name: Release on: - push: - branches: [main, staging, release] - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + pull_request: + types: [closed] + branches: [main] jobs: - setup: - runs-on: ubuntu-latest - outputs: - prerelease: ${{ steps.set-prerelease.outputs.prerelease }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup git user (for changelog step) - run: | - git config --global user.name "${{ github.actor }}" - git config --global user.email "${{ github.actor }}@users.noreply.github.com" + build-artifacts: + env: + archive_name: artifact - - name: Check for pre-release configuration - id: set-prerelease - run: | - if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then - echo "prerelease=nightly" >> $GITHUB_OUTPUT - elif [[ "${GITHUB_REF}" == "refs/heads/staging" ]]; then - echo "prerelease=rc" >> $GITHUB_OUTPUT - else - echo "prerelease=false" >> $GITHUB_OUTPUT + strategy: + fail-fast: false + matrix: + pkg: [fuel-core-nats] + os: [ubuntu-latest] + target: [x86_64-unknown-linux-gnu] - changelog: - runs-on: ubuntu-latest - needs: setup - outputs: - version: ${{ steps.save-outputs.outputs.version }} - changelog: ${{ steps.save-outputs.outputs.changelog }} - commit_message: ${{ steps.save-outputs.outputs.commit_message }} - branch: ${{ steps.save-outputs.outputs.branch }} + runs-on: ${{ matrix.os }} + name: ${{ matrix.pkg }} ${{ matrix.target }} steps: - - name: Checkout code - uses: actions/checkout@v4 - - - id: cz - name: Create bump and changelog - uses: commitizen-tools/commitizen-action@master + - uses: actions/checkout@v4 + - name: Install Rust + uses: ./.github/actions/setup-rust with: - github_token: ${{ secrets.GITHUB_TOKEN }} - changelog_increment_filename: body.md - prerelease: ${{ needs.setup.outputs.prerelease }} + toolchain: stable + target: wasm32-unknown-unknown - - name: Save outputs - id: save-outputs - run: | - version=${{ steps.cz.outputs.version }} - changelog=$(cat body.md) - commit_message="ci(bump): release ${version}" - branch="release-${{ steps.cz.outputs.version }}" + - name: Install host target + run: rustup target add ${{ matrix.target }} - echo "version=${version}" >> $GITHUB_OUTPUT - echo "changelog=${changelog}" >> $GITHUB_OUTPUT - echo "commit_message=${commit_message}" >> $GITHUB_OUTPUT - echo "branch=${branch}" >> $GITHUB_OUTPUT + - name: Build + run: make build TARGET=${{ matrix.target }} PACKAGE=${{ matrix.pkg }} - create_pr: - runs-on: ubuntu-latest - needs: changelog + - name: Set Archive Name + id: archive + run: echo "archive_name=${{ matrix.pkg }}-${{ matrix.target }}" >> $GITHUB_ENV - steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Create Tar Archive + run: | + mkdir ${{ env.archive_name }} + cp target/${{ matrix.target }}/release/${{ matrix.pkg }} ${{ env.archive_name }} + tar -czf ${{ env.archive_name }}.tgz ${{ env.archive_name }} - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v3 + - name: Upload Artifact + uses: actions/upload-artifact@v4.3.3 with: - commit-message: ${{ needs.changelog.outputs.commit_message }} - title: Release ${{ needs.changelog.outputs.version }} - body: | - ${{ needs.changelog.outputs.changelog }} - branch: ${{ needs.changelog.outputs.branch }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Check outputs - if: ${{ steps.cpr.outputs.pull-request-number }} - run: | - echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" - echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" + name: ${{ matrix.pkg }}-${{ matrix.target }} + path: ${{ env.archive_name }}.tgz + if-no-files-found: error release: + needs: [build-artifacts] runs-on: ubuntu-latest - needs: changelog - if: github.ref == 'refs/heads/release' - + permissions: + contents: read + actions: write steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Release - uses: softprops/action-gh-release@v1 + - uses: actions/checkout@v4.1.6 + - uses: actions/download-artifact@v4.1.7 with: - body_path: body.md - tag_name: ${{ needs.changelog.outputs.version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + path: artifacts + merge-multiple: true - notify: - runs-on: ubuntu-latest - if: failure() + - name: List artifacts + run: ls -R artifacts - steps: - - name: Error Notification - run: |- - echo "An error occurred during the release process" - # Optionally, send a notification to Slack or email + - uses: knope-dev/action@v2.1.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - run: knope release + env: + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} diff --git a/.github/workflows/update_deps.yaml b/.github/workflows/update_deps.yaml index d1f2023..53d64b3 100644 --- a/.github/workflows/update_deps.yaml +++ b/.github/workflows/update_deps.yaml @@ -37,10 +37,10 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - - name: Setup Rust Toolchain - uses: dtolnay/rust-toolchain@master + - name: Install Rust + uses: ./.github/actions/setup-rust with: - toolchain: ${{ env.RUST_VERSION }} + toolchain: stable - name: Update Cargo Dependencies run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log @@ -95,7 +95,7 @@ jobs: git commit --no-verify --file=commit.txt - name: Create or Update Pull Request - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v6 with: commit-message: ${{ env.COMMIT_MESSAGE }} title: ${{ env.PR_TITLE }} diff --git a/.gitignore b/.gitignore index 3d14346..16b395a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ lcov.info node_modules/ pnpm-lock.yaml ./package.json +tmp diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ec6276..a697b51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,38 +1,18 @@ -exclude: | - (?x)^( - tests/.*| - CHANGELOG.md - )$ +default_install_hook_types: [pre-commit, pre-push, commit-msg] +default_stages: [pre-commit] repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: trailing-whitespace - stages: [commit] - id: end-of-file-fixer - stages: [commit] - - id: check-yaml - stages: [commit] - id: check-json - stages: [commit] - id: check-toml - stages: [commit] - id: check-added-large-files - stages: [commit] - id: check-merge-conflict - stages: [commit] - id: check-case-conflict - stages: [commit] - id: detect-private-key - stages: [commit] - - - repo: https://github.com/commitizen-tools/commitizen - rev: v3.27.0 - hooks: - - id: commitizen - - id: commitizen-branch - stages: [push] - repo: https://github.com/lyz-code/yamlfix/ rev: 1.16.0 @@ -40,16 +20,44 @@ repos: - id: yamlfix args: [-c, .yamlfix.toml] + - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook + rev: v9.16.0 + hooks: + - id: commitlint + stages: [commit-msg] + additional_dependencies: ['@commitlint/config-conventional'] + - repo: https://github.com/crate-ci/typos rev: v1.21.0 hooks: - id: typos - - repo: https://github.com/doublify/pre-commit-rust - rev: v1.0 + - repo: local hooks: - - id: fmt - args: [--, --check, --color, always] - id: clippy - args: [--all-targets, --all-features, --, -D, warnings] - stages: [manual] + name: clippy + description: Lint rust sources + entry: make lint-clippy + language: system + types: [rust] + pass_filenames: false + - id: fmt-markdown + name: lint-markdown + description: Lint config files using Prettier + entry: npx prettier --write --no-error-on-unmatched-pattern + language: system + types: [markdown] + - id: fmt-rust + name: fmt-rust + description: Format files with cargo fmt. + entry: make fmt-rust + language: system + types: [rust] + pass_filenames: false + - id: fmt-cargo + name: fmt-cargo + description: Lint Cargo.toml files using cargo-sort + entry: make fmt-cargo + language: system + types: [toml] + pass_filenames: false diff --git a/.rustfmt.toml b/.rustfmt.toml index cbce36b..b45980f 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,6 +1,9 @@ -max_width = 100 -edition = "2021" +max_width = 90 +normalize_comments = true +imports_layout = "Vertical" +imports_granularity = "Crate" +trailing_semicolon = false use_try_shorthand = true +edition = "2021" use_field_init_shorthand = true -hard_tabs = true tab_spaces = 4 diff --git a/.yamlfix.toml b/.yamlfix.toml index 2924781..4d509e0 100644 --- a/.yamlfix.toml +++ b/.yamlfix.toml @@ -1,4 +1,4 @@ explicit_start = false section_whitelines = 1 whitelines = 1 -line_length = 100 +line_length = 200 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5eaa29e..5569d55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,9 +9,10 @@ Most projects under the umbrella of data systems are written in Rust, so we prefer using Rust tooling and community standards. Ensure you have the following tools installed: -- [Rust](https://www.rust-lang.org/tools/install) -- [Make](https://www.gnu.org/software/make/) -- [Pre-commit](https://pre-commit.com/#install) +- [Rust](https://www.rust-lang.org/tools/install) +- [Make](https://www.gnu.org/software/make/) +- [Pre-commit](https://pre-commit.com/#install) +- [NodeJS](https://nodejs.org/en/download/) ## 📟 Setting up @@ -32,71 +33,66 @@ make setup You can check the [./scripts/setup.sh](./scripts/setup.sh) file to see what is being installed on your machine. -## 📝 Code conventions +## 📇 Code conventions We enforce some conventions to ensure code quality, sustainability, and maintainability. The following tools help us with that: -- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) - - Ensures that commit messages are clear and understandable. -- [Pre-commit](https://pre-commit.com/) - Ensures that the code is formatted - and linted before being committed. -- [Commitizen](https://commitizen-tools.github.io/commitizen/) - Standardizes - commit messages using the Conventional Commits specification. +- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) - + Ensures that commit messages are clear and understandable. +- [Pre-commit](https://pre-commit.com/) - Ensures that the code is formatted + and linted before being committed. +- [Commitlint](https://commitlint.js.org/) - Lints commit messages to ensure + they follow the Conventional Commits specification. -### Writing your commits +### 📝 Writing your Commits & Pull Requests When creating a commit, please follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. Use `category(scope or module): message` in your commit message with one of the following categories: -- `feat / feature`: All changes that introduce completely new code or new - features. -- `fix`: Changes that fix a bug (ideally referencing an issue if present). -- `refactor`: Any code-related change that is not a fix or a feature. -- `docs`: Changes to existing documentation or creation of new documentation - (e.g., README, usage docs). -- `build`: Changes regarding the build of the software, dependencies, or the - addition of new dependencies. -- `test`: Changes regarding tests (adding new tests or changing existing - ones). -- `ci`: Changes regarding the configuration of continuous integration (e.g., - GitHub Actions, CI systems). -- `chore`: Changes to the repository that do not fit into any of the above - categories. - -### Using Commitizen - -Commitizen helps you create commit messages that follow the Conventional -Commits specification. To use Commitizen, refer to the [Commitizen installation -guide](https://commitizen-tools.github.io/commitizen/). - -Once installed, create your commit using the following command: - -```sh -cz commit -``` - -Commitizen will guide you through the process of creating a standardized -commit message. +- `arch`: Changes that affect the architecture of the software. +- `build`: Changes regarding the build of the software, dependencies, or the + addition of new dependencies. +- `ci`: Changes regarding the configuration of continuous integration (e.g., + GitHub Actions, CI systems). +- `docs`: Changes to existing documentation or creation of new documentation + (e.g., README, usage docs). +- `feat`: All changes that introduce completely new code or new + features. +- `fix`: Changes that fix a bug (ideally referencing an issue if present). +- `perf`: Changes that improve the performance of the software. +- `refactor`: Any code-related change that is not a fix or a feature. +- `test`: Changes regarding tests (adding new tests or changing existing + ones). + +This is a general rule used for commits. When you are creating a PR, ensure +that the title follows the same pattern, but in terms of PR, the scope is a +mandatory field. That's the scopes allowed at the moment: + +- `repo`: Changes that affect a global scope of the repository. +- `release`: Scoped used for automatic release pull requests. +- `data-streams`: Changes that affect the data-streams package. +- `sdk-rust`: Changes that affect the Rust SDK package. +- `sdk-js`: Changes that affect the Typescript SDK package. ## 📜 Useful Commands To make your life easier, here are some commands to run common tasks in this project: -| Command | Description | -| ---------------- | ------------------------------------------------------ | -| `make build` | Build the project | -| `make check` | Run cargo check | -| `make dev-watch` | Run the project in development mode with auto-reload | -| `make dev` | Run the project in development mode | -| `make fmt` | Format the code | -| `make install` | Install the project | -| `make lint` | Format and lint the code | -| `make run` | Run the project in release mode | -| `make setup` | Install all the tools needed | +| Command | Description | +| ---------------- | ----------------------------------------------------- | +| `make build` | Build the project with default settings | +| `make clean` | Clean the build artifacts and release directory | +| `make dev-watch` | Run the project in development mode with auto-reload | +| `make dev` | Run the project in development mode | +| `make fmt` | Format the code and Markdown files | +| `make install` | Fetch the project dependencies using `cargo fetch` | +| `make lint` | Perform linting checks on the code and Markdown files | +| `make run` | Run the built executable using `cargo run --release` | +| `make setup` | Run the setup script located at `./scripts/setup.sh` | ## 📬 Open a Pull Request diff --git a/Cargo.lock b/Cargo.lock index e07a612..60640ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -753,9 +753,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" dependencies = [ "jobserver", "libc", @@ -855,23 +855,23 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", - "clap_derive 4.5.4", + "clap_derive 4.5.5", ] [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.0", + "clap_lex 0.7.1", "strsim 0.11.1", ] @@ -890,9 +890,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -911,9 +911,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "cobs" @@ -2019,7 +2019,7 @@ dependencies = [ "async-graphql", "async-trait", "axum", - "clap 4.5.4", + "clap 4.5.7", "derive_more", "enum-iterator", "fuel-core-chain-config", @@ -2068,7 +2068,7 @@ checksum = "f92303bae6c08dd0680b3f879c8624163d291b12b50adcc9ce2caaece5657f0d" dependencies = [ "anyhow", "async-trait", - "clap 4.5.4", + "clap 4.5.7", "const_format", "dirs", "dotenvy", @@ -2179,11 +2179,11 @@ dependencies = [ [[package]] name = "fuel-core-nats" -version = "0.26.0" +version = "0.0.1" dependencies = [ "anyhow", "async-nats", - "clap 4.5.4", + "clap 4.5.7", "fuel-core", "fuel-core-bin", "fuel-core-services", @@ -2453,6 +2453,10 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "fuel-nats" +version = "0.0.1" + [[package]] name = "fuel-storage" version = "0.50.0" @@ -3015,9 +3019,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "9f3935c160d00ac752e09787e6e6bfc26494c2183cc922f1bc678a60d4733bc2" [[package]] name = "httpdate" @@ -3092,6 +3096,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -3110,12 +3232,14 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -3917,7 +4041,7 @@ dependencies = [ "thiserror", "tracing", "yamux 0.12.1", - "yamux 0.13.2", + "yamux 0.13.3", ] [[package]] @@ -4016,6 +4140,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -4938,7 +5068,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "unarray", ] @@ -5034,9 +5164,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904e3d3ba178131798c6d9375db2b13b34337d489b089fc5ba0825a2ff1bee73" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" dependencies = [ "bytes", "futures-io", @@ -5052,9 +5182,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e974563a4b1c2206bbc61191ca4da9c22e4308b4c455e8906751cc7828393f08" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" dependencies = [ "bytes", "rand", @@ -5069,9 +5199,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4f0def2590301f4f667db5a77f9694fb004f82796dc1a8b1508fafa3d0e8b72" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" dependencies = [ "libc", "once_cell", @@ -5201,14 +5331,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -5222,13 +5352,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -5239,9 +5369,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" @@ -6107,9 +6237,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "symbolic-common" -version = "12.9.1" +version = "12.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d2aef0f60f62e38c472334148758afbd570ed78d20be622692e5ebfec3734f" +checksum = "71297dc3e250f7dbdf8adb99e235da783d690f5819fdeb4cce39d9cfb0aca9f1" dependencies = [ "debugid", "memmap2", @@ -6119,9 +6249,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.9.1" +version = "12.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1719d1292eac816cdd3fdad12b22315624b7ce6a7bacb267a3a27fccfd286b48" +checksum = "424fa2c9bf2c862891b9cfd354a752751a6730fd838a4691e7f6c2c7957b9daf" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -6326,6 +6456,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -6504,7 +6644,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.11", + "winnow 0.6.13", ] [[package]] @@ -6783,12 +6923,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.0", "percent-encoding", ] @@ -6798,11 +6938,23 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -7149,6 +7301,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.25.4" @@ -7370,9 +7532,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c52728401e1dc672a56e81e593e912aa54c78f40246869f78359a2bf24d29d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -7387,6 +7549,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -7476,18 +7650,18 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f97202f6b125031b95d83e01dc57292b529384f80bfae4677e4bbc10178cf72" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" dependencies = [ "futures", - "instant", "log", "nohash-hasher", "parking_lot", "pin-project", "rand", "static_assertions", + "web-time", ] [[package]] @@ -7499,6 +7673,30 @@ dependencies = [ "time", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.34" @@ -7519,6 +7717,27 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.1" @@ -7539,6 +7758,28 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "zerovec" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 9e9dad1..2c0de51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,7 @@ +[package] +name = "fuel-nats" +version = "0.0.1" + [workspace] members = ["crates/fuel-core-nats"] resolver = "2" @@ -8,7 +12,7 @@ keywords = ["data-stream", "blockchain", "cryptocurrencies"] edition = "2021" homepage = "https://fuel.network/" license = "Apache-2.0" -repository = "https://github.com/FuelLabs/data-systems" +repository = "https://github.com/fuellabs/data-systems" version = "0.0.1" [workspace.dependencies] @@ -16,7 +20,12 @@ anyhow = "1.0" clap = { version = "4.5", features = ["derive"] } futures = "0.3" tokio = { version = "1.38", features = ["full"] } -fuel-core-bin = { version = "0.27", features = ["env", "p2p", "relayer", "rocksdb"] } +fuel-core-bin = { version = "0.27", features = [ + "env", + "p2p", + "relayer", + "rocksdb", +] } fuel-core = { version = "0.27", features = ["p2p", "relayer", "rocksdb"] } fuel-core-types = { version = "0.27" } fuel-core-services = "0.27" diff --git a/Makefile b/Makefile index adcf404..0fb9595 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,23 @@ -build: - cargo build --release +# ------------------------------------------------------------ +# Setup +# ------------------------------------------------------------ -check: - cargo check --all-targets --all-features +TARGET ?= aarch64-apple-darwin +PACKAGE ?= fuel-core-nats + +.PHONY: all build run clean lint fmt help test doc + +all: build + +install: + cargo fetch + +setup: + ./scripts/setup.sh + +# ------------------------------------------------------------ +# Development +# ------------------------------------------------------------ dev: cargo run @@ -10,18 +25,84 @@ dev: dev-watch: cargo watch -- cargo run -fmt: - cargo fmt -- --check --color always - -install: - cargo fetch +# ------------------------------------------------------------ +# Build & Release +# ------------------------------------------------------------ -lint: - pre-commit run --all-files - pre-commit run --hook-stage manual clippy --all-files +build: install + cargo build --release --target "$(TARGET)" --package "$(PACKAGE)" run: cargo run --release -setup: - ./scripts/install.sh +clean: + cargo clean + rm -rf release + +# ------------------------------------------------------------ +# Format +# ------------------------------------------------------------ + +fmt: fmt-cargo fmt-rust fmt-markdown + +fmt-cargo: + cargo sort -w + +fmt-rust: + cargo +nightly fmt -- --color always + +fmt-markdown: + npx prettier *.md **/*.md --write --no-error-on-unmatched-pattern + +# ------------------------------------------------------------ +# Validate code +# ------------------------------------------------------------ + +check: + cargo check --all-targets --all-features + +lint: check lint-cargo lint-rust lint-clippy lint-markdown + +lint-cargo: + cargo sort -w --check + +lint-rust: + cargo +nightly fmt -- --check --color always + +lint-clippy: + cargo clippy --workspace -- -D warnings + +lint-markdown: + npx prettier *.md **/*.md --check --no-error-on-unmatched-pattern + +# ------------------------------------------------------------ +# Test +# ------------------------------------------------------------ + +test: + cargo test --all + +# ------------------------------------------------------------ +# Documentation +# ------------------------------------------------------------ + +doc: + cargo doc --no-deps + +# ------------------------------------------------------------ +# Help +# ------------------------------------------------------------ + +help: + @echo "Available commands:" + @echo " install - Install project dependencies" + @echo " setup - Run the setup script" + @echo " dev - Run the project in development mode" + @echo " dev-watch - Run the project in development mode with auto-reload" + @echo " build - Build the project" + @echo " run - Run the project in release mode" + @echo " clean - Clean the build artifacts and release directory" + @echo " fmt - Format the code and Markdown files" + @echo " lint - Perform linting checks on the code and Markdown files" + @echo " test - Run tests" + @echo " doc - Generate documentation" diff --git a/crates/fuel-core-nats/Cargo.toml b/crates/fuel-core-nats/Cargo.toml index a26bd4b..65a44ae 100644 --- a/crates/fuel-core-nats/Cargo.toml +++ b/crates/fuel-core-nats/Cargo.toml @@ -1,17 +1,23 @@ [package] name = "fuel-core-nats" -version = "0.26.0" -edition = "2021" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +keywords = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +description = "Fuel library to handle data streams using Nats" [dependencies] -fuel-core-bin = { workspace = true } +anyhow = "1.0.86" +async-nats = "0.35.1" +clap = "4.5.4" fuel-core = { workspace = true } -fuel-core-types = { workspace = true } +fuel-core-bin = { workspace = true } fuel-core-services = { workspace = true } +fuel-core-types = { workspace = true } +futures-util = "0.3.30" serde_json = "1.0.117" tokio = "1.37.0" tracing = "0.1.40" -clap = "4.5.4" -anyhow = "1.0.86" -async-nats = "0.35.1" -futures-util = "0.3.30" diff --git a/crates/fuel-core-nats/src/lib.rs b/crates/fuel-core-nats/src/lib.rs index 36085a9..57c4616 100644 --- a/crates/fuel-core-nats/src/lib.rs +++ b/crates/fuel-core-nats/src/lib.rs @@ -1,10 +1,16 @@ -use anyhow::{bail, Context}; +use anyhow::{ + bail, + Context, +}; use futures_util::stream::TryStreamExt; use tracing::info; -use fuel_core_types::fuel_tx::field::Inputs; -use fuel_core_types::services::{ - block_importer::ImportResult, executor::TransactionExecutionResult, +use fuel_core_types::{ + fuel_tx::field::Inputs, + services::{ + block_importer::ImportResult, + executor::TransactionExecutionResult, + }, }; const NUM_TOPICS: usize = 3; @@ -19,195 +25,202 @@ const NUM_TOPICS: usize = 3; /// owners.{height}.{owner_id} e.g. owners.*.0xab..cd /// assets.{height}.{asset_id} e.g. assets.*.0xab..cd pub async fn nats_publisher( - mut subscription: tokio::sync::broadcast::Receiver< - std::sync::Arc + Send + Sync>, - >, - nats_url: String, + mut subscription: tokio::sync::broadcast::Receiver< + std::sync::Arc + Send + Sync>, + >, + nats_url: String, ) -> anyhow::Result<()> { - // Connect to the NATS server - let client = async_nats::connect(&nats_url) - .await - .context(format!("Connecting to {nats_url}"))?; - // Create a JetStream context - let jetstream = async_nats::jetstream::new(client); - // Create a JetStream stream (if it doesn't exist) - let _stream = jetstream - .get_or_create_stream(async_nats::jetstream::stream::Config { - name: "fuel".to_string(), - subjects: vec![ - // blocks.{height} - "blocks.*".to_string(), - // receipts.{height}.{contract_id}.{kind} - // or - // receipts.{height}.{contract_id}.{topic_1} - "receipts.*.*.*".to_string(), - // receipts.{height}.{contract_id}.{topic_1}.{topic_2} - "receipts.*.*.*.*".to_string(), - // receipts.{height}.{contract_id}.{topic_1}.{topic_2}.{topic_3} - "receipts.*.*.*.*.*".to_string(), - // transactions.{height}.{index}.{kind} - "transactions.*.*.*".to_string(), - // owners.{height}.{owner_id} - "owners.*.*".to_string(), - // assets.{height}.{asset_id} - "assets.*.*.".to_string(), - ], - storage: async_nats::jetstream::stream::StorageType::File, - ..Default::default() - }) - .await?; - - // Check the last block height in the stream - let last_block_height = { - let config = async_nats::jetstream::consumer::pull::Config { - deliver_policy: async_nats::jetstream::consumer::DeliverPolicy::Last, - filter_subject: "blocks.*".to_string(), - ..Default::default() - }; - let consumer = jetstream.create_consumer_on_stream(config, "fuel").await?; - let mut batch = consumer.fetch().max_messages(1).messages().await?; - - if let Ok(Some(message)) = batch.try_next().await { - let block_height: u32 = message.subject.strip_prefix("blocks.").unwrap().parse()?; - block_height - } else { - 0 - } - }; - - info!("NATS Publisher started"); - - while let Ok(result) = subscription.recv().await { - let result = &**result; - let height = u32::from(result.sealed_block.entity.header().consensus().height); - if !(height == last_block_height + 1) { - bail!("NATS Publisher: missing blocks: stream block height={last_block_height}, chain block height={height}"); - } - let block = &result.sealed_block.entity; - - // Publish the block. - info!("NATS Publisher: Block#{height}"); - let payload = serde_json::to_string_pretty(block)?; - jetstream - .publish(format!("blocks.{height}"), payload.into()) - .await?; - - use fuel_core_types::fuel_tx::Transaction; - for (index, tx) in block.transactions().iter().enumerate() { - match tx { - Transaction::Script(s) => { - for i in s.inputs() { - if let Some(owner_id) = i.input_owner() { - let payload = serde_json::to_string_pretty(tx)?; - jetstream - .publish(format!("owners.{height}.{owner_id}"), payload.into()) - .await?; - } - use fuel_core_types::fuel_tx::AssetId; - // TODO: from chain config? - let base_asset_id = AssetId::zeroed(); - if let Some(asset_id) = i.asset_id(&base_asset_id) { - let payload = serde_json::to_string_pretty(tx)?; - jetstream - .publish(format!("assets.{height}.{asset_id}"), payload.into()) - .await?; - } - } - } - _ => (), - }; - - let tx_kind = match tx { - Transaction::Create(_) => "create", - Transaction::Mint(_) => "mint", - Transaction::Script(_) => "script", - Transaction::Upload(_) => "upload", - Transaction::Upgrade(_) => "upgrade", - }; - - // Publish the transaction. - info!("NATS Publisher: Transaction#{height}.{index}.{tx_kind}"); - let payload = serde_json::to_string_pretty(tx)?; - jetstream - .publish( - format!("transactions.{height}.{index}.{tx_kind}"), - payload.into(), - ) - .await?; - } - - for t in result.tx_status.iter() { - let receipts = match &t.result { - TransactionExecutionResult::Success { receipts, .. } => receipts, - TransactionExecutionResult::Failed { receipts, .. } => receipts, - }; - - use fuel_core_types::fuel_tx::Receipt; - for r in receipts.iter() { - let receipt_kind = match r { - Receipt::Call { .. } => "call", - Receipt::Return { .. } => "return", - Receipt::ReturnData { .. } => "return_data", - Receipt::Panic { .. } => "panic", - Receipt::Revert { .. } => "revert", - Receipt::Log { .. } => "log", - Receipt::LogData { .. } => "log_data", - Receipt::Transfer { .. } => "transfer", - Receipt::TransferOut { .. } => "transfer_out", - Receipt::ScriptResult { .. } => "script_result", - Receipt::MessageOut { .. } => "message_out", - Receipt::Mint { .. } => "mint", - Receipt::Burn { .. } => "burn", - }; - - let contract_id = r.contract_id().map(|x| x.to_string()).unwrap_or( - "0000000000000000000000000000000000000000000000000000000000000000".to_string(), - ); - - // Publish the receipt. - info!("NATS Publisher: Receipt#{height}.{contract_id}.{receipt_kind}"); - let payload = serde_json::to_string_pretty(r)?; - let subject = format!("receipts.{height}.{contract_id}.{receipt_kind}"); - jetstream.publish(subject, payload.into()).await?; - - // Publish LogData topics, if any. - if let Receipt::LogData { data, .. } = r { - if let Some(data) = data { - info!("NATS Publisher: Log Data Length: {}", data.len()); - // 0x0000000012345678 - let header = vec![0, 0, 0, 0, 18, 52, 86, 120]; - if data.starts_with(&header) { - let data = &data[header.len()..]; - let mut topics = vec![]; - for i in 0..NUM_TOPICS { - let topic_bytes: Vec = data[32 * i..32 * (i + 1)] - .iter() - .cloned() - .take_while(|x| *x > 0) - .collect(); - let topic = String::from_utf8_lossy(&topic_bytes).into_owned(); - if !topic.is_empty() { - topics.push(topic); - } - } - let topics = topics.join("."); - // TODO: JSON payload to match other topics? {"data": payload} - let payload = data[NUM_TOPICS * 32..].to_owned(); - - // Publish - info!("NATS Publisher: Receipt#{height}.{contract_id}.{topics}"); - jetstream - .publish( - format!("receipts.{height}.{contract_id}.{topics}"), - payload.into(), - ) - .await?; - } - } - } - } - } - } - - Ok(()) + // Connect to the NATS server + let client = async_nats::connect(&nats_url) + .await + .context(format!("Connecting to {nats_url}"))?; + // Create a JetStream context + let jetstream = async_nats::jetstream::new(client); + // Create a JetStream stream (if it doesn't exist) + let _stream = jetstream + .get_or_create_stream(async_nats::jetstream::stream::Config { + name: "fuel".to_string(), + subjects: vec![ + // blocks.{height} + "blocks.*".to_string(), + // receipts.{height}.{contract_id}.{kind} + // or + // receipts.{height}.{contract_id}.{topic_1} + "receipts.*.*.*".to_string(), + // receipts.{height}.{contract_id}.{topic_1}.{topic_2} + "receipts.*.*.*.*".to_string(), + // receipts.{height}.{contract_id}.{topic_1}.{topic_2}.{topic_3} + "receipts.*.*.*.*.*".to_string(), + // transactions.{height}.{index}.{kind} + "transactions.*.*.*".to_string(), + // owners.{height}.{owner_id} + "owners.*.*".to_string(), + // assets.{height}.{asset_id} + "assets.*.*.".to_string(), + ], + storage: async_nats::jetstream::stream::StorageType::File, + ..Default::default() + }) + .await?; + + // Check the last block height in the stream + let last_block_height = { + let config = async_nats::jetstream::consumer::pull::Config { + deliver_policy: async_nats::jetstream::consumer::DeliverPolicy::Last, + filter_subject: "blocks.*".to_string(), + ..Default::default() + }; + let consumer = jetstream.create_consumer_on_stream(config, "fuel").await?; + let mut batch = consumer.fetch().max_messages(1).messages().await?; + + if let Ok(Some(message)) = batch.try_next().await { + let block_height: u32 = + message.subject.strip_prefix("blocks.").unwrap().parse()?; + block_height + } else { + 0 + } + }; + + info!("NATS Publisher started"); + + while let Ok(result) = subscription.recv().await { + let result = &**result; + let height = u32::from(result.sealed_block.entity.header().consensus().height); + if height != last_block_height + 1 { + bail!("NATS Publisher: missing blocks: stream block height={last_block_height}, chain block height={height}"); + } + let block = &result.sealed_block.entity; + + // Publish the block. + info!("NATS Publisher: Block#{height}"); + let payload = serde_json::to_string_pretty(block)?; + jetstream + .publish(format!("blocks.{height}"), payload.into()) + .await?; + + use fuel_core_types::fuel_tx::Transaction; + for (index, tx) in block.transactions().iter().enumerate() { + if let Transaction::Script(s) = tx { + for i in s.inputs() { + if let Some(owner_id) = i.input_owner() { + let payload = serde_json::to_string_pretty(tx)?; + jetstream + .publish( + format!("owners.{height}.{owner_id}"), + payload.into(), + ) + .await?; + } + use fuel_core_types::fuel_tx::AssetId; + // TODO: from chain config? + let base_asset_id = AssetId::zeroed(); + if let Some(asset_id) = i.asset_id(&base_asset_id) { + let payload = serde_json::to_string_pretty(tx)?; + jetstream + .publish( + format!("assets.{height}.{asset_id}"), + payload.into(), + ) + .await?; + } + } + }; + + let tx_kind = match tx { + Transaction::Create(_) => "create", + Transaction::Mint(_) => "mint", + Transaction::Script(_) => "script", + Transaction::Upload(_) => "upload", + Transaction::Upgrade(_) => "upgrade", + }; + + // Publish the transaction. + info!("NATS Publisher: Transaction#{height}.{index}.{tx_kind}"); + let payload = serde_json::to_string_pretty(tx)?; + jetstream + .publish( + format!("transactions.{height}.{index}.{tx_kind}"), + payload.into(), + ) + .await?; + } + + for t in result.tx_status.iter() { + let receipts = match &t.result { + TransactionExecutionResult::Success { receipts, .. } => receipts, + TransactionExecutionResult::Failed { receipts, .. } => receipts, + }; + + use fuel_core_types::fuel_tx::Receipt; + for r in receipts.iter() { + let receipt_kind = match r { + Receipt::Call { .. } => "call", + Receipt::Return { .. } => "return", + Receipt::ReturnData { .. } => "return_data", + Receipt::Panic { .. } => "panic", + Receipt::Revert { .. } => "revert", + Receipt::Log { .. } => "log", + Receipt::LogData { .. } => "log_data", + Receipt::Transfer { .. } => "transfer", + Receipt::TransferOut { .. } => "transfer_out", + Receipt::ScriptResult { .. } => "script_result", + Receipt::MessageOut { .. } => "message_out", + Receipt::Mint { .. } => "mint", + Receipt::Burn { .. } => "burn", + }; + + let contract_id = r.contract_id().map(|x| x.to_string()).unwrap_or( + "0000000000000000000000000000000000000000000000000000000000000000" + .to_string(), + ); + + // Publish the receipt. + info!("NATS Publisher: Receipt#{height}.{contract_id}.{receipt_kind}"); + let payload = serde_json::to_string_pretty(r)?; + let subject = format!("receipts.{height}.{contract_id}.{receipt_kind}"); + jetstream.publish(subject, payload.into()).await?; + + // Publish LogData topics, if any. + if let Receipt::LogData { + data: Some(data), .. + } = r + { + info!("NATS Publisher: Log Data Length: {}", data.len()); + // 0x0000000012345678 + let header = vec![0, 0, 0, 0, 18, 52, 86, 120]; + if data.starts_with(&header) { + let data = &data[header.len()..]; + let mut topics = vec![]; + for i in 0..NUM_TOPICS { + let topic_bytes: Vec = data[32 * i..32 * (i + 1)] + .iter() + .cloned() + .take_while(|x| *x > 0) + .collect(); + let topic = + String::from_utf8_lossy(&topic_bytes).into_owned(); + if !topic.is_empty() { + topics.push(topic); + } + } + let topics = topics.join("."); + // TODO: JSON payload to match other topics? {"data": payload} + let payload = data[NUM_TOPICS * 32..].to_owned(); + + // Publish + info!("NATS Publisher: Receipt#{height}.{contract_id}.{topics}"); + jetstream + .publish( + format!("receipts.{height}.{contract_id}.{topics}"), + payload.into(), + ) + .await?; + } + } + } + } + } + + Ok(()) } diff --git a/crates/fuel-core-nats/src/main.rs b/crates/fuel-core-nats/src/main.rs index 9d934c0..9fe264f 100644 --- a/crates/fuel-core-nats/src/main.rs +++ b/crates/fuel-core-nats/src/main.rs @@ -5,28 +5,28 @@ use fuel_core_services::Service; #[derive(Parser)] pub struct Cli { - #[arg( - long, - value_name = "URL", - env = "NATS_URL", - default_value = "localhost:4222" - )] - nats_url: String, - #[command(flatten)] - fuel_core_config: run::Command, + #[arg( + long, + value_name = "URL", + env = "NATS_URL", + default_value = "localhost:4222" + )] + nats_url: String, + #[command(flatten)] + fuel_core_config: run::Command, } #[tokio::main] async fn main() -> anyhow::Result<()> { - fuel_core_bin::cli::init_logging(); + fuel_core_bin::cli::init_logging(); - let cli = Cli::parse(); - let service = run::get_service(cli.fuel_core_config)?; - service.start()?; + let cli = Cli::parse(); + let service = run::get_service(cli.fuel_core_config)?; + service.start()?; - let subscription = service.shared.block_importer.block_importer.subscribe(); + let subscription = service.shared.block_importer.block_importer.subscribe(); - fuel_core_nats::nats_publisher(subscription, cli.nats_url).await?; + fuel_core_nats::nats_publisher(subscription, cli.nats_url).await?; - Ok(()) + Ok(()) } diff --git a/knope.toml b/knope.toml new file mode 100644 index 0000000..3c062dd --- /dev/null +++ b/knope.toml @@ -0,0 +1,87 @@ +[package] +versioned_files = ["Cargo.toml"] +changelog = "CHANGELOG.md" + +[[package.assets]] +path = "artifacts/fuel-core-nats-x86_64-unknown-linux-gnu.tgz" + +# ------------------------------------------------------------ +# Workflow to get the current version +# ------------------------------------------------------------ +[[workflows]] +name = "get-version" +help_text = "Get the current version of the project" + +[[workflows.steps]] +type = "Command" +command = "echo \"$VERSION\"" +variables = { "$VERSION" = "Version" } + +# ------------------------------------------------------------ +# Workflow to create a new changeset +# ------------------------------------------------------------ +[[workflows]] +name = "changeset" + +[[workflows.steps]] +type = "CreateChangeFile" + +# ------------------------------------------------------------ +# Workflow to create a new release +# ------------------------------------------------------------ +[[workflows]] +name = "prepare-release" + +[[workflows.steps]] +type = "PrepareRelease" + +[[workflows.steps]] +type = "Command" +command = "git switch -c $RELEASE_BRANCH" +shell = true + +[[workflows.steps]] +type = "Command" +command = "./scripts/bump-version.sh $VERSION && git add ." +variables = { "$VERSION" = "Version" } +shell = true + +[[workflows.steps]] +type = "Command" +command = "git commit -m \"ci(release): preparing $VERSION\"" +variables = { "$VERSION" = "Version" } + +[[workflows.steps]] +type = "Command" +command = "git push --force --set-upstream origin $RELEASE_BRANCH" +shell = true + +[[workflows.steps]] +type = "CreatePullRequest" +base = "main" +variables = { "$VERSION" = "Version" } + +[workflows.steps.title] +template = "ci(release): preparing v$VERSION" +variables = { "$VERSION" = "Version" } + +[workflows.steps.body] +template = "v$VERSION" +variables = { "$VERSION" = "Version" } + +# ------------------------------------------------------------ +# Workflow to release a new version +# ------------------------------------------------------------ +[[workflows]] +name = "release" + +[[workflows.steps]] +type = "Release" +variables = { "$VERSION" = "Version" } + +# ------------------------------------------------------------ +# GitHub configuration +# ------------------------------------------------------------ +[github] +owner = "fuellabs" +repo = "data-systems" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ca5876e..b1fc4c1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "1.78.0" -components = ["rustfmt", "clippy"] +components = ["rustfmt", "clippy", "rust-analyzer"] targets = ["wasm32-unknown-unknown"] diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh new file mode 100755 index 0000000..86bf2c8 --- /dev/null +++ b/scripts/bump-version.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cargo set-version --workspace "$1" +cargo update --workspace +make fmt diff --git a/scripts/setup.sh b/scripts/setup.sh index 91742e8..331a008 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -15,5 +15,10 @@ check_command pre-commit # Install pre-commit hooks pre-commit install -# Install cargo watch -cargo install cargo-watch + +# Install nightly toolchain +rustup toolchain install nightly -c rustfmt + +# Install cargo global crates +cargo install cargo-binstall +cargo binstall --no-confirm cargo-watch knope cargo-sort diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}