diff --git a/.editorconfig b/.editorconfig index 72e61c1b..12808c50 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,3 +19,7 @@ trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 + +[{Makefile,**.mk}] +# Use tabs for indentation (Makefiles require tabs) +indent_style = tab diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8fd6c99a..fd142d16 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,13 +1,7 @@ name: CI on: - workflow_dispatch: pull_request: - types: - - opened - - synchronize - - edited - - reopened push: branches: - main @@ -187,24 +181,24 @@ jobs: - name: Install dependencies run: cargo fetch - test-helm: - needs: install-deps - name: Test Helm - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Helm - uses: azure/setup-helm@v4 - with: - version: "latest" - - - name: Install helm unittest plugin - run: | - helm plugin install https://github.com/helm-unittest/helm-unittest.git - - - name: Run Helm unit tests - run: | - make helm-test + # test-helm: + # needs: install-deps + # name: Test Helm + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - name: Set up Helm + # uses: azure/setup-helm@v4 + # with: + # version: "latest" + + # - name: Install helm unittest plugin + # run: | + # helm plugin install https://github.com/helm-unittest/helm-unittest.git + + # - name: Run Helm unit tests + # run: | + # make helm-test test: needs: install-deps @@ -364,7 +358,7 @@ jobs: github.event_name == 'workflow_dispatch' needs: - test - - test-helm + # - test-helm - build runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/docker_publish.yaml b/.github/workflows/docker_publish.yaml index 47ba1bd8..ed2d0ba1 100644 --- a/.github/workflows/docker_publish.yaml +++ b/.github/workflows/docker_publish.yaml @@ -20,11 +20,15 @@ concurrency: jobs: build-and-publish-image: runs-on: ubuntu-latest - if: | - (github.event_name == 'release' && github.event.action == 'published') || - github.ref == 'refs/heads/main' || - github.event_name == 'workflow_dispatch' || - github.event_name == 'pull_request' + strategy: + matrix: + package: + - name: fuel-streams-publisher + image: cluster/docker/fuel-core.Dockerfile + - name: sv-emitter + image: cluster/docker/fuel-core.Dockerfile + - name: sv-consumer + image: cluster/docker/sv-consumer.Dockerfile steps: - uses: actions/checkout@v4 @@ -38,5 +42,7 @@ jobs: with: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - image: ghcr.io/fuellabs/fuel-streams-publisher - dockerfile: cluster/docker/fuel-streams-publisher.Dockerfile + image: ghcr.io/fuellabs/${{ matrix.package.name }} + dockerfile: ${{ matrix.package.image }} + build-args: |- + PACKAGE_NAME=${{ matrix.package.name }} diff --git a/.gitignore b/.gitignore index c3ed4a0a..5e8b6a25 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ coverage/ docs/ **/**/charts/**.tgz values-publisher-secrets.yaml +.vscode/launch.json diff --git a/.prettierignore b/.prettierignore index 8b7b5b96..0063613c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,2 @@ -helm -cluster +cluster/charts pnpm-lock.yaml diff --git a/.rustfmt.toml b/.rustfmt.toml index aaebb675..2d0df4eb 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -10,3 +10,8 @@ use_field_init_shorthand = true reorder_imports = true reorder_modules = true tab_spaces = 4 +# Add these new settings +format_macro_matchers = true +format_macro_bodies = true +# If you want macros to ignore the max_width setting +overflow_delimited_expr = true diff --git a/Cargo.lock b/Cargo.lock index e1cc9d60..890561a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2825,22 +2825,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "eventsource-client" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ddc25e1ad2cc0106d5e2d967397b4fb2068a66677ee9b0eea4600e5cfe8fb4" -dependencies = [ - "futures", - "hyper 0.14.31", - "hyper-rustls 0.24.2", - "hyper-timeout 0.4.1", - "log", - "pin-project", - "rand", - "tokio", -] - [[package]] name = "eyre" version = "0.6.12" @@ -3084,7 +3068,6 @@ dependencies = [ "clap 4.5.23", "const_format", "dirs", - "dotenvy", "fuel-core", "fuel-core-chain-config", "fuel-core-compression", @@ -3129,14 +3112,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a10ccde16fd926137070d3baa77a1096c2ff6cdca26d14177139c16e59e697d" dependencies = [ "anyhow", - "base64 0.22.1", "cynic", "derive_more 0.99.18", - "eventsource-client", "fuel-core-types 0.40.2", - "futures", "hex", - "hyper-rustls 0.24.2", "itertools 0.12.1", "reqwest 0.11.27", "schemafy_lib", @@ -3687,14 +3666,19 @@ dependencies = [ name = "fuel-streams-core" version = "0.0.13" dependencies = [ + "anyhow", "async-nats", "async-trait", "chrono", "clap 4.5.23", "displaydoc", "dotenvy", + "fuel-core", + "fuel-core-bin", "fuel-core-client", "fuel-core-importer", + "fuel-core-services", + "fuel-core-storage", "fuel-core-types 0.40.2", "fuel-data-parser", "fuel-streams-macros", @@ -3720,6 +3704,25 @@ dependencies = [ "tokio", ] +[[package]] +name = "fuel-streams-executors" +version = "0.0.13" +dependencies = [ + "anyhow", + "async-nats", + "fuel-core", + "fuel-streams-core", + "futures", + "num_cpus", + "rayon", + "serde", + "serde_json", + "sha2 0.10.8", + "thiserror 2.0.4", + "tokio", + "tracing", +] + [[package]] name = "fuel-streams-macros" version = "0.0.13" @@ -3746,26 +3749,20 @@ dependencies = [ "elasticsearch", "fuel-core", "fuel-core-bin", - "fuel-core-importer", "fuel-core-services", - "fuel-core-storage", - "fuel-core-types 0.40.2", - "fuel-streams", "fuel-streams-core", + "fuel-streams-executors", "futures", "mockall 0.13.1", "mockall_double", - "num_cpus", "openssl", "parking_lot", "prometheus", "rand", - "rayon", "rust_decimal", "serde", "serde_json", "serde_prometheus", - "sha2 0.10.8", "sysinfo", "thiserror 2.0.4", "tokio", @@ -4573,12 +4570,9 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.31", - "log", "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", - "webpki-roots 0.25.4", ] [[package]] @@ -6424,6 +6418,15 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -8727,6 +8730,47 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "sv-consumer" +version = "0.0.13" +dependencies = [ + "anyhow", + "async-nats", + "clap 4.5.23", + "fuel-core", + "fuel-streams-core", + "fuel-streams-executors", + "futures", + "openssl", + "serde_json", + "sv-emitter", + "thiserror 2.0.4", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sv-emitter" +version = "0.0.13" +dependencies = [ + "anyhow", + "async-nats", + "clap 4.5.23", + "fuel-core", + "fuel-core-bin", + "fuel-core-types 0.40.2", + "fuel-streams-core", + "fuel-streams-executors", + "futures", + "openssl", + "thiserror 2.0.4", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "symbolic-common" version = "12.12.3" @@ -9125,7 +9169,9 @@ checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -9602,6 +9648,7 @@ dependencies = [ "sharded-slab", "smallvec", "thread_local", + "time", "tracing", "tracing-core", "tracing-log", diff --git a/Cargo.toml b/Cargo.toml index f5b1c85b..9e36651f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,21 +33,31 @@ clap = { version = "4.5", features = ["derive", "env"] } dotenvy = "0.15" displaydoc = "0.2" futures = "0.3" -fuel-core-bin = { version = "0.40.2", features = ["p2p", "relayer", "rocksdb"] } -fuel-core = { version = "0.40.2", features = ["p2p", "relayer", "rocksdb"] } -fuel-core-client = { version = "0.40.2" } +fuel-core-bin = { version = "0.40.2", default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", +] } +fuel-core = { version = "0.40.2", default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", +] } +fuel-core-client = { version = "0.40.2", default-features = false, features = ["std"] } fuel-core-importer = { version = "0.40.2" } fuel-core-storage = { version = "0.40.2" } -fuel-core-types = { version = "0.40.2", features = ["test-helpers", "serde"] } -fuel-core-services = { version = "0.40.2" } +fuel-core-types = { version = "0.40.2", default-features = false, features = ["std", "serde"] } +fuel-core-services = { version = "0.40.2", default-features = false, features = ["test-helpers"] } futures-util = "0.3" itertools = "0.13" mockall = "0.13" mockall_double = "0.3.1" hex = "0.4" pretty_assertions = "1.4" +num_cpus = "1.16" rand = "0.8" serde = { version = "1.0", features = ["derive"] } +rayon = "1.10.0" serde_json = "1.0" sha2 = "0.10" strum = "0.26" @@ -65,6 +75,9 @@ fuel-streams-core = { version = "0.0.13", path = "crates/fuel-streams-core" } fuel-streams-publisher = { version = "0.0.13", path = "crates/fuel-streams-publisher" } fuel-streams-macros = { version = "0.0.13", path = "crates/fuel-streams-macros" } subject-derive = { version = "0.0.13", path = "crates/fuel-streams-macros/subject-derive" } +fuel-streams-executors = { version = "0.0.13", path = "crates/fuel-streams-executors" } +sv-emitter = { version = "0.0.13", path = "crates/sv-emitter" } +sv-consumer = { version = "0.0.13", path = "crates/sv-consumer" } # Workspace projects [workspace.metadata.cargo-machete] diff --git a/Makefile b/Makefile index 937e3fb6..51aa1ac1 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ RUST_VERSION := 1.81.0 clean clean-build cleanup-artifacts test-watch test bench helm-test \ fmt fmt-cargo fmt-rust fmt-prettier fmt-markdown lint lint-cargo \ lint-rust lint-clippy lint-prettier lint-markdown lint-machete \ - audit audit-fix-test audit-fix load-test run-publisher \ + audit audit-fix-test audit-fix load-test run-publisher run-consumer \ run-mainnet-dev run-mainnet-profiling run-testnet-dev run-testnet-profiling \ start-nats stop-nats restart-nats clean-nats minikube-setup minikube-start \ minikube-delete k8s-setup helm-setup cluster-setup pre-cluster \ @@ -112,6 +112,9 @@ clean-build: rm -rf target/ rm -rf node_modules/ +cleanup-artifacts: REPO_OWNER="fuellabs" +cleanup-artifacts: REPO_NAME="data-systems" +cleanup-artifacts: DAYS_TO_KEEP=10 cleanup-artifacts: @echo "Running artifact cleanup..." @./scripts/cleanup_artifacts.sh $(REPO_OWNER) $(REPO_NAME) $(DAYS_TO_KEEP) @@ -120,16 +123,20 @@ cleanup-artifacts: # Testing # ------------------------------------------------------------ +test-watch: PROFILE="all" test-watch: cargo watch -x "test --profile $(PROFILE)" +test: PACKAGE="all" +test: PROFILE="dev" test: + @echo "Running tests for package $(PACKAGE) with profile $(PROFILE)" @if [ "$(PACKAGE)" = "all" ] || [ -z "$(PACKAGE)" ]; then \ - cargo nextest run --cargo-profile $(PROFILE) --workspace --color always --locked --no-tests=pass && \ - cargo test --profile $(PROFILE) --doc --workspace; \ + cargo nextest run --cargo-profile $(PROFILE) --workspace --color always --no-tests=pass --all-features && \ + cargo test --profile $(PROFILE) --doc --workspace --all-features; \ else \ - cargo nextest run --cargo-profile $(PROFILE) -p $(PACKAGE) --color always --locked --no-tests=pass && \ - cargo test --profile $(PROFILE) --doc -p $(PACKAGE); \ + cargo nextest run --cargo-profile $(PROFILE) -p $(PACKAGE) --color always --no-tests=pass --all-features && \ + cargo test --profile $(PROFILE) --doc -p $(PACKAGE) --all-features; \ fi bench: @@ -201,13 +208,15 @@ load-test: # Publisher Run Commands # ------------------------------------------------------------ +run-publisher: NETWORK="testnet" +run-publisher: PACKAGE="sv-emitter" +run-publisher: MODE="dev" +run-publisher: PORT="4000" +run-publisher: TELEMETRY_PORT="8080" +run-publisher: NATS_URL="localhost:4222" +run-publisher: EXTRA_ARGS="" run-publisher: check-network - @./scripts/run_publisher.sh \ - --network $(NETWORK) \ - --mode $(MODE) \ - $(if $(PORT),--port $(PORT),) \ - $(if $(TELEMETRY_PORT),--telemetry-port $(TELEMETRY_PORT),) \ - $(if $(extra_args),--extra-args "$(extra_args)",) + @./scripts/run_publisher.sh run-mainnet-dev: $(MAKE) run-publisher NETWORK=mainnet MODE=dev @@ -221,6 +230,13 @@ run-testnet-dev: run-testnet-profiling: $(MAKE) run-publisher NETWORK=testnet MODE=profiling +run-consumer: NATS_CORE_URL="localhost:4222" +run-consumer: NATS_PUBLISHER_URL="localhost:4223" +run-consumer: + cargo run --package sv-consumer --profile dev -- \ + --nats-core-url $(NATS_CORE_URL) \ + --nats-publisher-url $(NATS_PUBLISHER_URL) + # ------------------------------------------------------------ # Docker Compose # ------------------------------------------------------------ @@ -241,6 +257,8 @@ restart-nats: clean-nats: $(MAKE) run-docker-compose COMMAND="down -v --rmi all --remove-orphans" +reset-nats: clean-nats start-nats + # ------------------------------------------------------------ # Local cluster (Minikube) # ------------------------------------------------------------ diff --git a/Tiltfile b/Tiltfile index 254afdb9..1e6622e7 100755 --- a/Tiltfile +++ b/Tiltfile @@ -10,15 +10,46 @@ version_settings(True) # Enable 'new version' banner # Load environment variables from .env file dotenv() -# Build publisher image with proper configuration for Minikube +allow_k8s_contexts('minikube') + +# Build sv-emitter +custom_build( + ref='sv-emitter:latest', + command=[ + './cluster/scripts/build_docker.sh', + '--image-name', 'sv-emitter', + '--dockerfile', './cluster/docker/fuel-core.Dockerfile', + '--build-args', '--build-arg PACKAGE_NAME=sv-emitter' + ], + deps=[ + './src', + './Cargo.toml', + './Cargo.lock', + './cluster/docker/fuel-core.Dockerfile' + ], + live_update=[ + sync('./src', '/usr/src'), + sync('./Cargo.toml', '/usr/src/Cargo.toml'), + sync('./Cargo.lock', '/usr/src/Cargo.lock'), + run('cargo build', trigger=['./src', './Cargo.toml', './Cargo.lock']) + ], + skips_local_docker=True, + ignore=['./target'] +) + +# Build sv-consumer custom_build( - ref='fuel-streams-publisher:latest', - command=['./cluster/scripts/build_publisher.sh'], + ref='sv-consumer:latest', + command=[ + './cluster/scripts/build_docker.sh', + '--image-name', 'sv-consumer', + '--dockerfile', './cluster/docker/sv-consumer.Dockerfile' + ], deps=[ './src', './Cargo.toml', './Cargo.lock', - './cluster/docker/fuel-streams-publisher.Dockerfile' + './cluster/docker/sv-consumer.Dockerfile' ], live_update=[ sync('./src', '/usr/src'), @@ -41,45 +72,30 @@ RESOURCES = { 'labels': 'publisher', 'config_mode': ['minimal', 'full'] }, + 'consumer': { + 'name': 'fuel-streams-sv-consumer', + 'ports': ['8082:8082'], + 'labels': 'consumer', + 'config_mode': ['minimal', 'full'] + }, 'nats-core': { 'name': 'fuel-streams-nats-core', - 'ports': ['4222:4222', '8222:8222'], + 'ports': ['4222:4222', '6222:6222', '7422:7422'], 'labels': 'nats', 'config_mode': ['minimal', 'full'] }, 'nats-client': { 'name': 'fuel-streams-nats-client', - 'ports': ['4223:4222', '8443:8443'], + 'ports': ['14222:4222', '17422:7422', '8443:8443'], 'labels': 'nats', 'config_mode': ['minimal', 'full'] }, 'nats-publisher': { 'name': 'fuel-streams-nats-publisher', - 'ports': ['4224:4222'], + 'ports': ['24222:4222', '27422:7422'], 'labels': 'nats', 'config_mode': ['minimal', 'full'] - }, - # 'grafana': { - # 'name': 'fuel-streams-grafana', - # 'ports': ['3000:3000'], - # 'labels': 'monitoring', - # 'config_mode': ['minimal', 'full'] - # }, - # 'prometheus-operator': { - # 'name': 'fuel-streams-prometheus-operator', - # 'labels': 'monitoring', - # 'config_mode': ['minimal', 'full'] - # }, - # 'kube-state-metrics': { - # 'name': 'fuel-streams-kube-state-metrics', - # 'labels': 'monitoring', - # 'config_mode': ['minimal', 'full'] - # }, - # 'node-exporter': { - # 'name': 'fuel-streams-prometheus-node-exporter', - # 'labels': 'monitoring', - # 'config_mode': ['minimal', 'full'] - # } + } } k8s_yaml(helm( @@ -88,7 +104,8 @@ k8s_yaml(helm( namespace='fuel-streams', values=[ 'cluster/charts/fuel-streams/values-publisher-secrets.yaml', - 'cluster/charts/fuel-streams/values.yaml' + 'cluster/charts/fuel-streams/values.yaml', + 'cluster/charts/fuel-streams/values-local.yaml' ] )) diff --git a/cluster/README.md b/cluster/README.md index 389ef86f..835541bd 100755 --- a/cluster/README.md +++ b/cluster/README.md @@ -10,15 +10,15 @@ The latter is intended for local development, but it also allows us to deploy th The following are prerequisites for spinning up the fuel-data-systems cluster locally: -- kubectl - `https://www.howtoforge.com/how-to-install-kubernetes-with-minikube-ubuntu-20-04/` +- kubectl + `https://www.howtoforge.com/how-to-install-kubernetes-with-minikube-ubuntu-20-04/` -- Tilt: - `https://docs.tilt.dev/install.html` +- Tilt: + `https://docs.tilt.dev/install.html` -- minikube based on the following description: - `https://phoenixnap.com/kb/install-minikube-on-ubuntu` - `https://minikube.sigs.k8s.io/docs/start/` +- minikube based on the following description: + `https://phoenixnap.com/kb/install-minikube-on-ubuntu` + `https://minikube.sigs.k8s.io/docs/start/` ...or alternatively use this tool which will automatically set up your cluster: `https://github.com/tilt-dev/ctlptl##minikube-with-a-built-in-registry` @@ -26,32 +26,36 @@ The following are prerequisites for spinning up the fuel-data-systems cluster lo ## Setup 1. To setup and start the local environment, run: - ```bash - make cluster-setup # Sets up both minikube and kubernetes configuration - ``` - Alternatively, you can run the setup steps individually: - ```bash - make minikube-setup # Sets up minikube with required addons - make k8s-setup # Configures kubernetes with proper namespace and context - ``` + ```bash + make cluster-setup # Sets up both minikube and kubernetes configuration + ``` - You can also start the minikube cluster without running the setup script: - ```bash - make minikube-start # Start minikube cluster - ``` + Alternatively, you can run the setup steps individually: + + ```bash + make minikube-setup # Sets up minikube with required addons + make k8s-setup # Configures kubernetes with proper namespace and context + ``` + + You can also start the minikube cluster without running the setup script: + + ```bash + make minikube-start # Start minikube cluster + ``` 2. Start the Tilt services: - ```bash - make cluster-up # Starts Tiltfile services - ``` + ```bash + make cluster-up # Starts Tiltfile services + ``` You can use the following commands to manage the services: + ```bash -make cluster-up # Start services -make cluster-down # Stop services -make cluster-reset # Reset services -make minikube-start # Start minikube (if you've already run setup before) +make cluster-up # Start services +make cluster-down # Stop services +make cluster-reset # Reset services +make minikube-start # Start minikube (if you've already run setup before) ``` ## Using `k9s` for an interactive terminal UI @@ -62,9 +66,9 @@ Run it with `k9s --context= --namespace=.yaml`. -- Tilt [tutorial](https://docs.tilt.dev/tutorial.html) +- How [kubernetes works](https://www.youtube.com/watch?v=ZuIQurh_kDk) +- Kubernetes [concepts](https://kubernetes.io/docs/concepts/) +- Kubectl [overview](https://kubernetes.io/docs/reference/kubectl/overview/) +- Kubectl [cheat sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) +- Helm [chart tutorial](https://docs.bitnami.com/kubernetes/how-to/create-your-first-helm-chart/), then examine the helm charts in this repository, and the values yaml files that are used to template them. The defults values are in the charts themselves as `values.yaml`, and the values for specific configurations are at `values/.yaml`. +- Tilt [tutorial](https://docs.tilt.dev/tutorial.html) diff --git a/cluster/charts/fuel-streams/Chart.lock b/cluster/charts/fuel-streams/Chart.lock index 44606f01..3b1e4e2c 100644 --- a/cluster/charts/fuel-streams/Chart.lock +++ b/cluster/charts/fuel-streams/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: nats repository: https://nats-io.github.io/k8s/helm/charts/ - version: 1.2.6 + version: 1.2.8 - name: nats repository: https://nats-io.github.io/k8s/helm/charts/ - version: 1.2.6 + version: 1.2.8 - name: nats repository: https://nats-io.github.io/k8s/helm/charts/ - version: 1.2.6 -digest: sha256:ad7948ef2413ea2f9af239829570612f04abd624844413ad73600fd67ce2e9b6 -generated: "2024-12-08T20:11:41.144678-03:00" + version: 1.2.8 +digest: sha256:a5f3dd64e1a20f7c9d58894359f6f909f33d14772355ee70033fd411219bcc7e +generated: "2024-12-18T16:59:13.903435-03:00" diff --git a/cluster/charts/fuel-streams/Chart.yaml b/cluster/charts/fuel-streams/Chart.yaml index 588a1013..61e1bdf8 100755 --- a/cluster/charts/fuel-streams/Chart.yaml +++ b/cluster/charts/fuel-streams/Chart.yaml @@ -2,20 +2,20 @@ apiVersion: v2 appVersion: "1.0" description: A Helm chart for Kubernetes name: fuel-streams -version: 0.1.2 +version: 0.5.7 dependencies: - name: nats - version: 1.2.6 + version: 1.2.8 repository: https://nats-io.github.io/k8s/helm/charts/ alias: nats-core condition: nats-core.enabled - name: nats - version: 1.2.6 + version: 1.2.8 repository: https://nats-io.github.io/k8s/helm/charts/ alias: nats-publisher condition: nats-publisher.enabled - name: nats - version: 1.2.6 + version: 1.2.8 repository: https://nats-io.github.io/k8s/helm/charts/ alias: nats-client condition: nats-client.enabled diff --git a/cluster/charts/fuel-streams/templates/_blocks.tpl b/cluster/charts/fuel-streams/templates/_blocks.tpl index fe70c729..55e3bf07 100644 --- a/cluster/charts/fuel-streams/templates/_blocks.tpl +++ b/cluster/charts/fuel-streams/templates/_blocks.tpl @@ -57,4 +57,56 @@ readinessProbe: startupProbe: {{- include "merge" (dict "context" .context "service" .service "defaultKey" "startupProbe" "path" "config.startupProbe") | nindent 2 }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Configure nats accounts +*/}} +{{- define "nats-accounts" -}} +data: + auth.conf: | + accounts { + SYS: { + users: [ + {user: $NATS_SYS_USER, password: $NATS_SYS_PASSWORD} + ] + } + ADMIN: { + jetstream: enabled + users: [ + {user: $NATS_ADMIN_USER, password: $NATS_ADMIN_PASSWORD} + ] + } + PUBLIC: { + jetstream: enabled + users: [ + { + user: $NATS_PUBLIC_USER + password: $NATS_PUBLIC_PASSWORD + permissions: { + subscribe: ">" + publish: { + deny: [ + "*.by_id.>" + "*.blocks.>" + "*.transactions.>" + "*.inputs.>" + "*.outputs.>" + "*.receipts.>" + "*.logs.>" + "*.utxos.>" + "$JS.API.STREAM.CREATE.>" + "$JS.API.STREAM.UPDATE.>" + "$JS.API.STREAM.DELETE.>" + "$JS.API.STREAM.PURGE.>" + "$JS.API.STREAM.RESTORE.>" + "$JS.API.STREAM.MSG.DELETE.>" + "$JS.API.CONSUMER.DURABLE.CREATE.>" + ] + } + } + } + ] + } + } +{{- end }} diff --git a/cluster/charts/fuel-streams/templates/_helpers.tpl b/cluster/charts/fuel-streams/templates/_helpers.tpl index 4344d0aa..24026951 100644 --- a/cluster/charts/fuel-streams/templates/_helpers.tpl +++ b/cluster/charts/fuel-streams/templates/_helpers.tpl @@ -3,6 +3,16 @@ Expand the name of the chart. If nameOverride is provided in Values.config, use that instead of .Chart.Name. The result is truncated to 63 chars and has any trailing "-" removed to comply with Kubernetes naming rules. Returns: String - The chart name, truncated and cleaned +Example: + Given: + .Chart.Name = "fuel-streams" + .Values.config.nameOverride = "custom-name" + Result: "custom-name" + + Given: + .Chart.Name = "fuel-streams" + .Values.config.nameOverride = null + Result: "fuel-streams" */}} {{- define "fuel-streams.name" -}} {{- default .Chart.Name .Values.config.nameOverride | trunc 63 | trimSuffix "-" }} @@ -17,6 +27,24 @@ This template follows these rules: - If not, concatenate release name and chart name with a hyphen The result is truncated to 63 chars and has any trailing "-" removed to comply with Kubernetes naming rules. Returns: String - The fully qualified app name, truncated and cleaned +Example: + Given: + .Values.config.fullnameOverride = "override-name" + Result: "override-name" + + Given: + .Release.Name = "my-release" + .Chart.Name = "fuel-streams" + .Values.config.nameOverride = null + .Values.config.fullnameOverride = null + Result: "my-release-fuel-streams" + + Given: + .Release.Name = "fuel-streams-prod" + .Chart.Name = "fuel-streams" + .Values.config.nameOverride = null + .Values.config.fullnameOverride = null + Result: "fuel-streams-prod" */}} {{- define "fuel-streams.fullname" -}} {{- if .Values.config.fullnameOverride }} @@ -49,26 +77,43 @@ Includes: - Selector labels (app name and instance) - App version (if defined) - Managed-by label indicating Helm management +Parameters: + - name: Optional custom name to use instead of the default name + - .: Full context (passed automatically or as "context") Returns: Map - A set of key-value pairs representing Kubernetes labels +Example: + {{- include "fuel-streams.labels" . }} + # Or with custom name: + {{- include "fuel-streams.labels" (dict "name" "custom-name" "context" $) }} */}} {{- define "fuel-streams.labels" -}} -helm.sh/chart: {{ include "fuel-streams.chart" . }} -{{ include "fuel-streams.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- $context := default . .context -}} +helm.sh/chart: {{ include "fuel-streams.chart" $context }} +{{ include "fuel-streams.selectorLabels" (dict "name" .name "context" $context) }} +{{- if $context.Chart.AppVersion }} +app.kubernetes.io/version: {{ $context.Chart.AppVersion | quote }} {{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/managed-by: {{ $context.Release.Service }} {{- end }} {{/* Selector labels Core identifying labels used for object selection and service discovery. These labels should be used consistently across all related resources. +Parameters: + - name: Optional custom name to use instead of the default name + - .: Full context (passed automatically or as "context") Returns: Map - A set of key-value pairs for Kubernetes selector labels +Example: + {{- include "fuel-streams.selectorLabels" . }} + # Or with custom name: + {{- include "fuel-streams.selectorLabels" (dict "name" "custom-name" "context" $) }} */}} {{- define "fuel-streams.selectorLabels" -}} -app.kubernetes.io/name: {{ include "fuel-streams.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} +{{- $context := default . .context -}} +{{- $name := default (include "fuel-streams.name" $context) .name -}} +app.kubernetes.io/name: {{ $name }} +app.kubernetes.io/instance: {{ $context.Release.Name }} {{- end }} {{/* diff --git a/cluster/charts/fuel-streams/templates/_hpa.yaml b/cluster/charts/fuel-streams/templates/_hpa.yaml new file mode 100644 index 00000000..2f539b35 --- /dev/null +++ b/cluster/charts/fuel-streams/templates/_hpa.yaml @@ -0,0 +1,55 @@ +{{- define "k8s.hpa" -}} +{{- $service := .service -}} +{{- $context := .context -}} +{{- $autoscaling := $service.autoscaling -}} +{{- if $autoscaling.enabled }} +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + {{- include "k8s.metadata" (dict "context" $context "suffix" (printf "-%s" $service.name)) | nindent 2 }} + labels: + {{- include "fuel-streams.labels" (dict "name" $service.name "context" $context) | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "fuel-streams.fullname" $context }}-{{ $service.name }} + minReplicas: {{ $autoscaling.minReplicas }} + maxReplicas: {{ $autoscaling.maxReplicas }} + behavior: + scaleDown: + stabilizationWindowSeconds: {{ $autoscaling.behavior.scaleDown.stabilizationWindowSeconds | default 300 }} + policies: + - type: Percent + value: {{ $autoscaling.behavior.scaleDown.percentValue | default 100 }} + periodSeconds: {{ $autoscaling.behavior.scaleDown.periodSeconds | default 15 }} + scaleUp: + stabilizationWindowSeconds: {{ $autoscaling.behavior.scaleUp.stabilizationWindowSeconds | default 0 }} + policies: + - type: Percent + value: {{ $autoscaling.behavior.scaleUp.percentValue | default 100 }} + periodSeconds: {{ $autoscaling.behavior.scaleUp.periodSeconds | default 15 }} + - type: Pods + value: {{ $autoscaling.behavior.scaleUp.podValue | default 4 }} + periodSeconds: {{ $autoscaling.behavior.scaleUp.periodSeconds | default 15 }} + selectPolicy: Max + metrics: + {{- if $autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ $autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if $autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ $autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/cluster/charts/fuel-streams/templates/certificate.yaml b/cluster/charts/fuel-streams/templates/certificate.yaml deleted file mode 100644 index 971e1070..00000000 --- a/cluster/charts/fuel-streams/templates/certificate.yaml +++ /dev/null @@ -1,52 +0,0 @@ -{{- $tls := .Values.tls }} -{{- $externalService := .Values.externalService }} -{{- if and $tls.enabled $externalService.dns }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - {{- include "k8s.metadata" (dict "context" . "suffix" "-cert-validator") | nindent 2 }} - labels: - {{- include "fuel-streams.labels" . | nindent 4 }} - {{- include "set-value" (dict "context" $tls "path" "labels") | nindent 4 }} - app.kubernetes.io/service: external-service - annotations: - cert-manager.io/cluster-issuer: {{ $tls.issuer }} - kubernetes.io/ingress.class: nginx - acme.cert-manager.io/http01-ingress-class: nginx - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "false" - {{- include "set-value" (dict "context" $tls "path" "annotations") | nindent 4 }} -spec: - ingressClassName: nginx - rules: - - host: {{ $externalService.dns }} - http: - paths: - - path: /.well-known/acme-challenge/ - pathType: Prefix - backend: - service: - name: cm-acme-http-solver - port: - number: 8089 ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - {{- include "k8s.metadata" (dict "context" . "suffix" "-ws-cert") | nindent 2 }} - labels: - {{- include "fuel-streams.labels" . | nindent 4 }} - {{- include "set-value" (dict "context" $tls "path" "labels") | nindent 4 }} - app.kubernetes.io/service: external-service - annotations: - {{- include "set-value" (dict "context" $tls "path" "annotations") | nindent 4 }} -spec: - secretName: {{ include "fuel-streams.fullname" . }}-ws-tls - duration: {{ $tls.duration }} - renewBefore: {{ $tls.renewBefore }} - dnsNames: - - {{ $externalService.dns }} - issuerRef: - name: {{ $tls.issuer }} - kind: ClusterIssuer -{{- end }} diff --git a/cluster/charts/fuel-streams/templates/consumer/statefulset.yaml b/cluster/charts/fuel-streams/templates/consumer/statefulset.yaml new file mode 100644 index 00000000..5f15bb02 --- /dev/null +++ b/cluster/charts/fuel-streams/templates/consumer/statefulset.yaml @@ -0,0 +1,79 @@ +{{- $consumer := .Values.consumer -}} +{{- if $consumer.enabled -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + {{- include "k8s.metadata" (dict "context" . "suffix" "-consumer") | nindent 2 }} + annotations: + {{- include "set-value" (dict "context" $consumer "path" "config.annotations") | nindent 4 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "consumer" "context" .) | nindent 4 }} + {{- include "set-value" (dict "context" $consumer "path" "config.labels") | nindent 4 }} +spec: + serviceName: {{ include "fuel-streams.fullname" . }}-consumer + {{- if not $consumer.autoscaling.enabled }} + replicas: {{ $consumer.config.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "fuel-streams.selectorLabels" (dict "name" "consumer" "context" .) | nindent 6 }} + + template: + metadata: + annotations: + {{- include "set-value" (dict "context" $consumer "path" "config.podAnnotations") | nindent 8 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "consumer" "context" .) | nindent 8 }} + {{- include "set-value" (dict "context" $consumer "path" "config.labels") | nindent 8 }} + + spec: + {{- if .Values.serviceAccount.create }} + serviceAccountName: {{ include "fuel-streams.serviceAccountName" . }} + {{- end }} + {{- include "set-field-and-value" (dict "context" $consumer "field" "imagePullSecrets" "path" "config.imagePullSecrets") | nindent 6 }} + {{- include "set-field-and-value" (dict "context" $consumer "field" "nodeSelector" "path" "config.nodeSelector") | nindent 6 }} + {{- include "set-field-and-value" (dict "context" $consumer "field" "affinity" "path" "config.affinity") | nindent 6 }} + {{- include "set-field-and-value" (dict "context" $consumer "field" "tolerations" "path" "config.tolerations") | nindent 6 }} + {{- include "k8s.security-context" (dict "context" . "service" "consumer") | nindent 6 }} + + containers: + - name: consumer + image: "{{ $consumer.image.repository }}:{{ $consumer.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ $consumer.image.pullPolicy }} + args: + {{- toYaml $consumer.image.args | nindent 12 }} + + ports: + - name: consumer + containerPort: {{ $consumer.port }} + protocol: TCP + {{- if $consumer.ports }} + {{- toYaml $consumer.ports | nindent 12 }} + {{- end }} + + {{- include "set-field-and-value" (dict "context" $consumer "field" "resources" "path" "config.resources") | nindent 10 }} + {{- include "k8s.probes" (dict "context" . "service" "consumer") | nindent 10 }} + {{- include "k8s.container-security-context" (dict "context" . "service" "consumer") | nindent 10 }} + + env: + {{- range $key, $value := $consumer.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- with $consumer.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + + envFrom: + - configMapRef: + name: {{ include "fuel-streams.fullname" $ }}-consumer + optional: true + - secretRef: + name: {{ include "fuel-streams.fullname" $ }}-consumer + optional: true + {{- with $consumer.envFrom }} + {{- toYaml . | nindent 12 }} + {{- end }} + +{{- include "k8s.hpa" (dict "context" . "service" (dict "name" "consumer" "autoscaling" $consumer.autoscaling)) }} +{{- end }} diff --git a/cluster/charts/fuel-streams/templates/nats/accounts-secret.yaml b/cluster/charts/fuel-streams/templates/nats/accounts-secret.yaml new file mode 100644 index 00000000..f5b8c743 --- /dev/null +++ b/cluster/charts/fuel-streams/templates/nats/accounts-secret.yaml @@ -0,0 +1,15 @@ +{{- $secret := .Values.natsAccountsSecret }} +{{- if $secret.enabled }} +apiVersion: v1 +kind: Secret +metadata: + {{- include "k8s.metadata" (dict "context" . "suffix" "-nats-accounts") | nindent 2 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "nats-accounts" "context" .) | nindent 4 }} + app.kubernetes.io/component: nats +type: Opaque +data: + {{- if $secret.data }} + {{- toYaml $secret.data | nindent 2 }} + {{- end }} +{{- end }} diff --git a/cluster/charts/fuel-streams/templates/nats/certificate.yaml b/cluster/charts/fuel-streams/templates/nats/certificate.yaml new file mode 100644 index 00000000..46b00bba --- /dev/null +++ b/cluster/charts/fuel-streams/templates/nats/certificate.yaml @@ -0,0 +1,57 @@ +{{- $cert := .Values.natsExternalService.certificate}} +{{- $service := .Values.natsExternalService.service }} +{{- if and .Values.natsExternalService.enabled $service.dns }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + {{- include "k8s.metadata" (dict "context" . "suffix" "-nats-cert") | nindent 2 }} + annotations: + {{- include "set-value" (dict "context" $cert "path" "annotations") | nindent 4 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "nats-client" "context" .) | nindent 4 }} + {{- include "set-value" (dict "context" $cert "path" "labels") | nindent 4 }} + app.kubernetes.io/component: nats +spec: + secretName: {{ include "fuel-streams.fullname" . }}-nats-tls + duration: {{ $cert.duration }} + renewBefore: {{ $cert.renewBefore }} + dnsNames: + - {{ $service.dns }} + issuerRef: + name: {{ $cert.issuer }} + kind: ClusterIssuer +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + {{- include "k8s.metadata" (dict "context" . "suffix" "-nats-cert-validator") | nindent 2 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "nats-client" "context" .) | nindent 4 }} + {{- include "set-value" (dict "context" $cert "path" "labels") | nindent 4 }} + app.kubernetes.io/component: nats + annotations: + cert-manager.io/cluster-issuer: {{ $cert.issuer }} + kubernetes.io/ingress.class: nginx + acme.cert-manager.io/http01-ingress-class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + cert-manager.io/common-name: {{ $service.dns }} + {{- include "set-value" (dict "context" $cert "path" "annotations") | nindent 4 }} +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ $service.dns }} + secretName: {{ include "fuel-streams.fullname" . }}-nats-tls + rules: + - host: {{ $service.dns }} + http: + paths: + - path: /.well-known/acme-challenge/ + pathType: Prefix + backend: + service: + name: cm-acme-http-solver + port: + number: 8089 +{{- end }} diff --git a/cluster/charts/fuel-streams/templates/external-service.yaml b/cluster/charts/fuel-streams/templates/nats/external-service.yaml similarity index 50% rename from cluster/charts/fuel-streams/templates/external-service.yaml rename to cluster/charts/fuel-streams/templates/nats/external-service.yaml index 4b2c4602..22231bbc 100644 --- a/cluster/charts/fuel-streams/templates/external-service.yaml +++ b/cluster/charts/fuel-streams/templates/nats/external-service.yaml @@ -1,15 +1,11 @@ -{{- $externalService := .Values.externalService }} -{{- if and $externalService.enabled $externalService.dns }} +{{- $service := .Values.natsExternalService.service }} +{{- if and .Values.natsExternalService.enabled $service.dns }} apiVersion: v1 kind: Service metadata: - {{- include "k8s.metadata" (dict "context" . "suffix" "-external") | nindent 2 }} - labels: - {{- include "fuel-streams.labels" . | nindent 4 }} - {{- include "set-value" (dict "context" $externalService "path" "labels") | nindent 4 }} - app.kubernetes.io/service: external-service + {{- include "k8s.metadata" (dict "context" . "suffix" "-nats-client-nlb") | nindent 2 }} annotations: - external-dns.alpha.kubernetes.io/hostname: {{ $externalService.dns | quote }} + external-dns.alpha.kubernetes.io/hostname: {{ $service.dns }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" service.beta.kubernetes.io/aws-load-balancer-attributes: load_balancing.cross_zone.enabled=true service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp @@ -18,14 +14,27 @@ metadata: service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: preserve_client_ip.enabled=true,stickiness.enabled=true,stickiness.type=source_ip,load_balancing.cross_zone.enabled=true service.beta.kubernetes.io/aws-load-balancer-type: external service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "WebSocket=true" - {{- include "set-value" (dict "context" $externalService "path" "annotations") | nindent 2 }} + {{- include "set-value" (dict "context" $service "path" "annotations") | nindent 2 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "nats-client" "context" .) | nindent 4 }} + {{- include "set-value" (dict "context" $service "path" "labels") | nindent 4 }} + app.kubernetes.io/component: nats spec: type: LoadBalancer loadBalancerClass: service.k8s.aws/nlb externalTrafficPolicy: Local ports: - {{- toYaml $externalService.ports | nindent 4 }} + - appProtocol: tcp + name: nats + port: 4222 + protocol: TCP + targetPort: nats + - appProtocol: tcp + name: wss + port: 8443 + protocol: TCP + targetPort: websocket selector: - {{- include "fuel-streams.selectorLabels" . | nindent 4 }} - app.kubernetes.io/service: external-service + {{- include "fuel-streams.selectorLabels" (dict "name" "nats-client" "context" .) | nindent 4 }} + app.kubernetes.io/component: nats {{- end }} diff --git a/cluster/charts/fuel-streams/templates/publisher/network-configmap.yaml b/cluster/charts/fuel-streams/templates/publisher/network-configmap.yaml deleted file mode 100644 index 18a644ef..00000000 --- a/cluster/charts/fuel-streams/templates/publisher/network-configmap.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{- $publisher := .Values.publisher }} -apiVersion: v1 -kind: ConfigMap -metadata: - {{- include "k8s.metadata" (dict "context" . "suffix" "-network-config") | nindent 2 }} - annotations: - {{- include "set-value" (dict "context" $publisher "path" "config.annotations") | nindent 4 }} - labels: - {{- include "fuel-streams.labels" . | nindent 4 }} - {{- include "set-value" (dict "context" $publisher "path" "config.labels") | nindent 4 }} - app.kubernetes.io/component: publisher -data: - P2P_PORT: "30333" - DB_PATH: {{ .Values.publisher.storage.mountPath | quote }} - POA_INSTANT: "false" - SERVICE_NAME: "Publisher Node ({{ $publisher.network }})" - {{- if eq $publisher.network "mainnet" }} - RELAYER_V2_LISTENING_CONTRACTS: "0xAEB0c00D0125A8a788956ade4f4F12Ead9f65DDf" - RELAYER_DA_DEPLOY_HEIGHT: "20620434" - RELAYER_LOG_PAGE_SIZE: "2000" - SYNC_HEADER_BATCH_SIZE: "100" - RESERVED_NODES: "/dnsaddr/mainnet.fuel.network" - CHAIN_CONFIG: "mainnet" - {{- else if eq $publisher.network "testnet" }} - RELAYER_V2_LISTENING_CONTRACTS: "0x01855B78C1f8868DE70e84507ec735983bf262dA" - RELAYER_DA_DEPLOY_HEIGHT: "5827607" - RELAYER_LOG_PAGE_SIZE: "2000" - SYNC_HEADER_BATCH_SIZE: "100" - RESERVED_NODES: "/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmDxoChB7AheKNvCVpD4PHJwuDGn8rifMBEHmEynGHvHrf,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmHnANNk4HjAxQV66BNCRxd2MBUU89ijboZkE69aLuSn1g,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmVE468rpkh2X1kzz8qQXmqNFiPxU5Lrya28nZdbRUdVJX" - CHAIN_CONFIG: "testnet" - {{- end }} diff --git a/cluster/charts/fuel-streams/templates/publisher/statefulset.yaml b/cluster/charts/fuel-streams/templates/publisher/statefulset.yaml index 0ad2c022..85de7960 100644 --- a/cluster/charts/fuel-streams/templates/publisher/statefulset.yaml +++ b/cluster/charts/fuel-streams/templates/publisher/statefulset.yaml @@ -7,9 +7,8 @@ metadata: annotations: {{- include "set-value" (dict "context" $publisher "path" "config.annotations") | nindent 4 }} labels: - {{- include "fuel-streams.labels" . | nindent 4 }} + {{- include "fuel-streams.labels" (dict "name" "publisher" "context" .) | nindent 4 }} {{- include "set-value" (dict "context" $publisher "path" "config.labels") | nindent 4 }} - app.kubernetes.io/component: publisher spec: serviceName: {{ include "fuel-streams.fullname" . }}-publisher {{- if not $publisher.autoscaling.enabled }} @@ -17,18 +16,15 @@ spec: {{- end }} selector: matchLabels: - {{- include "fuel-streams.selectorLabels" . | nindent 6 }} - {{- include "set-value" (dict "context" $publisher "path" "config.selectorLabels") | nindent 6 }} - app.kubernetes.io/component: publisher + {{- include "fuel-streams.selectorLabels" (dict "name" "publisher" "context" .) | nindent 6 }} template: metadata: annotations: {{- include "set-value" (dict "context" $publisher "path" "config.podAnnotations") | nindent 8 }} labels: - {{- include "fuel-streams.selectorLabels" . | nindent 8 }} + {{- include "fuel-streams.labels" (dict "name" "publisher" "context" .) | nindent 8 }} {{- include "set-value" (dict "context" $publisher "path" "config.labels") | nindent 8 }} - app.kubernetes.io/component: publisher spec: {{- if .Values.serviceAccount.create }} @@ -45,7 +41,7 @@ spec: emptyDir: {} - name: var-dir emptyDir: {} - + initContainers: - name: update-{{ $publisher.storage.name }} image: alpine:latest @@ -81,6 +77,64 @@ spec: - name: publisher image: "{{ $publisher.image.repository }}:{{ $publisher.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ $publisher.image.pullPolicy }} + args: + # Common arguments + - "--enable-relayer" + - "--enable-p2p" + - "--keypair" + - "$(KEYPAIR)" + - "--relayer" + - "$(RELAYER)" + - "--ip" + - "0.0.0.0" + - "--port" + - "$(PORT)" + - "--db-path" + - "$(DB_PATH)" + - "--nats-url" + - "$(NATS_URL)" + - "--sync-header-batch-size" + - "100" + - "--relayer-log-page-size" + - "2000" + - "--sync-block-stream-buffer-size" + - "50" + - "--max-database-cache-size" + - "17179869184" + - "--state-rewind-duration" + - "136y" + - "--request-timeout" + - "60" + - "--graphql-max-complexity" + - "1000000000" + {{- if eq $publisher.network "mainnet" }} + # Mainnet specific args + - "--service-name" + - "Publisher Node (Mainnet)" + - "--snapshot" + - "./chain-config/mainnet" + - "--reserved-nodes" + - "/dnsaddr/mainnet.fuel.network" + - "--relayer-v2-listening-contracts" + - "0xAEB0c00D0125A8a788956ade4f4F12Ead9f65DDf" + - "--relayer-da-deploy-height" + - "20620434" + {{- else if eq $publisher.network "testnet" }} + # Testnet specific args + - "--service-name" + - "Publisher Node (Testnet)" + - "--snapshot" + - "./chain-config/testnet" + - "--reserved-nodes" + - "/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmDxoChB7AheKNvCVpD4PHJwuDGn8rifMBEHmEynGHvHrf,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmHnANNk4HjAxQV66BNCRxd2MBUU89ijboZkE69aLuSn1g,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmVE468rpkh2X1kzz8qQXmqNFiPxU5Lrya28nZdbRUdVJX" + - "--relayer-v2-listening-contracts" + - "0x01855B78C1f8868DE70e84507ec735983bf262dA" + - "--relayer-da-deploy-height" + - "5827607" + {{- end }} + {{- if $publisher.image.extraArgs }} + {{- toYaml $publisher.image.extraArgs | nindent 12 }} + {{- end }} ports: - name: http containerPort: {{ int $publisher.service.port }} @@ -96,6 +150,8 @@ spec: env: - name: TMPDIR value: "/var/fuel-streams/tmp" + - name: DB_PATH + value: {{ $publisher.storage.mountPath | default "/mnt/db" | quote }} {{- range $key, $value := $publisher.env }} - name: {{ $key }} value: {{ $value | quote }} @@ -105,8 +161,6 @@ spec: {{- end }} envFrom: - - configMapRef: - name: {{ include "fuel-streams.fullname" $ }}-network-config - configMapRef: name: {{ include "fuel-streams.fullname" $ }}-publisher optional: true diff --git a/cluster/charts/fuel-streams/templates/secret-creator.yaml b/cluster/charts/fuel-streams/templates/secret-creator.yaml index 04719e93..a64043ec 100755 --- a/cluster/charts/fuel-streams/templates/secret-creator.yaml +++ b/cluster/charts/fuel-streams/templates/secret-creator.yaml @@ -4,7 +4,7 @@ kind: Role metadata: {{- include "k8s.metadata" (dict "context" . "suffix" "-secret-creator") | nindent 2 }} labels: - {{- include "fuel-streams.labels" . | nindent 2 }} + {{- include "fuel-streams.labels" (dict "name" "secret-creator" "context" .) | nindent 2 }} rules: - apiGroups: [""] # "" indicates the core API group resources: ["pods"] @@ -20,6 +20,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: {{- include "k8s.metadata" (dict "context" . "suffix" "-secret-creator") | nindent 2 }} + labels: + {{- include "fuel-streams.labels" (dict "name" "secret-creator" "context" .) | nindent 2 }} subjects: - kind: ServiceAccount name: {{ include "fuel-streams.serviceAccountName" . }} diff --git a/cluster/charts/fuel-streams/templates/service-account.yaml b/cluster/charts/fuel-streams/templates/service-account.yaml index 8201ea7c..eac6647b 100755 --- a/cluster/charts/fuel-streams/templates/service-account.yaml +++ b/cluster/charts/fuel-streams/templates/service-account.yaml @@ -4,6 +4,6 @@ kind: ServiceAccount metadata: {{- include "k8s.metadata" (dict "context" . "suffix" "-service-account") | nindent 2 }} labels: - {{- include "fuel-streams.labels" . | nindent 4 }} + {{- include "fuel-streams.labels" (dict "name" "service-account" "context" .) | nindent 4 }} automountServiceAccountToken: {{ .Values.serviceAccount.automount }} {{- end -}} diff --git a/cluster/charts/fuel-streams/templates/webserver/deployment.yaml b/cluster/charts/fuel-streams/templates/webserver/deployment.yaml index 759fc13a..57b7dad3 100644 --- a/cluster/charts/fuel-streams/templates/webserver/deployment.yaml +++ b/cluster/charts/fuel-streams/templates/webserver/deployment.yaml @@ -7,31 +7,23 @@ metadata: annotations: {{- include "set-value" (dict "context" $webserver "path" "config.annotations") | nindent 4 }} labels: - {{- include "fuel-streams.labels" . | nindent 4 }} + {{- include "fuel-streams.labels" (dict "name" "webserver" "context" .) | nindent 4 }} {{- include "set-value" (dict "context" $webserver "path" "config.labels") | nindent 4 }} - app.kubernetes.io/component: webserver - app.kubernetes.io/service: external-service - spec: {{- if not $webserver.autoscaling.enabled }} replicas: {{ $webserver.config.replicaCount }} {{- end }} selector: matchLabels: - {{- include "fuel-streams.selectorLabels" . | nindent 6 }} - {{- include "set-value" (dict "context" $webserver "path" "config.selectorLabels") | nindent 6 }} - app.kubernetes.io/component: webserver - app.kubernetes.io/service: external-service + {{- include "fuel-streams.selectorLabels" (dict "name" "webserver" "context" .) | nindent 6 }} template: metadata: annotations: {{- include "set-value" (dict "context" $webserver "path" "config.podAnnotations") | nindent 8 }} labels: - {{- include "fuel-streams.selectorLabels" . | nindent 8 }} + {{- include "fuel-streams.labels" (dict "name" "webserver" "context" .) | nindent 8 }} {{- include "set-value" (dict "context" $webserver "path" "config.labels") | nindent 8 }} - app.kubernetes.io/component: webserver - app.kubernetes.io/service: external-service spec: {{- if .Values.serviceAccount.create }} @@ -69,4 +61,6 @@ spec: {{- with $webserver.extraEnv }} {{- toYaml . | nindent 12 }} {{- end }} + +{{- include "k8s.hpa" (dict "context" . "service" (dict "name" "webserver" "autoscaling" $webserver.autoscaling)) }} {{- end }} diff --git a/cluster/charts/fuel-streams/tests/consumer/deployment_test.yaml b/cluster/charts/fuel-streams/tests/consumer/deployment_test.yaml new file mode 100644 index 00000000..03334a73 --- /dev/null +++ b/cluster/charts/fuel-streams/tests/consumer/deployment_test.yaml @@ -0,0 +1,305 @@ +suite: Testing Consumer deployment +templates: + - templates/consumer/deployment.yaml +tests: + - it: should not create deployment when consumer is disabled + set: + consumer.enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should create deployment with correct kind and metadata + set: + consumer.enabled: true + asserts: + - isKind: + of: Deployment + documentIndex: 0 + - isAPIVersion: + of: apps/v1 + documentIndex: 0 + - equal: + path: metadata.name + value: RELEASE-NAME-fuel-streams-consumer + - equal: + path: metadata.labels["app.kubernetes.io/component"] + value: consumer + - equal: + path: metadata.labels["app.kubernetes.io/service"] + value: external-service + documentIndex: 0 + + - it: should set correct selector labels + set: + consumer.enabled: true + asserts: + - equal: + path: spec.selector.matchLabels["app.kubernetes.io/component"] + value: consumer + documentIndex: 0 + - isSubset: + path: spec.selector.matchLabels + content: + app.kubernetes.io/name: fuel-streams + app.kubernetes.io/instance: RELEASE-NAME + documentIndex: 0 + + - it: should set image configuration correctly + set: + consumer.enabled: true + consumer.image.repository: ghcr.io/fuellabs/fuel-streams-webserver + consumer.image.tag: latest + consumer.image.pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ghcr.io/fuellabs/fuel-streams-webserver:latest + documentIndex: 0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + documentIndex: 0 + + - it: should use chart version when tag is not specified + set: + consumer.enabled: true + consumer.image.repository: ghcr.io/fuellabs/fuel-streams-webserver + consumer.image.tag: null + Chart: + Version: "1.0" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ghcr.io/fuellabs/fuel-streams-webserver:1.0 + documentIndex: 0 + + - it: should configure ports correctly + set: + consumer.enabled: true + consumer.port: 8082 + consumer.ports: + - name: metrics + containerPort: 9090 + protocol: TCP + asserts: + - lengthEqual: + path: spec.template.spec.containers[0].ports + count: 2 + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].ports + content: + name: consumer + containerPort: 8082 + protocol: TCP + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].ports + content: + name: metrics + containerPort: 9090 + protocol: TCP + documentIndex: 0 + + - it: should set replicas when autoscaling is disabled + set: + consumer.enabled: true + consumer.autoscaling.enabled: false + consumer.config.replicaCount: 3 + asserts: + - equal: + path: spec.replicas + value: 3 + documentIndex: 0 + + - it: should not set replicas when autoscaling is enabled + set: + consumer.enabled: true + consumer.autoscaling.enabled: true + consumer.config.replicaCount: 3 + asserts: + - isNull: + path: spec.replicas + documentIndex: 0 + + - it: should merge environment variables correctly + set: + consumer.enabled: true + consumer.env: + RUST_LOG: info + APP_PORT: "8080" + consumer.extraEnv: + - name: EXTRA_VAR + value: "extra-value" + - name: SECRET_VAR + valueFrom: + secretKeyRef: + name: my-secret + key: my-key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: RUST_LOG + value: "info" + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].env + content: + name: APP_PORT + value: "8080" + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].env + content: + name: EXTRA_VAR + value: "extra-value" + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].env + content: + name: SECRET_VAR + valueFrom: + secretKeyRef: + name: my-secret + key: my-key + documentIndex: 0 + + - it: should set security context when specified + set: + consumer.enabled: true + consumer.config.securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + asserts: + - equal: + path: spec.template.spec.securityContext.runAsUser + value: 1000 + documentIndex: 0 + - equal: + path: spec.template.spec.securityContext.runAsGroup + value: 3000 + documentIndex: 0 + - equal: + path: spec.template.spec.securityContext.fsGroup + value: 2000 + documentIndex: 0 + + - it: should set resource limits and requests + set: + consumer.enabled: true + consumer.config.resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + asserts: + - equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 100m + documentIndex: 0 + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 128Mi + documentIndex: 0 + - equal: + path: spec.template.spec.containers[0].resources.requests.cpu + value: 50m + documentIndex: 0 + - equal: + path: spec.template.spec.containers[0].resources.requests.memory + value: 64Mi + documentIndex: 0 + + - it: should create HPA with correct configuration when autoscaling is enabled + set: + consumer.enabled: true + consumer.autoscaling.enabled: true + consumer.autoscaling.minReplicas: 2 + consumer.autoscaling.maxReplicas: 5 + consumer.autoscaling.targetCPUUtilizationPercentage: 75 + consumer.autoscaling.targetMemoryUtilizationPercentage: 85 + asserts: + - hasDocuments: + count: 2 + - isKind: + of: HorizontalPodAutoscaler + documentIndex: 1 + - equal: + path: spec.minReplicas + value: 2 + documentIndex: 1 + - equal: + path: spec.maxReplicas + value: 5 + documentIndex: 1 + - equal: + path: spec.metrics[0].resource.target.averageUtilization + value: 75 + documentIndex: 1 + - equal: + path: spec.metrics[1].resource.target.averageUtilization + value: 85 + documentIndex: 1 + + - it: should configure HPA scaling behavior correctly + set: + consumer.enabled: true + consumer.autoscaling.enabled: true + consumer.autoscaling.behavior.scaleDown.stabilizationWindowSeconds: 400 + consumer.autoscaling.behavior.scaleDown.percentValue: 50 + consumer.autoscaling.behavior.scaleUp.stabilizationWindowSeconds: 60 + consumer.autoscaling.behavior.scaleUp.percentValue: 200 + consumer.autoscaling.behavior.scaleUp.podValue: 6 + asserts: + - equal: + path: spec.behavior.scaleDown.stabilizationWindowSeconds + value: 400 + documentIndex: 1 + - equal: + path: spec.behavior.scaleDown.policies[0].type + value: Percent + documentIndex: 1 + - equal: + path: spec.behavior.scaleDown.policies[0].value + value: 50 + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.stabilizationWindowSeconds + value: 60 + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.policies[0].type + value: Percent + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.policies[0].value + value: 200 + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.policies[1].type + value: Pods + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.policies[1].value + value: 6 + documentIndex: 1 + - equal: + path: spec.behavior.scaleUp.selectPolicy + value: Max + documentIndex: 1 + + - it: should not create HPA when autoscaling is disabled + set: + consumer.enabled: true + consumer.autoscaling.enabled: false + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Deployment + documentIndex: 0 diff --git a/cluster/charts/fuel-streams/tests/external_service_test.yaml b/cluster/charts/fuel-streams/tests/external_service_test.yaml index 11a70a5e..611cb452 100644 --- a/cluster/charts/fuel-streams/tests/external_service_test.yaml +++ b/cluster/charts/fuel-streams/tests/external_service_test.yaml @@ -73,7 +73,7 @@ tests: path: spec.selector content: app.kubernetes.io/name: fuel-streams - app.kubernetes.io/service: external-service + app.kubernetes.io/service: external-ws - it: should set correct annotations set: diff --git a/cluster/charts/fuel-streams/tests/publisher/network-configmap.yaml b/cluster/charts/fuel-streams/tests/publisher/network-configmap.yaml deleted file mode 100644 index dfb5a7b3..00000000 --- a/cluster/charts/fuel-streams/tests/publisher/network-configmap.yaml +++ /dev/null @@ -1,87 +0,0 @@ -suite: Testing Publisher network configmap -templates: - - templates/publisher/network-configmap.yaml -tests: - - it: should configure mainnet correctly - set: - publisher.enabled: true - publisher.network: mainnet - publisher.storage.mountPath: /mnt/db - asserts: - - isKind: - of: ConfigMap - - equal: - path: metadata.name - value: RELEASE-NAME-fuel-streams-network-config - - equal: - path: data.P2P_PORT - value: "30333" - - equal: - path: data.DB_PATH - value: /mnt/db - - equal: - path: data.POA_INSTANT - value: "false" - - equal: - path: data.SERVICE_NAME - value: "Publisher Node (mainnet)" - - equal: - path: data.RELAYER_V2_LISTENING_CONTRACTS - value: "0xAEB0c00D0125A8a788956ade4f4F12Ead9f65DDf" - - equal: - path: data.RELAYER_DA_DEPLOY_HEIGHT - value: "20620434" - - equal: - path: data.RELAYER_LOG_PAGE_SIZE - value: "2000" - - equal: - path: data.SYNC_HEADER_BATCH_SIZE - value: "100" - - equal: - path: data.RESERVED_NODES - value: "/dnsaddr/mainnet.fuel.network" - - equal: - path: data.CHAIN_CONFIG - value: "mainnet" - - - it: should configure testnet correctly - set: - publisher.enabled: true - publisher.network: testnet - publisher.storage.mountPath: /mnt/db - asserts: - - isKind: - of: ConfigMap - - equal: - path: metadata.name - value: RELEASE-NAME-fuel-streams-network-config - - equal: - path: data.P2P_PORT - value: "30333" - - equal: - path: data.DB_PATH - value: /mnt/db - - equal: - path: data.POA_INSTANT - value: "false" - - equal: - path: data.SERVICE_NAME - value: "Publisher Node (testnet)" - - equal: - path: data.RELAYER_V2_LISTENING_CONTRACTS - value: "0x01855B78C1f8868DE70e84507ec735983bf262dA" - - equal: - path: data.RELAYER_DA_DEPLOY_HEIGHT - value: "5827607" - - equal: - path: data.RELAYER_LOG_PAGE_SIZE - value: "2000" - - equal: - path: data.SYNC_HEADER_BATCH_SIZE - value: "100" - - equal: - path: data.RESERVED_NODES - value: "/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmDxoChB7AheKNvCVpD4PHJwuDGn8rifMBEHmEynGHvHrf,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmHnANNk4HjAxQV66BNCRxd2MBUU89ijboZkE69aLuSn1g,/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmVE468rpkh2X1kzz8qQXmqNFiPxU5Lrya28nZdbRUdVJX" - - equal: - path: data.CHAIN_CONFIG - value: "testnet" diff --git a/cluster/charts/fuel-streams/values-local.yaml b/cluster/charts/fuel-streams/values-local.yaml new file mode 100644 index 00000000..dc5af796 --- /dev/null +++ b/cluster/charts/fuel-streams/values-local.yaml @@ -0,0 +1,137 @@ +config: + createRoles: true + healthChecks: true + +# Reduce storage requirements for local development +publisher: + storage: + size: 10Gi + storageClass: "standard" # Use default storage class + + config: + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + env: + PORT: 8080 + PUBLISHER_MAX_THREADS: "12" + NATS_URL: "fuel-streams-nats-publisher:4222" + +consumer: + config: + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + +# NATS Core configuration for local development +nats-core: + container: + env: + GOMEMLIMIT: 1GiB + merge: + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + config: + cluster: + replicas: 1 # Single replica for local development + + jetstream: + fileStore: + pvc: + size: 10Gi + storageClassName: "standard" + + merge: + jetstream: + max_file_store: << 10GiB >> + max_memory_store: << 1GiB >> + +# NATS Publisher configuration for local development +nats-publisher: + container: + env: + GOMEMLIMIT: 1GiB + merge: + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + config: + jetstream: + fileStore: + pvc: + size: 10Gi + storageClassName: "standard" + + merge: + jetstream: + max_file_store: << 10GiB >> + max_memory_store: << 1GiB >> + +# NATS Client configuration for local development +nats-client: + container: + env: + GOMEMLIMIT: 1GiB + merge: + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + config: + jetstream: + fileStore: + pvc: + size: 10Gi + storageClassName: "standard" + + merge: + jetstream: + max_file_store: << 10GiB >> + max_memory_store: << 1GiB >> + +# Disable external service for local development +natsExternalService: + enabled: false + +# Use simple passwords for local development +natsAccountsSecret: + enabled: true + data: + - name: NATS_SYS_USER + value: sys + - name: NATS_SYS_PASS + value: sys + - name: NATS_ADMIN_USER + value: admin + - name: NATS_ADMIN_PASS + value: admin + - name: NATS_PUBLISHER_USER + value: default_user + - name: NATS_PUBLISHER_PASS + value: "" diff --git a/cluster/charts/fuel-streams/values.yaml b/cluster/charts/fuel-streams/values.yaml index e00d00d1..7741dc0b 100755 --- a/cluster/charts/fuel-streams/values.yaml +++ b/cluster/charts/fuel-streams/values.yaml @@ -1,6 +1,3 @@ -docker: - registry: registry.dev.svc.cluster.local:5000 - config: # Override the name and fullname of the chart nameOverride: "" @@ -72,29 +69,6 @@ startupProbe: failureThreshold: 6 successThreshold: 1 -tls: - enabled: false - issuer: "letsencrypt-prod" - duration: "2160h" - renewBefore: "360h" - annotations: {} - labels: {} - -externalService: - enabled: false - dns: "streams.svc.cluster.local" - labels: {} - annotations: {} - ports: - - name: websocket - port: 8443 - targetPort: websocket - protocol: TCP - - name: webserver - port: 8082 - targetPort: http - protocol: TCP - # ------------------------------------------------------------------------------------------------- # Monitoring # ------------------------------------------------------------------------------------------------- @@ -111,9 +85,10 @@ publisher: network: mainnet image: - repository: fuel-streams-publisher - pullPolicy: Never + repository: ghcr.io/fuellabs/sv-emitter + pullPolicy: Always tag: "latest" + extraArgs: [] service: type: ClusterIP @@ -126,8 +101,8 @@ publisher: storage: name: rocks-db - size: 10Gi - storageClass: standard + size: 500Gi + storageClass: "gp3-generic" accessMode: ReadWriteOnce mountPath: /mnt/db @@ -154,11 +129,16 @@ publisher: maxReplicas: 3 targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: 80 - - env: - PUBLISHER_MAX_THREADS: "32" - NATS_URL: "fuel-streams-nats-publisher:4222" - HISTORICAL: "true" + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + percentValue: 100 + periodSeconds: 15 + scaleUp: + stabilizationWindowSeconds: 0 + percentValue: 100 + podValue: 4 + periodSeconds: 15 # Additional environment variables with complex structures # extraEnv: [] @@ -184,21 +164,35 @@ publisher: # - secretRef: # name: additional-secrets + env: + PORT: 8080 + PUBLISHER_MAX_THREADS: "32" + NATS_URL: "fuel-streams-nats-publisher:4222" + # ------------------------------------------------------------------------------------------------- -# WebServer configuration +# Consumer configuration # ------------------------------------------------------------------------------------------------- -webserver: - enabled: false - port: 8082 - +consumer: + enabled: true + port: 8080 image: - repository: fuel-streams-webserver - pullPolicy: Never + repository: ghcr.io/fuellabs/sv-consumer + pullPolicy: Always tag: "latest" + args: + - --nats-core-url + - $(NATS_CORE_URL) + - --nats-publisher-url + - $(NATS_PUBLISHER_URL) + + env: + PORT: 8080 + NATS_CORE_URL: "fuel-streams-nats-core:4222" + NATS_PUBLISHER_URL: "fuel-streams-nats-publisher:4222" config: - replicaCount: 1 + replicaCount: 3 labels: {} annotations: {} podAnnotations: {} @@ -212,20 +206,47 @@ webserver: startupProbe: {} securityContext: {} containerSecurityContext: {} - resources: - requests: - cpu: 100m - memory: 128Mi - limits: - cpu: 500m - memory: 512Mi + resources: {} autoscaling: - enabled: false + enabled: true minReplicas: 1 maxReplicas: 3 targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: 80 + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + percentValue: 100 + periodSeconds: 15 + scaleUp: + stabilizationWindowSeconds: 0 + percentValue: 100 + podValue: 4 + periodSeconds: 15 + +# ------------------------------------------------------------------------------------------------- +# NATS Common Configuration +# ------------------------------------------------------------------------------------------------- + +natsExternalService: + enabled: true + certificate: + issuer: "letsencrypt-prod" + duration: "2160h" + renewBefore: "360h" + annotations: {} + labels: {} + service: + dns: "stream-dev.fuel.network" + labels: {} + annotations: {} + +# This is just need to run locally, for production you need to +# create a secret with the correct values named fuel-streams-nats-accounts +natsAccountsSecret: + enabled: false + data: [] # ------------------------------------------------------------------------------------------------- # NATS Core configuration @@ -252,17 +273,14 @@ nats-core: container: image: repository: nats - tag: 2.10.22-alpine + tag: 2.10.24-alpine env: - GOMEMLIMIT: 8GiB - startupProbe: - initialDelaySeconds: 60 - periodSeconds: 10 - failureThreshold: 1080 - resources: - requests: - cpu: 8 - memory: 8Gi + GOMEMLIMIT: 7GiB + merge: + resources: + requests: + cpu: 2 + memory: 8Gi service: enabled: true @@ -271,6 +289,8 @@ nats-core: enabled: true cluster: enabled: true + websocket: + enabled: true leafnodes: enabled: true monitor: @@ -280,18 +300,22 @@ nats-core: cluster: enabled: true port: 6222 - replicas: 3 + replicas: 5 routeURLs: useFQDN: true + websocket: + enabled: true + port: 8443 + jetstream: enabled: true fileStore: dir: /data pvc: enabled: true - size: 500Gi - storageClassName: standard + size: 2000Gi + storageClassName: "gp3-generic" leafnodes: enabled: true @@ -302,65 +326,61 @@ nats-core: port: 8222 merge: + max_payload: << 32MiB >> jetstream: - max_file_store: << 500GiB >> - max_memory_store: << 7168MiB >> - domain: "central" - max_payload: << 8MiB >> + domain: CORE + sync_interval: << 30s >> + max_outstanding_catchup: << 512MiB >> + max_file_store: << 2000GiB >> + max_memory_store: << 7GiB >> + system_account: SYS + $include: auth.conf + + configMap: + merge: + $tplYaml: | + {{- include "nats-accounts" . | nindent 8 }} # ------------------------------------------------------------------------------------------------- -# NATS Client configuration +# NATS Publisher configuration # ------------------------------------------------------------------------------------------------- -nats-client: +nats-publisher: enabled: true - global: - labels: - app.kubernetes.io/service: external-service - natsBox: enabled: false promExporter: enabled: false + statefulSet: + merge: + spec: + replicas: 5 + container: image: repository: nats - tag: 2.10.22-alpine + tag: 2.10.24-alpine env: - GOMEMLIMIT: 2GiB - startupProbe: - initialDelaySeconds: 60 - periodSeconds: 10 - failureThreshold: 1080 - resources: - requests: - cpu: 2 - memory: 2Gi + GOMEMLIMIT: 7GiB + merge: + resources: + requests: + cpu: 2 + memory: 8Gi service: enabled: true ports: nats: enabled: true - websocket: + leafnodes: enabled: true monitor: enabled: false - statefulSet: - merge: - spec: - replicas: 2 - - podTemplate: - topologySpreadConstraints: - kubernetes.io/hostname: - maxSkew: 1 - whenUnsatisfiable: DoNotSchedule - config: jetstream: enabled: true @@ -368,104 +388,77 @@ nats-client: dir: /data pvc: enabled: true - size: 20Gi - storageClassName: standard - merge: - domain: "client" + size: 100Gi + storageClassName: "gp3-generic" leafnodes: enabled: true port: 7422 - remotes: - - url: "nats://nats-core:7422" - - websocket: - enabled: true - port: 8443 merge: - no_tls: true - no_auth_user: default_user + remotes: + - urls: ["nats-leaf://admin:admin@fuel-streams-nats-core:7422"] + account: ADMIN monitor: enabled: false port: 8222 merge: + max_payload: << 32MiB >> jetstream: - max_file_store: << 20GiB >> - max_memory_store: << 2048MiB >> - max_payload: << 8MiB >> - accounts: - USERS: - jetstream: enabled - users: - - user: default_user - permissions: - subscribe: ">" - publish: - deny: - - "*.by_id.>" - - "*.blocks.>" - - "*.transactions.>" - - "*.inputs.>" - - "*.outputs.>" - - "*.receipts.>" - - "*.logs.>" - - "*.utxos.>" - - "$JS.API.STREAM.CREATE.>" - - "$JS.API.STREAM.UPDATE.>" - - "$JS.API.STREAM.DELETE.>" - - "$JS.API.STREAM.PURGE.>" - - "$JS.API.STREAM.RESTORE.>" - - "$JS.API.STREAM.MSG.DELETE.>" - - "$JS.API.CONSUMER.DURABLE.CREATE.>" + domain: PUBLISHER + sync_interval: << 30s >> + max_outstanding_catchup: << 512MiB >> + max_file_store: << 100GiB >> + max_memory_store: << 7GiB >> + system_account: SYS + $include: auth.conf + + configMap: + merge: + $tplYaml: | + {{- include "nats-accounts" . | nindent 8 }} # ------------------------------------------------------------------------------------------------- -# NATS Publisher configuration +# NATS Client configuration # ------------------------------------------------------------------------------------------------- -nats-publisher: +nats-client: enabled: true natsBox: enabled: false - promExporter: - enabled: false + statefulSet: + merge: + spec: + replicas: 3 container: image: repository: nats - tag: 2.10.22-alpine + tag: 2.10.24-alpine env: - GOMEMLIMIT: 3GiB - startupProbe: - initialDelaySeconds: 60 - periodSeconds: 10 - failureThreshold: 1080 - resources: - requests: - cpu: 4 - memory: 4Gi + GOMEMLIMIT: 7GiB + merge: + resources: + requests: + cpu: 2 + memory: 8Gi service: enabled: true ports: nats: enabled: true + websocket: + enabled: true + leafnodes: + enabled: true monitor: enabled: false - - statefulSet: - merge: - spec: - replicas: 3 - - podTemplate: - topologySpreadConstraints: - kubernetes.io/hostname: - maxSkew: 1 - whenUnsatisfiable: DoNotSchedule + mqtt: + enabled: false config: jetstream: @@ -474,23 +467,107 @@ nats-publisher: dir: /data pvc: enabled: true - size: 50Gi - storageClassName: standard - merge: - domain: "publisher" + size: 100Gi + storageClassName: "gp3-generic" leafnodes: enabled: true port: 7422 - remotes: - - url: "nats://nats-core:7422" + merge: + remotes: + - urls: ["nats-leaf://admin:admin@fuel-streams-nats-core:7422"] + account: ADMIN + + websocket: + enabled: true + port: 8443 + # This is just enable if the natsExternalService is enabled + # and the DNS is set to the correct value + tls: + enabled: true + dir: /etc/nats-certs/websocket + cert: tls.crt + key: tls.key + secretName: fuel-streams-nats-tls + merge: + no_tls: false + same_origin: false + compression: false + handshake_timeout: "20s" + no_auth_user: default_user monitor: enabled: false port: 8222 merge: + max_payload: << 32MiB >> jetstream: - max_file_store: << 50GiB >> - max_memory_store: << 3072MiB >> - max_payload: << 8MiB >> + domain: CLIENT + sync_interval: << 30s >> + max_outstanding_catchup: << 512MiB >> + max_file_store: << 100GiB >> + max_memory_store: << 7GiB >> + system_account: SYS + $include: auth.conf + + configMap: + merge: + $tplYaml: | + {{- include "nats-accounts" . | nindent 8 }} + +# ------------------------------------------------------------------------------------------------- +# WebServer configuration +# ------------------------------------------------------------------------------------------------- + +webserver: + enabled: false + port: 8443 + + image: + repository: fuel-streams-webserver + pullPolicy: Never + tag: "latest" + + config: + replicaCount: 1 + labels: {} + annotations: {} + podAnnotations: {} + nodeSelector: {} + tolerations: [] + affinity: {} + imagePullSecrets: [] + ports: [] + livenessProbe: {} + readinessProbe: {} + startupProbe: {} + securityContext: {} + containerSecurityContext: {} + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 500m + memory: 256Mi + + autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 5 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + percentValue: 100 + periodSeconds: 15 + scaleUp: + stabilizationWindowSeconds: 0 + percentValue: 100 + podValue: 4 + periodSeconds: 15 + + env: + PORT: 8443 diff --git a/cluster/docker/fuel-core.Dockerfile b/cluster/docker/fuel-core.Dockerfile new file mode 100644 index 00000000..0ec3f52b --- /dev/null +++ b/cluster/docker/fuel-core.Dockerfile @@ -0,0 +1,84 @@ +# Stage 1: Build +FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx +FROM --platform=$BUILDPLATFORM rust:1.81.0 AS chef + +# Add package name as build argument +ARG PACKAGE_NAME +ARG TARGETPLATFORM + +RUN cargo install cargo-chef && rustup target add wasm32-unknown-unknown +WORKDIR /build/ + +COPY --from=xx / / + +# hadolint ignore=DL3008 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + lld \ + clang \ + libclang-dev \ + && xx-apt-get update \ + && xx-apt-get install -y libc6-dev g++ binutils \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + +FROM chef AS planner +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + + +FROM chef AS builder +ARG PACKAGE_NAME +ARG DEBUG_SYMBOLS=false +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true +ENV CARGO_PROFILE_RELEASE_DEBUG=$DEBUG_SYMBOLS +COPY --from=planner /build/recipe.json recipe.json +RUN echo $CARGO_PROFILE_RELEASE_DEBUG +# Build our project dependencies, not our application! +RUN \ + --mount=type=cache,target=/usr/local/cargo/registry/index \ + --mount=type=cache,target=/usr/local/cargo/registry/cache \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/build/target \ + xx-cargo chef cook --release --no-default-features -p ${PACKAGE_NAME} --recipe-path recipe.json +# Up to this point, if our dependency tree stays the same, +# all layers should be cached. +COPY . . +# build application +RUN \ + --mount=type=cache,target=/usr/local/cargo/registry/index \ + --mount=type=cache,target=/usr/local/cargo/registry/cache \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/build/target \ + xx-cargo build --release --no-default-features -p ${PACKAGE_NAME} \ + && xx-verify ./target/$(xx-cargo --print-target-triple)/release/${PACKAGE_NAME} \ + && cp ./target/$(xx-cargo --print-target-triple)/release/${PACKAGE_NAME} /root/${PACKAGE_NAME} \ + && cp ./target/$(xx-cargo --print-target-triple)/release/${PACKAGE_NAME}.d /root/${PACKAGE_NAME}.d + +# Stage 2: Run +FROM ubuntu:22.04 AS run + +ARG PACKAGE_NAME +ARG PORT=4000 +ARG P2P_PORT=30333 +ENV IP="${IP}" +ENV PORT="${PORT}" + +WORKDIR /usr/src + +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends ca-certificates curl \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /root/${PACKAGE_NAME} . +COPY --from=builder /root/${PACKAGE_NAME}.d . + +COPY /cluster/chain-config ./chain-config +EXPOSE ${PORT} +EXPOSE ${P2P_PORT} + +ENTRYPOINT ["./${PACKAGE_NAME}"] diff --git a/cluster/docker/fuel-streams-publisher.Dockerfile b/cluster/docker/fuel-streams-publisher.Dockerfile deleted file mode 100644 index a93014e2..00000000 --- a/cluster/docker/fuel-streams-publisher.Dockerfile +++ /dev/null @@ -1,131 +0,0 @@ -# Stage 1: Build -FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx -FROM --platform=$BUILDPLATFORM rust:1.81.0 AS chef - -ARG TARGETPLATFORM -RUN cargo install cargo-chef && rustup target add wasm32-unknown-unknown -WORKDIR /build/ - -COPY --from=xx / / - -# hadolint ignore=DL3008 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - lld \ - clang \ - libclang-dev \ - && xx-apt-get update \ - && xx-apt-get install -y libc6-dev g++ binutils \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - - -FROM chef AS planner -ENV CARGO_NET_GIT_FETCH_WITH_CLI=true -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - - -FROM chef AS builder -ARG DEBUG_SYMBOLS=false -ENV CARGO_NET_GIT_FETCH_WITH_CLI=true -ENV CARGO_PROFILE_RELEASE_DEBUG=$DEBUG_SYMBOLS -COPY --from=planner /build/recipe.json recipe.json -RUN echo $CARGO_PROFILE_RELEASE_DEBUG -# Build our project dependencies, not our application! -RUN \ - --mount=type=cache,target=/usr/local/cargo/registry/index \ - --mount=type=cache,target=/usr/local/cargo/registry/cache \ - --mount=type=cache,target=/usr/local/cargo/git/db \ - --mount=type=cache,target=/build/target \ - xx-cargo chef cook --release --no-default-features -p fuel-streams-publisher --recipe-path recipe.json -# Up to this point, if our dependency tree stays the same, -# all layers should be cached. -COPY . . -# build application -RUN \ - --mount=type=cache,target=/usr/local/cargo/registry/index \ - --mount=type=cache,target=/usr/local/cargo/registry/cache \ - --mount=type=cache,target=/usr/local/cargo/git/db \ - --mount=type=cache,target=/build/target \ - xx-cargo build --release --no-default-features -p fuel-streams-publisher \ - && xx-verify ./target/$(xx-cargo --print-target-triple)/release/fuel-streams-publisher \ - && cp ./target/$(xx-cargo --print-target-triple)/release/fuel-streams-publisher /root/fuel-streams-publisher \ - && cp ./target/$(xx-cargo --print-target-triple)/release/fuel-streams-publisher.d /root/fuel-streams-publisher.d - -# Stage 2: Run -FROM ubuntu:22.04 AS run - -ARG IP=0.0.0.0 -ARG PORT=4000 -ARG TELEMETRY_PORT=8080 -ARG P2P_PORT=30333 -ARG DB_PATH=/mnt/db/ -ARG POA_INSTANT=false -ARG RELAYER_LOG_PAGE_SIZE=2000 -ARG SERVICE_NAME="NATS Publisher Node" -ARG SYNC_HEADER_BATCH_SIZE=100 -ARG RESERVED_NODES=/dns4/p2p-testnet.fuel.network/tcp/30333/p2p/16Uiu2HAmDxoChB7AheKNvCVpD4PHJwuDGn8rifMBEHmEynGHvHrf - -ENV IP=$IP -ENV PORT=$PORT -ENV TELEMETRY_PORT=$TELEMETRY_PORT -ENV DB_PATH=$DB_PATH -ENV POA_INSTANT=false -ENV RELAYER_LOG_PAGE_SIZE=$RELAYER_LOG_PAGE_SIZE -ENV SERVICE_NAME=$SERVICE_NAME -ENV SYNC_HEADER_BATCH_SIZE=$SYNC_HEADER_BATCH_SIZE -ENV RESERVED_NODES=$RESERVED_NODES -ENV HISTORICAL=false - -ENV KEYPAIR= -ENV RELAYER= -ENV RELAYER_V2_LISTENING_CONTRACTS= -ENV RELAYER_DA_DEPLOY_HEIGHT= -ENV CHAIN_CONFIG= -ENV NATS_URL= -ENV USE_PUBLISHER_METRICS= -ENV USE_ELASTIC_LOGGING= - -WORKDIR /usr/src - -RUN apt-get update -y \ - && apt-get install -y --no-install-recommends ca-certificates curl \ - # Clean up - && apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - -COPY --from=builder /root/fuel-streams-publisher . -COPY --from=builder /root/fuel-streams-publisher.d . - -COPY /cluster/chain-config ./chain-config -EXPOSE ${PORT} -EXPOSE ${P2P_PORT} -EXPOSE ${TELEMETRY_PORT} - -# https://stackoverflow.com/a/44671685 -# https://stackoverflow.com/a/40454758 -# hadolint ignore=DL3025 -CMD exec ./fuel-streams-publisher \ - --service-name "${SERVICE_NAME}" \ - --nats-url $NATS_URL \ - --keypair $KEYPAIR \ - --relayer $RELAYER \ - --ip $IP \ - --port $PORT \ - --telemetry-port $TELEMETRY_PORT \ - --peering-port $P2P_PORT \ - --db-path "${DB_PATH}" \ - --utxo-validation \ - --poa-instant $POA_INSTANT \ - --snapshot ./chain-config/${CHAIN_CONFIG} \ - --enable-p2p \ - --reserved-nodes $RESERVED_NODES \ - --sync-header-batch-size $SYNC_HEADER_BATCH_SIZE \ - --enable-relayer \ - --relayer-v2-listening-contracts $RELAYER_V2_LISTENING_CONTRACTS \ - --relayer-da-deploy-height $RELAYER_DA_DEPLOY_HEIGHT \ - --relayer-log-page-size $RELAYER_LOG_PAGE_SIZE \ - --sync-block-stream-buffer-size 30 \ - $([ "$HISTORICAL" = "true" ] && echo "--historical") diff --git a/cluster/docker/nats.conf b/cluster/docker/nats.conf index 783a0450..cf5af290 100644 --- a/cluster/docker/nats.conf +++ b/cluster/docker/nats.conf @@ -1,52 +1,46 @@ +# Core settings port = 4222 http_port = 8222 -server_name = "fuel-nats-server" -authorization = { - timeout = 5 - ADMIN = { - publish = ">" - subscribe = ">" - } - default_permissions = { - subscribe = ">" - publish = { - deny = [ - "*.blocks.>", - "*.transactions.>", - "*.inputs.>", - "*.outputs.>", - "*.receipts.>", - "*.logs.>", - "*.utxos.>", - "$JS.API.STREAM.CREATE.>", - "$JS.API.STREAM.UPDATE.>", - "$JS.API.STREAM.DELETE.>", - "$JS.API.STREAM.PURGE.>", - "$JS.API.STREAM.RESTORE.>", - "$JS.API.STREAM.MSG.DELETE.>", - "$JS.API.CONSUMER.DURABLE.CREATE.>", - ] - } - } - users = [ - { user = admin, password = $NATS_ADMIN_PASS, permissions = $ADMIN }, - { user = default_user } - ] +# Jetstream settings +jetstream { + max_file_store = 536870912000 # 500GB + max_memory_store = 7516192768 # ~7.1GB } -jetstream = { - max_file_store = 21474836480 -} +# Max payload setting +max_payload = 8388608 # 8MB -max_payload = 8388608 - -websocket = { - port = 8443 - no_tls = true - same_origin = false - allowed_origins = [] - compression = false - handshake_timeout = "10s" - no_auth_user = default_user +# Authorization settings +authorization { + timeout = 5 + ADMIN = { + publish = ">" + subscribe = ">" + } + default_permissions = { + subscribe = ">" + publish = { + deny = [ + "*.blocks.>", + "*.transactions.>", + "*.inputs.>", + "*.outputs.>", + "*.receipts.>", + "*.logs.>", + "*.utxos.>", + "$JS.API.STREAM.CREATE.>", + "$JS.API.STREAM.UPDATE.>", + "$JS.API.STREAM.DELETE.>", + "$JS.API.STREAM.PURGE.>", + "$JS.API.STREAM.RESTORE.>", + "$JS.API.STREAM.MSG.DELETE.>", + "$JS.API.CONSUMER.DURABLE.CREATE.>" + ] + } + } + users = [ + { user = admin, password = $NATS_ADMIN_PASS, permissions = $ADMIN } + { user = default_user } + ] } diff --git a/cluster/docker/sv-consumer.Dockerfile b/cluster/docker/sv-consumer.Dockerfile new file mode 100644 index 00000000..533e8459 --- /dev/null +++ b/cluster/docker/sv-consumer.Dockerfile @@ -0,0 +1,75 @@ +# Stage 1: Build +FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx +FROM --platform=$BUILDPLATFORM rust:1.81.0 AS chef + +ARG TARGETPLATFORM +RUN cargo install cargo-chef && rustup target add wasm32-unknown-unknown +WORKDIR /build/ + +COPY --from=xx / / + +# hadolint ignore=DL3008 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + lld \ + clang \ + libclang-dev \ + && xx-apt-get update \ + && xx-apt-get install -y libc6-dev g++ binutils \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + +FROM chef AS planner +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + + +FROM chef AS builder +ARG DEBUG_SYMBOLS=false +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true +ENV CARGO_PROFILE_RELEASE_DEBUG=$DEBUG_SYMBOLS +COPY --from=planner /build/recipe.json recipe.json +RUN echo $CARGO_PROFILE_RELEASE_DEBUG +# Build our project dependencies, not our application! +RUN \ + --mount=type=cache,target=/usr/local/cargo/registry/index \ + --mount=type=cache,target=/usr/local/cargo/registry/cache \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/build/target \ + xx-cargo chef cook --release --no-default-features -p sv-consumer --recipe-path recipe.json +# Up to this point, if our dependency tree stays the same, +# all layers should be cached. +COPY . . +# build application +RUN \ + --mount=type=cache,target=/usr/local/cargo/registry/index \ + --mount=type=cache,target=/usr/local/cargo/registry/cache \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/build/target \ + xx-cargo build --release --no-default-features -p sv-consumer \ + && xx-verify ./target/$(xx-cargo --print-target-triple)/release/sv-consumer \ + && cp ./target/$(xx-cargo --print-target-triple)/release/sv-consumer /root/sv-consumer \ + && cp ./target/$(xx-cargo --print-target-triple)/release/sv-consumer.d /root/sv-consumer.d + +# Stage 2: Run +FROM ubuntu:22.04 AS run + +ARG PORT=8080 +ENV PORT=$PORT +WORKDIR /usr/src + +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends ca-certificates curl \ + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /root/sv-consumer . +COPY --from=builder /root/sv-consumer.d . + +EXPOSE ${PORT} + +ENTRYPOINT ["./sv-consumer"] diff --git a/cluster/scripts/build_docker.sh b/cluster/scripts/build_docker.sh new file mode 100755 index 00000000..ef274b27 --- /dev/null +++ b/cluster/scripts/build_docker.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Remove the -g flag from set +set -euo pipefail + +# Help/Usage function +usage() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Build a Docker image using specified parameters. + +Options: + --image-name Name for the Docker image (default: fuel-streams-publisher) + --dockerfile Path to Dockerfile (default: cluster/docker/fuel-core.Dockerfile) + --build-args Additional Docker build arguments (optional) + -h, --help Show this help message + +Environment variables: + TAG Docker image tag (default: latest) + DOCKER_HOST Docker daemon socket (optional) + +Examples: + $(basename "$0") --image-name my-image --dockerfile ./Dockerfile + $(basename "$0") --image-name my-image --dockerfile ./Dockerfile --build-args "--build-arg KEY=VALUE" +EOF + exit 1 +} + +# Show help if no arguments or help flag +if [[ $# -eq 0 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + usage +fi + +# Default values +IMAGE_NAME="fuel-streams-publisher" +DOCKERFILE="cluster/docker/fuel-core.Dockerfile" +BUILD_ARGS="" +TAG=${TAG:-"latest"} # From environment variable with default + +# Parse named arguments +while [[ $# -gt 0 ]]; do + case $1 in + --image-name) + IMAGE_NAME="$2" + shift 2 + ;; + --dockerfile) + DOCKERFILE="$2" + shift 2 + ;; + --build-args) + BUILD_ARGS="$2" + shift 2 + ;; + *) + echo "Error: Unknown argument '$1'" + usage + ;; + esac +done + +# Validate required files exist +if [[ ! -f "$DOCKERFILE" ]]; then + echo "Error: Dockerfile not found at $DOCKERFILE" + exit 1 +fi + +# Ensure we're using minikube's docker daemon +if [[ -n "${DOCKER_HOST:-}" ]]; then + echo "Using provided DOCKER_HOST: $DOCKER_HOST" +else + eval $(minikube docker-env) +fi + +echo "Building image ${IMAGE_NAME}:${TAG} using ${DOCKERFILE}" +echo "Build args: ${BUILD_ARGS}" + +# Build the docker image with build args if provided +if [[ -n "${BUILD_ARGS}" ]]; then + docker build ${BUILD_ARGS} -t "${IMAGE_NAME}:${TAG}" -f "${DOCKERFILE}" . +else + docker build -t "${IMAGE_NAME}:${TAG}" -f "${DOCKERFILE}" . +fi diff --git a/cluster/scripts/build_publisher.sh b/cluster/scripts/build_publisher.sh deleted file mode 100755 index 0fe43d4b..00000000 --- a/cluster/scripts/build_publisher.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# Use environment variables provided by Tilt if available -IMAGE_NAME=${EXPECTED_IMAGE:-"fuel-streams-publisher"} -TAG=${EXPECTED_TAG:-"latest"} -DOCKERFILE="cluster/docker/fuel-streams-publisher.Dockerfile" - -# Ensure we're using minikube's docker daemon if not already set -if [ -z "${DOCKER_HOST:-}" ]; then - eval $(minikube docker-env) -fi - -# Build the docker image -docker build -t ${IMAGE_NAME}:${TAG} -f ${DOCKERFILE} . diff --git a/cluster/scripts/gen_env_secret.sh b/cluster/scripts/gen_env_secret.sh index df0680d3..2d4a1e6c 100755 --- a/cluster/scripts/gen_env_secret.sh +++ b/cluster/scripts/gen_env_secret.sh @@ -4,7 +4,7 @@ source .env # Generate the YAML configuration -cat <cluster/charts/fuel-streams/values-publisher-secrets.yaml +cat << EOF > cluster/charts/fuel-streams/values-publisher-secrets.yaml publisher: extraEnv: - name: RELAYER diff --git a/cluster/scripts/setup_k8s.sh b/cluster/scripts/setup_k8s.sh index bb7537e8..791c8595 100755 --- a/cluster/scripts/setup_k8s.sh +++ b/cluster/scripts/setup_k8s.sh @@ -4,13 +4,13 @@ set -euo pipefail # Parse command line arguments -NAMESPACE="${1:-fuel-streams}" # Use first argument, default to "fuel-streams" if not provided +NAMESPACE="${1:-fuel-streams}" # Use first argument, default to "fuel-streams" if not provided # Configure namespace and context echo -e "\n\033[1;33mConfiguring ${NAMESPACE} namespace and context:\033[0m" # Check if namespace exists -if kubectl get namespace ${NAMESPACE} &>/dev/null; then +if kubectl get namespace ${NAMESPACE} &> /dev/null; then echo "Namespace ${NAMESPACE} already exists" else echo "Creating namespace ${NAMESPACE}..." diff --git a/cluster/scripts/setup_minikube.sh b/cluster/scripts/setup_minikube.sh index 0c01374a..55c63555 100755 --- a/cluster/scripts/setup_minikube.sh +++ b/cluster/scripts/setup_minikube.sh @@ -4,12 +4,12 @@ set -euo pipefail # Check if minikube is installed -if ! command -v minikube &>/dev/null; then +if ! command -v minikube &> /dev/null; then echo "Installing minikube..." - sudo curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && - sudo chmod +x minikube && - sudo cp minikube /usr/local/bin/ && - sudo rm minikube + sudo curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \ + && sudo chmod +x minikube \ + && sudo cp minikube /usr/local/bin/ \ + && sudo rm minikube else echo "minikube is already installed" fi @@ -17,13 +17,9 @@ fi # Delete any existing minikube cluster minikube delete -# Default values for resources -DEFAULT_DISK_SIZE='50000mb' -DEFAULT_MEMORY='12000mb' - -# Get parameters with defaults -DISK_SIZE=${1:-$DEFAULT_DISK_SIZE} -MEMORY=${2:-$DEFAULT_MEMORY} +# Set disk and memory size, using defaults if not provided +DISK_SIZE=${1:-'50000mb'} +MEMORY=${2:-'12000mb'} # Start minikube with specified resources minikube start \ diff --git a/crates/fuel-streams-core/Cargo.toml b/crates/fuel-streams-core/Cargo.toml index 1ff4045f..69a28916 100644 --- a/crates/fuel-streams-core/Cargo.toml +++ b/crates/fuel-streams-core/Cargo.toml @@ -11,15 +11,29 @@ version = { workspace = true } rust-version = { workspace = true } [dependencies] +anyhow = { workspace = true } async-nats = { workspace = true } async-trait = { workspace = true } chrono = { workspace = true } clap = { workspace = true } displaydoc = { workspace = true } dotenvy = { workspace = true } -fuel-core-client = { workspace = true } +fuel-core = { workspace = true, default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", + "test-helpers", +] } +fuel-core-bin = { workspace = true, default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", +] } +fuel-core-client = { workspace = true, default-features = false, features = ["std"] } fuel-core-importer = { workspace = true } -fuel-core-types = { workspace = true } +fuel-core-services = { workspace = true, default-features = false, features = ["test-helpers"] } +fuel-core-storage = { workspace = true } +fuel-core-types = { workspace = true, default-features = false, features = ["std", "serde"] } fuel-data-parser = { workspace = true } fuel-streams-macros = { workspace = true } futures = { workspace = true } @@ -27,6 +41,7 @@ hex = { workspace = true } pretty_assertions = { workspace = true, optional = true } rand = { workspace = true } serde = { workspace = true } +serde_json = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } diff --git a/crates/fuel-streams-publisher/src/publisher/fuel_core_like.rs b/crates/fuel-streams-core/src/fuel_core_like.rs similarity index 92% rename from crates/fuel-streams-publisher/src/publisher/fuel_core_like.rs rename to crates/fuel-streams-core/src/fuel_core_like.rs index 921cf743..93a395a7 100644 --- a/crates/fuel-streams-publisher/src/publisher/fuel_core_like.rs +++ b/crates/fuel-streams-core/src/fuel_core_like.rs @@ -2,15 +2,8 @@ use std::{sync::Arc, time::Duration}; use fuel_core::{ combined_database::CombinedDatabase, - database::{ - database_description::{on_chain::OnChain, DatabaseHeight}, - Database, - }, + database::{database_description::on_chain::OnChain, Database}, fuel_core_graphql_api::ports::DatabaseBlocks, - state::{ - generic_database::GenericDatabase, - iterable_key_value_view::IterableKeyValueViewWrapper, - }, }; use fuel_core_bin::FuelService; use fuel_core_importer::ports::ImporterDatabase; @@ -19,14 +12,9 @@ use fuel_core_types::{ blockchain::consensus::{Consensus, Sealed}, fuel_types::BlockHeight, }; -use fuel_streams_core::types::*; use tokio::{sync::broadcast::Receiver, time::sleep}; -pub type OffchainDatabase = GenericDatabase< - IterableKeyValueViewWrapper< - fuel_core::fuel_core_graphql_api::storage::Column, - >, ->; +use crate::types::*; /// Interface for `fuel-core` related logic. /// This was introduced to simplify mocking and testing the `fuel-streams-publisher` crate. @@ -42,6 +30,7 @@ pub trait FuelCoreLike: Sync + Send { fn base_asset_id(&self) -> &FuelCoreAssetId; fn chain_id(&self) -> &FuelCoreChainId; + fn fuel_service(&self) -> &FuelService; fn database(&self) -> &CombinedDatabase; fn onchain_database(&self) -> &Database { @@ -60,14 +49,19 @@ pub trait FuelCoreLike: Sync + Send { &self, ) -> Receiver; - fn get_latest_block_height(&self) -> anyhow::Result { + fn get_latest_block_height(&self) -> anyhow::Result { Ok(self .onchain_database() .latest_block_height()? - .map(|h| h.as_u64()) + .map(|h| *h) .unwrap_or_default()) } + fn get_tx_status( + &self, + tx_id: &FuelCoreBytes32, + ) -> anyhow::Result>; + fn get_receipts( &self, tx_id: &FuelCoreBytes32, @@ -198,6 +192,10 @@ impl FuelCoreLike for FuelCore { Ok(()) } + fn fuel_service(&self) -> &FuelService { + &self.fuel_service + } + async fn stop(&self) { if matches!( self.fuel_service.state(), @@ -262,12 +260,18 @@ impl FuelCoreLike for FuelCore { .subscribe() } + fn get_tx_status( + &self, + tx_id: &FuelCoreBytes32, + ) -> anyhow::Result> { + Ok(self.offchain_database()?.get_tx_status(tx_id)?) + } + fn get_receipts( &self, tx_id: &FuelCoreBytes32, ) -> anyhow::Result>> { let receipts = self - .offchain_database()? .get_tx_status(tx_id)? .map(|status| match &status { FuelCoreTransactionStatus::Success { receipts, .. } diff --git a/crates/fuel-streams-core/src/fuel_core_types.rs b/crates/fuel-streams-core/src/fuel_core_types.rs index d42f0009..b5461427 100644 --- a/crates/fuel-streams-core/src/fuel_core_types.rs +++ b/crates/fuel-streams-core/src/fuel_core_types.rs @@ -1,5 +1,7 @@ -/// FuelCore Types -/// Allows flexilibity of aggregating and transforming them for different payload types +use fuel_core::state::{ + generic_database::GenericDatabase, + iterable_key_value_view::IterableKeyValueViewWrapper, +}; pub use fuel_core_client::client::schema::Tai64Timestamp as FuelCoreTai64Timestamp; pub use fuel_core_importer::ImporterResult as FuelCoreImporterResult; pub use fuel_core_types::{ @@ -29,7 +31,9 @@ pub use fuel_core_types::{ Input as FuelCoreInput, MessageId as FuelCoreMessageId, Output as FuelCoreOutput, + PanicInstruction as FuelCorePanicInstruction, Receipt as FuelCoreReceipt, + ScriptExecutionResult as FuelCoreScriptExecutionResult, StorageSlot as FuelCoreStorageSlot, Transaction as FuelCoreTransaction, TxId as FuelCoreTxId, @@ -52,3 +56,9 @@ pub use fuel_core_types::{ }, tai64::Tai64 as FuelCoreTai64, }; + +pub type OffchainDatabase = GenericDatabase< + IterableKeyValueViewWrapper< + fuel_core::fuel_core_graphql_api::storage::Column, + >, +>; diff --git a/crates/fuel-streams-core/src/inputs/types.rs b/crates/fuel-streams-core/src/inputs/types.rs index fcd5b01d..91ff8c1b 100644 --- a/crates/fuel-streams-core/src/inputs/types.rs +++ b/crates/fuel-streams-core/src/inputs/types.rs @@ -1,3 +1,5 @@ +use fuel_core_types::fuel_crypto; + use crate::types::*; // Input enum @@ -171,3 +173,24 @@ pub struct InputMessage { pub sender: Address, pub witness_index: u16, } + +impl InputMessage { + pub fn compute_message_id(&self) -> MessageId { + let hasher = fuel_crypto::Hasher::default() + .chain(self.sender.as_ref()) + .chain(self.recipient.as_ref()) + .chain(self.nonce.as_ref()) + .chain(self.amount.to_be_bytes()) + .chain(self.data.as_ref()); + + (*hasher.finalize()).into() + } + + pub fn computed_utxo_id(&self) -> UtxoId { + let message_id = self.compute_message_id(); + UtxoId { + tx_id: Bytes32::from(message_id), + output_index: 0, + } + } +} diff --git a/crates/fuel-streams-core/src/lib.rs b/crates/fuel-streams-core/src/lib.rs index 040bae8d..bea378e9 100644 --- a/crates/fuel-streams-core/src/lib.rs +++ b/crates/fuel-streams-core/src/lib.rs @@ -13,6 +13,7 @@ pub mod stream; pub mod subjects; +pub mod fuel_core_like; mod fuel_core_types; mod primitive_types; pub mod types; @@ -20,7 +21,14 @@ pub mod types; pub use stream::*; pub mod prelude { + #[allow(unused_imports)] pub use fuel_streams_macros::subject::*; - pub use crate::{nats::*, stream::*, subjects::*, types::*}; + pub use crate::{ + fuel_core_like::*, + nats::*, + stream::*, + subjects::*, + types::*, + }; } diff --git a/crates/fuel-streams-core/src/logs/types.rs b/crates/fuel-streams-core/src/logs/types.rs index 4fdb7473..927216d4 100644 --- a/crates/fuel-streams-core/src/logs/types.rs +++ b/crates/fuel-streams-core/src/logs/types.rs @@ -27,94 +27,30 @@ pub enum Log { }, } -impl From for Log { - fn from(value: FuelCoreReceipt) -> Self { +impl From for Log { + fn from(value: Receipt) -> Self { match value { - FuelCoreReceipt::Log { - id, - ra, - rb, - rc, - rd, - pc, - is, - } => Log::WithoutData { - id: id.into(), - ra, - rb, - rc, - rd, - pc, - is, + Receipt::Log(log) => Log::WithoutData { + id: log.id, + ra: log.ra, + rb: log.rb, + rc: log.rc, + rd: log.rd, + pc: log.pc, + is: log.is, }, - FuelCoreReceipt::LogData { - id, - ra, - rb, - ptr, - len, - digest, - pc, - is, - data, - } => Log::WithData { - id: id.into(), - ra, - rb, - ptr, - len, - digest: digest.into(), - pc, - is, - data, + Receipt::LogData(log) => Log::WithData { + id: log.id, + ra: log.ra, + rb: log.rb, + ptr: log.ptr, + len: log.len, + digest: log.digest, + pc: log.pc, + is: log.is, + data: log.data, }, _ => panic!("Invalid receipt type"), } } } - -/// Introduced majorly allow delegating serialization and deserialization to `fuel-core`'s Receipt -impl From for FuelCoreReceipt { - fn from(log: Log) -> FuelCoreReceipt { - match log { - Log::WithoutData { - id, - ra, - rb, - rc, - rd, - pc, - is, - } => FuelCoreReceipt::Log { - id: id.into(), - ra, - rb, - rc, - rd, - pc, - is, - }, - Log::WithData { - id, - ra, - rb, - ptr, - len, - digest, - pc, - is, - data, - } => FuelCoreReceipt::LogData { - id: id.into(), - ra, - rb, - ptr, - len, - digest: digest.into(), - pc, - is, - data, - }, - } - } -} diff --git a/crates/fuel-streams-core/src/nats/nats_client.rs b/crates/fuel-streams-core/src/nats/nats_client.rs index 3daae364..294e9a1d 100644 --- a/crates/fuel-streams-core/src/nats/nats_client.rs +++ b/crates/fuel-streams-core/src/nats/nats_client.rs @@ -64,7 +64,13 @@ impl NatsClient { source: e, } })?; - let jetstream = async_nats::jetstream::new(nats_client.to_owned()); + + let jetstream = match opts.domain.clone() { + None => async_nats::jetstream::new(nats_client.clone()), + Some(domain) => { + async_nats::jetstream::with_domain(nats_client.clone(), domain) + } + }; info!("Connected to NATS server at {}", url); Ok(Self { diff --git a/crates/fuel-streams-core/src/nats/nats_client_opts.rs b/crates/fuel-streams-core/src/nats/nats_client_opts.rs index 139ae32f..ffef16fa 100644 --- a/crates/fuel-streams-core/src/nats/nats_client_opts.rs +++ b/crates/fuel-streams-core/src/nats/nats_client_opts.rs @@ -72,6 +72,12 @@ pub struct NatsClientOpts { pub(crate) namespace: NatsNamespace, /// The timeout in seconds for NATS operations. pub(crate) timeout_secs: u64, + /// The domain to use for the NATS client. + pub(crate) domain: Option, + /// The user to use for the NATS client. + pub(crate) user: Option, + /// The password to use for the NATS client. + pub(crate) password: Option, } impl NatsClientOpts { @@ -81,6 +87,9 @@ impl NatsClientOpts { role: NatsUserRole::default(), namespace: NatsNamespace::default(), timeout_secs: 5, + domain: None, + user: None, + password: None, } } @@ -107,6 +116,27 @@ impl NatsClientOpts { } } + pub fn with_domain(self, domain: String) -> Self { + Self { + domain: Some(domain), + ..self + } + } + + pub fn with_user(self, user: String) -> Self { + Self { + user: Some(user), + ..self + } + } + + pub fn with_password(self, password: String) -> Self { + Self { + password: Some(password), + ..self + } + } + pub fn with_custom_url(self, url: String) -> Self { Self { url, ..self } } @@ -144,6 +174,11 @@ impl NatsClientOpts { } }; + let (user, pass) = match (self.user.clone(), self.password.clone()) { + (Some(user), Some(pass)) => (Some(user), Some(pass)), + _ => (user, pass), + }; + match (user, pass) { (Some(user), Some(pass)) => { ConnectOptions::with_user_and_password(user, pass) diff --git a/crates/fuel-streams-core/src/outputs/types.rs b/crates/fuel-streams-core/src/outputs/types.rs index 607bcd72..ddedd9a0 100644 --- a/crates/fuel-streams-core/src/outputs/types.rs +++ b/crates/fuel-streams-core/src/outputs/types.rs @@ -4,11 +4,11 @@ use crate::types::*; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum Output { - Coin(CoinOutput), + Coin(OutputCoin), Contract(OutputContract), - Change(ChangeOutput), - Variable(VariableOutput), - ContractCreated(ContractCreated), + Change(OutputChange), + Variable(OutputVariable), + ContractCreated(OutputContractCreated), } impl From<&FuelCoreOutput> for Output { @@ -18,7 +18,7 @@ impl From<&FuelCoreOutput> for Output { amount, asset_id, to, - } => Output::Coin(CoinOutput { + } => Output::Coin(OutputCoin { amount: *amount, asset_id: asset_id.into(), to: to.into(), @@ -30,7 +30,7 @@ impl From<&FuelCoreOutput> for Output { amount, asset_id, to, - } => Output::Change(ChangeOutput { + } => Output::Change(OutputChange { amount: *amount, asset_id: asset_id.into(), to: to.into(), @@ -39,7 +39,7 @@ impl From<&FuelCoreOutput> for Output { amount, asset_id, to, - } => Output::Variable(VariableOutput { + } => Output::Variable(OutputVariable { amount: *amount, asset_id: asset_id.into(), to: to.into(), @@ -47,7 +47,7 @@ impl From<&FuelCoreOutput> for Output { FuelCoreOutput::ContractCreated { contract_id, state_root, - } => Output::ContractCreated(ContractCreated { + } => Output::ContractCreated(OutputContractCreated { contract_id: contract_id.into(), state_root: state_root.into(), }), @@ -57,7 +57,7 @@ impl From<&FuelCoreOutput> for Output { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct CoinOutput { +pub struct OutputCoin { pub amount: u64, pub asset_id: AssetId, pub to: Address, @@ -65,7 +65,7 @@ pub struct CoinOutput { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ChangeOutput { +pub struct OutputChange { pub amount: u64, pub asset_id: AssetId, pub to: Address, @@ -73,7 +73,7 @@ pub struct ChangeOutput { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct VariableOutput { +pub struct OutputVariable { pub amount: u64, pub asset_id: AssetId, pub to: Address, @@ -99,7 +99,7 @@ impl From<&FuelCoreOutputContract> for OutputContract { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ContractCreated { - contract_id: ContractId, - state_root: Bytes32, +pub struct OutputContractCreated { + pub contract_id: ContractId, + pub state_root: Bytes32, } diff --git a/crates/fuel-streams-core/src/primitive_types.rs b/crates/fuel-streams-core/src/primitive_types.rs index 997b4221..158f23af 100644 --- a/crates/fuel-streams-core/src/primitive_types.rs +++ b/crates/fuel-streams-core/src/primitive_types.rs @@ -1,4 +1,8 @@ -use fuel_core_types::fuel_types; +use fuel_core_types::{ + fuel_asm::RawInstruction, + fuel_tx::PanicReason, + fuel_types, +}; pub use serde::{Deserialize, Serialize}; use crate::fuel_core_types::*; @@ -158,6 +162,58 @@ generate_byte_type_wrapper!(Salt, fuel_types::Salt, 32); generate_byte_type_wrapper!(MessageId, fuel_types::MessageId, 32); generate_byte_type_wrapper!(BlockId, fuel_types::Bytes32, 32); generate_byte_type_wrapper!(Signature, fuel_types::Bytes64, 64); +generate_byte_type_wrapper!(TxId, fuel_types::TxId, 32); + +/// Implements bidirectional conversions between `Bytes32` and a given type. +/// +/// This macro generates implementations of the `From` trait to convert: +/// - From `Bytes32` to the target type +/// - From a reference to `Bytes32` to the target type +/// - From the target type to `Bytes32` +/// - From a reference of the target type to `Bytes32` +/// +/// The target type must be a 32-byte type that can be converted to/from `[u8; 32]`. +/// +/// # Example +/// ```ignore +/// impl_bytes32_conversions!(ContractId); +/// ``` +macro_rules! impl_bytes32_conversions { + ($type:ty) => { + impl From for $type { + fn from(value: Bytes32) -> Self { + let bytes: [u8; 32] = value.0.into(); + <$type>::from(bytes) + } + } + impl From<&Bytes32> for $type { + fn from(value: &Bytes32) -> Self { + value.clone().into() + } + } + impl From<$type> for Bytes32 { + fn from(value: $type) -> Self { + let bytes: [u8; 32] = value.0.into(); + Bytes32::from(bytes) + } + } + impl From<&$type> for Bytes32 { + fn from(value: &$type) -> Self { + value.clone().into() + } + } + }; +} + +impl_bytes32_conversions!(MessageId); +impl_bytes32_conversions!(ContractId); +impl_bytes32_conversions!(AssetId); +impl_bytes32_conversions!(Address); +impl_bytes32_conversions!(BlobId); +impl_bytes32_conversions!(Nonce); +impl_bytes32_conversions!(Salt); +impl_bytes32_conversions!(BlockId); +impl_bytes32_conversions!(TxId); impl From for BlockId { fn from(value: FuelCoreBlockId) -> Self { @@ -165,18 +221,6 @@ impl From for BlockId { } } -impl From for MessageId { - fn from(value: Bytes32) -> Self { - let bytes: [u8; 32] = value.0.into(); - MessageId::from(bytes) - } -} -impl From<&Bytes32> for MessageId { - fn from(value: &Bytes32) -> Self { - value.clone().into() - } -} - #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct HexString(pub Vec); impl_hex_serde!(HexString); @@ -186,13 +230,26 @@ impl From<&[u8]> for HexString { HexString(value.to_vec()) } } - +impl From for HexString { + fn from(value: Bytes32) -> Self { + Self::from(value.0.as_ref()) + } +} +impl TryFrom for Bytes32 { + type Error = String; + fn try_from(value: HexString) -> Result { + let bytes: [u8; 32] = value + .0 + .try_into() + .map_err(|_| "Invalid length for Bytes32".to_string())?; + Ok(Bytes32::from(bytes)) + } +} impl std::fmt::Display for HexString { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "0x{}", hex::encode(&self.0)) } } - impl std::str::FromStr for HexString { type Err = String; fn from_str(s: &str) -> Result { @@ -200,6 +257,16 @@ impl std::str::FromStr for HexString { hex::decode(s).map(HexString).map_err(|e| e.to_string()) } } +impl AsRef<[u8]> for HexString { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} +impl HexString { + pub fn zeroed() -> Self { + HexString(vec![0u8; 32]) + } +} #[derive( Debug, @@ -230,22 +297,17 @@ impl From for TxPointer { } #[derive( - Debug, - Default, - Copy, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, + Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, )] #[serde(rename_all = "camelCase")] pub struct UtxoId { - tx_id: FuelCoreTxId, - output_index: u16, + pub tx_id: Bytes32, + pub output_index: u16, +} +impl From<&UtxoId> for HexString { + fn from(value: &UtxoId) -> Self { + value.to_owned().into() + } } impl From for UtxoId { fn from(value: FuelCoreUtxoId) -> Self { @@ -255,11 +317,67 @@ impl From for UtxoId { impl From<&FuelCoreUtxoId> for UtxoId { fn from(value: &FuelCoreUtxoId) -> Self { Self { - tx_id: *value.tx_id(), + tx_id: value.tx_id().into(), output_index: value.output_index(), } } } +impl From for HexString { + fn from(value: UtxoId) -> Self { + let mut bytes = Vec::with_capacity(34); + bytes.extend_from_slice(value.tx_id.0.as_ref()); + bytes.extend_from_slice(&value.output_index.to_be_bytes()); + HexString(bytes) + } +} + +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +pub struct PanicInstruction { + pub reason: PanicReason, + pub instruction: RawInstruction, +} +impl From for PanicInstruction { + fn from(value: FuelCorePanicInstruction) -> Self { + Self { + reason: value.reason().to_owned(), + instruction: value.instruction().to_owned(), + } + } +} + +#[derive( + Debug, + Copy, + Clone, + PartialEq, + Eq, + Hash, + Default, + serde::Serialize, + serde::Deserialize, +)] +#[repr(u64)] +pub enum ScriptExecutionResult { + Success, + Revert, + Panic, + // Generic failure case since any u64 is valid here + GenericFailure(u64), + #[default] + Unknown, +} +impl From for ScriptExecutionResult { + fn from(value: FuelCoreScriptExecutionResult) -> Self { + match value { + FuelCoreScriptExecutionResult::Success => Self::Success, + FuelCoreScriptExecutionResult::Revert => Self::Revert, + FuelCoreScriptExecutionResult::Panic => Self::Panic, + FuelCoreScriptExecutionResult::GenericFailure(value) => { + Self::GenericFailure(value) + } + } + } +} /// Macro to implement conversion from a type to `Bytes32`. /// diff --git a/crates/fuel-streams-core/src/receipts/types.rs b/crates/fuel-streams-core/src/receipts/types.rs index b32e654e..565185d8 100644 --- a/crates/fuel-streams-core/src/receipts/types.rs +++ b/crates/fuel-streams-core/src/receipts/types.rs @@ -1,106 +1,365 @@ +use fuel_core_types::fuel_asm::Word; +use serde::{self, Deserialize, Serialize}; + use crate::types::*; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum Receipt { + Call(CallReceipt), + Return(ReturnReceipt), + ReturnData(ReturnDataReceipt), + Panic(PanicReceipt), + Revert(RevertReceipt), + Log(LogReceipt), + LogData(LogDataReceipt), + Transfer(TransferReceipt), + TransferOut(TransferOutReceipt), + ScriptResult(ScriptResultReceipt), + MessageOut(MessageOutReceipt), + Mint(MintReceipt), + Burn(BurnReceipt), +} + +// Individual Receipt Types +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CallReceipt { + pub id: ContractId, + pub to: ContractId, + pub amount: Word, + pub asset_id: AssetId, + pub gas: Word, + pub param1: Word, + pub param2: Word, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct Receipt { - pub amount: Option, - pub asset_id: Option, +pub struct ReturnReceipt { + pub id: ContractId, + pub val: Word, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ReturnDataReceipt { + pub id: ContractId, + pub ptr: Word, + pub len: Word, + pub digest: Bytes32, + pub pc: Word, + pub is: Word, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option>, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PanicReceipt { + pub id: ContractId, + pub reason: PanicInstruction, + pub pc: Word, + pub is: Word, + #[serde(skip_serializing_if = "Option::is_none")] pub contract_id: Option, - pub data: Option, - pub digest: Option, - pub gas: Option, - pub gas_used: Option, - pub id: Option, - pub is: Option, - pub len: Option, - pub nonce: Option, - pub param1: Option, - pub param2: Option, - pub pc: Option, - pub ptr: Option, - pub ra: Option, - pub rb: Option, - pub rc: Option, - pub rd: Option, - pub reason: Option, - pub receipt_type: ReceiptType, - pub recipient: Option
, - pub result: Option, - pub sender: Option
, - pub sub_id: Option, - pub to: Option, - pub to_address: Option
, - pub val: Option, } -impl From<&FuelCoreReceipt> for Receipt { - fn from(r: &FuelCoreReceipt) -> Self { - Receipt { - amount: r.amount().map(Into::into), - asset_id: r.asset_id().copied().map(Into::into), - contract_id: r.contract_id().map(Into::into), - data: r.data().map(Into::into), - digest: r.digest().copied().map(Into::into), - gas: r.gas().map(Into::into), - gas_used: r.gas_used().map(Into::into), - id: r.id().map(Into::into), - is: r.is().map(Into::into), - len: r.len().map(Into::into), - nonce: r.nonce().copied().map(Into::into), - param1: r.param1().map(Into::into), - param2: r.param2().map(Into::into), - pc: r.pc().map(Into::into), - ptr: r.ptr().map(Into::into), - ra: r.ra().map(Into::into), - rb: r.rb().map(Into::into), - rc: r.rc().map(Into::into), - rd: r.rd().map(Into::into), - reason: r.reason().map(Into::into), - receipt_type: r.into(), - recipient: r.recipient().copied().map(Into::into), - result: r.result().map(|r| FuelCoreWord::from(*r)), - sender: r.sender().copied().map(Into::into), - sub_id: r.sub_id().copied().map(Into::into), - to: r.to().copied().map(Into::into), - to_address: r.to_address().copied().map(Into::into), - val: r.val().map(Into::into), +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RevertReceipt { + pub id: ContractId, + pub ra: Word, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LogReceipt { + pub id: ContractId, + pub ra: Word, + pub rb: Word, + pub rc: Word, + pub rd: Word, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LogDataReceipt { + pub id: ContractId, + pub ra: Word, + pub rb: Word, + pub ptr: Word, + pub len: Word, + pub digest: Bytes32, + pub pc: Word, + pub is: Word, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option>, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransferReceipt { + pub id: ContractId, + pub to: ContractId, + pub amount: Word, + pub asset_id: AssetId, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransferOutReceipt { + pub id: ContractId, + pub to: Address, + pub amount: Word, + pub asset_id: AssetId, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptResultReceipt { + pub result: ScriptExecutionResult, + pub gas_used: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MessageOutReceipt { + pub sender: Address, + pub recipient: Address, + pub amount: Word, + pub nonce: Nonce, + pub len: Word, + pub digest: Bytes32, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option>, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MintReceipt { + pub sub_id: Bytes32, + pub contract_id: ContractId, + pub val: Word, + pub pc: Word, + pub is: Word, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BurnReceipt { + pub sub_id: Bytes32, + pub contract_id: ContractId, + pub val: Word, + pub pc: Word, + pub is: Word, +} + +impl From for Receipt { + fn from(value: FuelCoreReceipt) -> Self { + match value { + FuelCoreReceipt::Call { + id, + to, + amount, + asset_id, + gas, + param1, + param2, + pc, + is, + } => Self::Call(CallReceipt { + id: id.into(), + to: to.into(), + amount, + asset_id: asset_id.into(), + gas, + param1, + param2, + pc, + is, + }), + FuelCoreReceipt::Return { id, val, pc, is } => { + Self::Return(ReturnReceipt { + id: id.into(), + val, + pc, + is, + }) + } + FuelCoreReceipt::ReturnData { + id, + ptr, + len, + digest, + pc, + is, + data, + } => Self::ReturnData(ReturnDataReceipt { + id: id.into(), + ptr, + len, + digest: digest.into(), + pc, + is, + data, + }), + FuelCoreReceipt::Panic { + id, + reason, + pc, + is, + contract_id, + } => Self::Panic(PanicReceipt { + id: id.into(), + reason: reason.into(), + pc, + is, + contract_id: contract_id.map(|id| id.into()), + }), + FuelCoreReceipt::Revert { id, ra, pc, is } => { + Self::Revert(RevertReceipt { + id: id.into(), + ra, + pc, + is, + }) + } + FuelCoreReceipt::Log { + id, + ra, + rb, + rc, + rd, + pc, + is, + } => Self::Log(LogReceipt { + id: id.into(), + ra, + rb, + rc, + rd, + pc, + is, + }), + FuelCoreReceipt::LogData { + id, + ra, + rb, + ptr, + len, + digest, + pc, + is, + data, + } => Self::LogData(LogDataReceipt { + id: id.into(), + ra, + rb, + ptr, + len, + digest: digest.into(), + pc, + is, + data, + }), + FuelCoreReceipt::Transfer { + id, + to, + amount, + asset_id, + pc, + is, + } => Self::Transfer(TransferReceipt { + id: id.into(), + to: to.into(), + amount, + asset_id: asset_id.into(), + pc, + is, + }), + FuelCoreReceipt::TransferOut { + id, + to, + amount, + asset_id, + pc, + is, + } => Self::TransferOut(TransferOutReceipt { + id: id.into(), + to: to.into(), + amount, + asset_id: asset_id.into(), + pc, + is, + }), + FuelCoreReceipt::ScriptResult { result, gas_used } => { + Self::ScriptResult(ScriptResultReceipt { + result: result.into(), + gas_used, + }) + } + FuelCoreReceipt::MessageOut { + sender, + recipient, + amount, + nonce, + len, + digest, + data, + } => Self::MessageOut(MessageOutReceipt { + sender: sender.into(), + recipient: recipient.into(), + amount, + nonce: nonce.into(), + len, + digest: digest.into(), + data, + }), + FuelCoreReceipt::Mint { + sub_id, + contract_id, + val, + pc, + is, + } => Self::Mint(MintReceipt { + sub_id: sub_id.into(), + contract_id: contract_id.into(), + val, + pc, + is, + }), + FuelCoreReceipt::Burn { + sub_id, + contract_id, + val, + pc, + is, + } => Self::Burn(BurnReceipt { + sub_id: sub_id.into(), + contract_id: contract_id.into(), + val, + pc, + is, + }), } } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum ReceiptType { - Burn, - Call, - Log, - LogData, - MessageOut, - Mint, - Panic, - Return, - ReturnData, - Revert, - ScriptResult, - Transfer, - TransferOut, -} - -impl From<&FuelCoreReceipt> for ReceiptType { - fn from(r: &FuelCoreReceipt) -> Self { - match r { - FuelCoreReceipt::Call { .. } => ReceiptType::Call, - FuelCoreReceipt::Return { .. } => ReceiptType::Return, - FuelCoreReceipt::ReturnData { .. } => ReceiptType::ReturnData, - FuelCoreReceipt::Panic { .. } => ReceiptType::Panic, - FuelCoreReceipt::Revert { .. } => ReceiptType::Revert, - FuelCoreReceipt::Log { .. } => ReceiptType::Log, - FuelCoreReceipt::LogData { .. } => ReceiptType::LogData, - FuelCoreReceipt::Transfer { .. } => ReceiptType::Transfer, - FuelCoreReceipt::TransferOut { .. } => ReceiptType::TransferOut, - FuelCoreReceipt::ScriptResult { .. } => ReceiptType::ScriptResult, - FuelCoreReceipt::MessageOut { .. } => ReceiptType::MessageOut, - FuelCoreReceipt::Mint { .. } => ReceiptType::Mint, - FuelCoreReceipt::Burn { .. } => ReceiptType::Burn, - } +impl From<&FuelCoreReceipt> for Receipt { + fn from(value: &FuelCoreReceipt) -> Self { + value.clone().into() } } diff --git a/crates/fuel-streams-publisher/src/publisher/fuel_streams.rs b/crates/fuel-streams-core/src/stream/fuel_streams.rs similarity index 87% rename from crates/fuel-streams-publisher/src/publisher/fuel_streams.rs rename to crates/fuel-streams-core/src/stream/fuel_streams.rs index 6900c82a..c7e8ba08 100644 --- a/crates/fuel-streams-publisher/src/publisher/fuel_streams.rs +++ b/crates/fuel-streams-core/src/stream/fuel_streams.rs @@ -1,9 +1,10 @@ +use std::sync::Arc; + use async_nats::{jetstream::stream::State as StreamState, RequestErrorKind}; -use fuel_streams::types::Log; -use fuel_streams_core::prelude::*; + +use crate::prelude::*; #[derive(Clone, Debug)] -/// Streams we currently support publishing to. pub struct FuelStreams { pub transactions: Stream, pub blocks: Stream, @@ -14,7 +15,6 @@ pub struct FuelStreams { pub logs: Stream, } -#[cfg_attr(test, mockall::automock)] impl FuelStreams { pub async fn new(nats_client: &NatsClient) -> Self { Self { @@ -27,6 +27,19 @@ impl FuelStreams { logs: Stream::::new(nats_client).await, } } + + pub async fn setup_all( + core_client: &NatsClient, + publisher_client: &NatsClient, + ) -> (Self, Self) { + let core_stream = Self::new(core_client).await; + let publisher_stream = Self::new(publisher_client).await; + (core_stream, publisher_stream) + } + + pub fn arc(self) -> Arc { + Arc::new(self) + } } #[async_trait::async_trait] @@ -72,7 +85,7 @@ pub trait FuelStreamsExt: Sync + Send { &self, ) -> Result, StreamState)>, RequestErrorKind>; - #[cfg(feature = "test-helpers")] + #[cfg(any(test, feature = "test-helpers"))] async fn is_empty(&self) -> bool; } @@ -101,10 +114,10 @@ impl FuelStreamsExt for FuelStreams { } async fn get_last_published_block(&self) -> anyhow::Result> { - Ok(self - .blocks + self.blocks .get_last_published(BlocksSubject::WILDCARD) - .await?) + .await + .map_err(|e| e.into()) } async fn get_consumers_and_state( @@ -121,7 +134,7 @@ impl FuelStreamsExt for FuelStreams { ]) } - #[cfg(feature = "test-helpers")] + #[cfg(any(test, feature = "test-helpers"))] async fn is_empty(&self) -> bool { self.blocks.is_empty(BlocksSubject::WILDCARD).await && self diff --git a/crates/fuel-streams-core/src/stream/mod.rs b/crates/fuel-streams-core/src/stream/mod.rs index 4ea63aff..a204e8d1 100644 --- a/crates/fuel-streams-core/src/stream/mod.rs +++ b/crates/fuel-streams-core/src/stream/mod.rs @@ -1,7 +1,9 @@ mod error; +mod fuel_streams; mod stream_encoding; mod stream_impl; pub use error::*; +pub use fuel_streams::*; pub use stream_encoding::*; pub use stream_impl::*; diff --git a/crates/fuel-streams-core/src/stream/stream_impl.rs b/crates/fuel-streams-core/src/stream/stream_impl.rs index c3b7e855..e2d690ed 100644 --- a/crates/fuel-streams-core/src/stream/stream_impl.rs +++ b/crates/fuel-streams-core/src/stream/stream_impl.rs @@ -1,6 +1,6 @@ #[cfg(any(test, feature = "test-helpers"))] use std::pin::Pin; -use std::{fmt::Debug, sync::Arc, time::Duration}; +use std::{fmt::Debug, sync::Arc}; use async_nats::{ jetstream::{ @@ -128,17 +128,17 @@ impl Stream { pub async fn new(client: &NatsClient) -> Self { let namespace = &client.namespace; let bucket_name = namespace.stream_name(S::NAME); + + let config = kv::Config { + bucket: bucket_name.to_owned(), + storage: stream::StorageType::File, + history: 1, + compression: true, + ..Default::default() + }; + let store = client - .get_or_create_kv_store(kv::Config { - bucket: bucket_name.to_owned(), - storage: stream::StorageType::File, - history: 1, - compression: true, - max_age: Duration::from_secs( - FUEL_BLOCK_TIME_SECS * MAX_RETENTION_BLOCKS, - ), - ..Default::default() - }) + .get_or_create_kv_store(config) .await .expect("Streams must be created"); @@ -291,7 +291,6 @@ impl Stream { wildcard: &str, ) -> Result, StreamError> { let subject_name = &Self::prefix_filter_subject(wildcard); - let message = self .store .stream @@ -301,7 +300,6 @@ impl Stream { match message { Ok(message) => { let payload = S::decode(message.payload.to_vec()).await; - Ok(Some(payload)) } Err(error) => match &error.kind() { @@ -345,6 +343,10 @@ impl Stream { pub fn store(&self) -> &kv::Store { &self.store } + + pub fn arc(&self) -> Arc { + Arc::new(self.to_owned()) + } } /// Configuration for subscribing to a consumer. diff --git a/crates/fuel-streams-core/src/transactions/types.rs b/crates/fuel-streams-core/src/transactions/types.rs index fe6233b5..adeb64fc 100644 --- a/crates/fuel-streams-core/src/transactions/types.rs +++ b/crates/fuel-streams-core/src/transactions/types.rs @@ -1,3 +1,4 @@ +pub use fuel_core_client::client::types::TransactionStatus as ClientTransactionStatus; use fuel_core_types::fuel_tx; use crate::types::*; @@ -405,7 +406,7 @@ impl Transaction { tx_pointer, upgrade_purpose, witnesses, - receipts: receipts.iter().map(Into::into).collect(), + receipts: receipts.iter().map(|r| r.to_owned().into()).collect(), } } } @@ -502,6 +503,31 @@ impl From<&FuelCoreTransactionStatus> for TransactionStatus { } } +impl From<&ClientTransactionStatus> for TransactionStatus { + fn from(value: &ClientTransactionStatus) -> Self { + match value { + ClientTransactionStatus::Failure { .. } => { + TransactionStatus::Failed + } + ClientTransactionStatus::Submitted { .. } => { + TransactionStatus::Submitted + } + ClientTransactionStatus::SqueezedOut { .. } => { + TransactionStatus::SqueezedOut + } + ClientTransactionStatus::Success { .. } => { + TransactionStatus::Success + } + } + } +} + +impl From for TransactionStatus { + fn from(value: ClientTransactionStatus) -> Self { + (&value).into() + } +} + pub trait FuelCoreTransactionExt { fn inputs(&self) -> &[FuelCoreInput]; fn outputs(&self) -> &Vec; diff --git a/crates/fuel-streams-core/src/types.rs b/crates/fuel-streams-core/src/types.rs index 9b9c16fb..4eb3a874 100644 --- a/crates/fuel-streams-core/src/types.rs +++ b/crates/fuel-streams-core/src/types.rs @@ -16,4 +16,5 @@ pub use crate::{ // ------------------------------------------------------------------------ // General // ------------------------------------------------------------------------ -pub type BoxedResult = Result>; +pub type BoxedError = Box; +pub type BoxedResult = Result; diff --git a/crates/fuel-streams-core/src/utxos/subjects.rs b/crates/fuel-streams-core/src/utxos/subjects.rs index 6238f49e..2d89d4c7 100644 --- a/crates/fuel-streams-core/src/utxos/subjects.rs +++ b/crates/fuel-streams-core/src/utxos/subjects.rs @@ -16,12 +16,12 @@ use crate::types::*; /// # use fuel_streams_core::types::*; /// # use fuel_streams_macros::subject::*; /// let subject = UtxosSubject { -/// hash: Some(MessageId::from([1u8; 32])), +/// utxo_id: Some(HexString::zeroed()), /// utxo_type: Some(UtxoType::Message), /// }; /// assert_eq!( /// subject.parse(), -/// "utxos.message.0x0101010101010101010101010101010101010101010101010101010101010101" +/// "utxos.message.0x0000000000000000000000000000000000000000000000000000000000000000" /// ); /// ``` /// @@ -40,10 +40,10 @@ use crate::types::*; /// # use fuel_streams_core::types::*; /// # use fuel_streams_macros::subject::*; /// let wildcard = UtxosSubject::wildcard( -/// Some(MessageId::from([1u8; 32])), +/// Some(HexString::zeroed()), /// None, /// ); -/// assert_eq!(wildcard, "utxos.*.0x0101010101010101010101010101010101010101010101010101010101010101"); +/// assert_eq!(wildcard, "utxos.*.0x0000000000000000000000000000000000000000000000000000000000000000"); /// ``` /// /// Using the builder pattern: @@ -53,16 +53,16 @@ use crate::types::*; /// # use fuel_streams_core::types::*; /// # use fuel_streams_macros::subject::*; /// let subject = UtxosSubject::new() -/// .with_hash(Some(MessageId::from([1u8; 32]))) +/// .with_utxo_id(Some(HexString::zeroed())) /// .with_utxo_type(Some(UtxoType::Message)); -/// assert_eq!(subject.parse(), "utxos.message.0x0101010101010101010101010101010101010101010101010101010101010101"); +/// assert_eq!(subject.parse(), "utxos.message.0x0000000000000000000000000000000000000000000000000000000000000000"); /// ``` #[derive(Subject, Debug, Clone, Default)] #[subject_wildcard = "utxos.>"] -#[subject_format = "utxos.{utxo_type}.{hash}"] +#[subject_format = "utxos.{utxo_type}.{utxo_id}"] pub struct UtxosSubject { - pub hash: Option, + pub utxo_id: Option, pub utxo_type: Option, } @@ -80,7 +80,7 @@ mod tests { #[test] fn test_utxos_message_subject_creation() { let utxo_subject = UtxosSubject::new() - .with_hash(Some(MessageId::zeroed())) + .with_utxo_id(Some(HexString::zeroed())) .with_utxo_type(Some(UtxoType::Message)); assert_eq!( utxo_subject.to_string(), @@ -91,7 +91,7 @@ mod tests { #[test] fn test_utxos_coin_subject_creation() { let utxo_subject = UtxosSubject::new() - .with_hash(Some(MessageId::zeroed())) + .with_utxo_id(Some(HexString::zeroed())) .with_utxo_type(Some(UtxoType::Coin)); assert_eq!( utxo_subject.to_string(), @@ -102,7 +102,7 @@ mod tests { #[test] fn test_utxos_contract_subject_creation() { let utxo_subject = UtxosSubject::new() - .with_hash(Some(MessageId::zeroed())) + .with_utxo_id(Some(HexString::zeroed())) .with_utxo_type(Some(UtxoType::Contract)); assert_eq!( utxo_subject.to_string(), diff --git a/crates/fuel-streams-core/src/utxos/types.rs b/crates/fuel-streams-core/src/utxos/types.rs index 2e067f29..1fd8daec 100644 --- a/crates/fuel-streams-core/src/utxos/types.rs +++ b/crates/fuel-streams-core/src/utxos/types.rs @@ -7,7 +7,7 @@ pub struct Utxo { pub sender: Option
, pub recipient: Option
, pub nonce: Option, - pub data: Option>, + pub data: Option, pub amount: Option, pub tx_id: Bytes32, } diff --git a/crates/fuel-streams-executors/Cargo.toml b/crates/fuel-streams-executors/Cargo.toml new file mode 100644 index 00000000..7b70773d --- /dev/null +++ b/crates/fuel-streams-executors/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "fuel-streams-executors" +description = "Executors for Fuel Streams entities" +authors = { workspace = true } +keywords = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +version = { workspace = true } +rust-version = { workspace = true } +publish = false + +[dependencies] +anyhow = { workspace = true } +async-nats = { workspace = true } +fuel-core = { workspace = true } +fuel-streams-core = { workspace = true, features = ["test-helpers"] } +futures = { workspace = true } +num_cpus = { workspace = true } +rayon = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } + +[features] +default = [] +test-helpers = [] diff --git a/crates/fuel-streams-executors/src/blocks.rs b/crates/fuel-streams-executors/src/blocks.rs new file mode 100644 index 00000000..b24ce9d6 --- /dev/null +++ b/crates/fuel-streams-executors/src/blocks.rs @@ -0,0 +1,81 @@ +use std::{sync::Arc, time::Instant}; + +use fuel_streams_core::prelude::*; +use futures::{future::try_join_all, stream::FuturesUnordered}; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process(&self) -> JoinHandle> { + let metadata = self.metadata(); + let block = self.block(); + let block_height = (*metadata.block_height).clone(); + let block_producer = (*metadata.block_producer).clone(); + let packet = PublishPacket::::new( + block.to_owned(), + BlocksSubject { + height: Some(block_height), + producer: Some(block_producer), + } + .arc(), + ); + self.publish(&packet) + } + + pub async fn process_all( + payload: Arc, + fuel_streams: &Arc, + ) -> Result<(), ExecutorError> { + let start_time = Instant::now(); + let metadata = Arc::new(payload.metadata().clone()); + + let block_stream = fuel_streams.blocks().arc(); + let tx_stream = fuel_streams.transactions().arc(); + let input_stream = fuel_streams.inputs().arc(); + let output_stream = fuel_streams.outputs().arc(); + let receipt_stream = fuel_streams.receipts().arc(); + let log_stream = fuel_streams.logs().arc(); + let utxo_stream = fuel_streams.utxos().arc(); + + let block_executor = Executor::new(&payload, &block_stream); + let tx_executor = Executor::new(&payload, &tx_stream); + let input_executor = Executor::new(&payload, &input_stream); + let output_executor = Executor::new(&payload, &output_stream); + let receipt_executor = Executor::new(&payload, &receipt_stream); + let log_executor = Executor::new(&payload, &log_stream); + let utxo_executor = Executor::new(&payload, &utxo_stream); + + let transactions = payload.transactions.to_owned(); + let tx_tasks = + transactions + .iter() + .enumerate() + .flat_map(|tx_item @ (_, tx)| { + vec![ + tx_executor.process(tx_item), + input_executor.process(tx), + output_executor.process(tx), + receipt_executor.process(tx), + log_executor.process(tx), + utxo_executor.process(tx), + ] + }); + + let block_task = block_executor.process(); + let all_tasks = std::iter::once(block_task) + .chain(tx_tasks.into_iter().flatten()) + .collect::>(); + + try_join_all(all_tasks).await?; + + let elapsed = start_time.elapsed(); + let height = metadata.block_height.clone(); + tracing::info!( + "Published streams for BlockHeight: {height} in {:?}", + elapsed + ); + + Ok(()) + } +} diff --git a/crates/fuel-streams-executors/src/inputs.rs b/crates/fuel-streams-executors/src/inputs.rs new file mode 100644 index 00000000..0c201b3b --- /dev/null +++ b/crates/fuel-streams-executors/src/inputs.rs @@ -0,0 +1,129 @@ +use std::sync::Arc; + +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx: &Transaction, + ) -> Vec>> { + let tx_id = tx.id.clone(); + let packets = tx + .inputs + .par_iter() + .enumerate() + .flat_map(move |(index, input)| { + let main_subject = main_subject(input, tx_id.clone(), index); + let identifier_subjects = + identifiers(input, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: InputsByIdSubject| subject.arc()) + .collect::>(); + + let mut packets = vec![input.to_packet(main_subject)]; + packets.extend( + identifier_subjects + .into_iter() + .map(|subject| input.to_packet(subject)), + ); + + packets + }) + .collect::>(); + + packets.iter().map(|packet| self.publish(packet)).collect() + } +} + +fn main_subject( + input: &Input, + tx_id: Bytes32, + index: usize, +) -> Arc { + match input { + Input::Contract(contract) => InputsContractSubject { + tx_id: Some(tx_id), + index: Some(index), + contract_id: Some(contract.contract_id.to_owned().into()), + } + .arc(), + Input::Coin(coin) => InputsCoinSubject { + tx_id: Some(tx_id), + index: Some(index), + owner: Some(coin.owner.to_owned()), + asset_id: Some(coin.asset_id.to_owned()), + } + .arc(), + Input::Message(message) => InputsMessageSubject { + tx_id: Some(tx_id), + index: Some(index), + sender: Some(message.sender.to_owned()), + recipient: Some(message.recipient.to_owned()), + } + .arc(), + } +} + +pub fn identifiers( + input: &Input, + tx_id: &Bytes32, + index: u8, +) -> Vec { + let mut identifiers = match input { + Input::Coin(coin) => { + vec![ + Identifier::Address( + tx_id.to_owned(), + index, + coin.owner.to_owned().into(), + ), + Identifier::AssetID( + tx_id.to_owned(), + index, + coin.asset_id.to_owned().into(), + ), + ] + } + Input::Message(message) => { + vec![ + Identifier::Address( + tx_id.to_owned(), + index, + message.sender.to_owned().into(), + ), + Identifier::Address( + tx_id.to_owned(), + index, + message.recipient.to_owned().into(), + ), + ] + } + Input::Contract(contract) => { + vec![Identifier::ContractID( + tx_id.to_owned(), + index, + contract.contract_id.to_owned(), + )] + } + }; + + match input { + Input::Coin(InputCoin { predicate, .. }) + | Input::Message(InputMessage { predicate, .. }) => { + let predicate_tag = super::sha256(&predicate.0); + identifiers.push(Identifier::PredicateID( + tx_id.to_owned(), + index, + predicate_tag, + )); + } + _ => {} + }; + + identifiers +} diff --git a/crates/fuel-streams-executors/src/lib.rs b/crates/fuel-streams-executors/src/lib.rs new file mode 100644 index 00000000..1fa507f9 --- /dev/null +++ b/crates/fuel-streams-executors/src/lib.rs @@ -0,0 +1,250 @@ +pub mod blocks; +pub mod inputs; +pub mod logs; +pub mod outputs; +pub mod receipts; +pub mod transactions; +pub mod utxos; + +use std::{ + env, + marker::PhantomData, + sync::{Arc, LazyLock}, +}; + +use async_nats::jetstream::context::Publish; +use fuel_streams_core::prelude::*; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use tokio::task::JoinHandle; + +pub static PUBLISHER_MAX_THREADS: LazyLock = LazyLock::new(|| { + let available_cpus = num_cpus::get(); + let default_threads = (available_cpus / 3).max(1); // Use 1/3 of CPUs, minimum 1 + + env::var("PUBLISHER_MAX_THREADS") + .ok() + .and_then(|val| val.parse().ok()) + .unwrap_or(default_threads) +}); + +pub fn sha256(bytes: &[u8]) -> Bytes32 { + let mut sha256 = Sha256::new(); + sha256.update(bytes); + let bytes: [u8; 32] = sha256 + .finalize() + .as_slice() + .try_into() + .expect("Must be 32 bytes"); + + bytes.into() +} + +#[derive(Debug, thiserror::Error)] +pub enum ExecutorError { + #[error("Failed to publish: {0}")] + PublishFailed(String), + #[error("Failed to acquire semaphore: {0}")] + SemaphoreError(#[from] tokio::sync::AcquireError), + #[error("Failed to serialize block payload: {0}")] + Serialization(#[from] serde_json::Error), + #[error("Failed to fetch transaction status: {0}")] + TransactionStatus(String), + #[error("Failed to access offchain database")] + OffchainDatabase(#[from] anyhow::Error), + #[error("Failed to join tasks: {0}")] + JoinError(#[from] tokio::task::JoinError), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Metadata { + pub chain_id: Arc, + pub base_asset_id: Arc, + pub block_producer: Arc
, + pub block_height: Arc, + pub consensus: Arc, +} + +impl Metadata { + pub fn new( + fuel_core: &Arc, + sealed_block: &FuelCoreSealedBlock, + ) -> Self { + let block = sealed_block.entity.clone(); + let consensus = sealed_block.consensus.clone(); + let height = *block.header().consensus().height; + let producer = + consensus.block_producer(&block.id()).unwrap_or_default(); + Self { + chain_id: Arc::new(*fuel_core.chain_id()), + base_asset_id: Arc::new(*fuel_core.base_asset_id()), + block_producer: Arc::new(producer.into()), + block_height: Arc::new(height.into()), + consensus: Arc::new(consensus.into()), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockPayload { + pub block: Block, + pub transactions: Vec, + metadata: Metadata, +} + +impl BlockPayload { + pub fn new( + fuel_core: Arc, + sealed_block: &FuelCoreSealedBlock, + metadata: &Metadata, + ) -> Result { + let block = sealed_block.entity.clone(); + let txs = Self::txs_from_fuelcore( + fuel_core.to_owned(), + sealed_block, + metadata, + )?; + let txs_ids = txs.iter().map(|i| i.id.clone()).collect(); + let block_height = block.header().height(); + let consensus = fuel_core.get_consensus(block_height)?; + let block = Block::new(&block, consensus.into(), txs_ids); + Ok(Self { + block, + transactions: txs, + metadata: metadata.to_owned(), + }) + } + + pub fn encode(&self) -> Result { + serde_json::to_string(self).map_err(ExecutorError::from) + } + + pub fn decode(json: &str) -> Result { + serde_json::from_str(json).map_err(ExecutorError::from) + } + + pub fn tx_ids(&self) -> Vec { + self.transactions + .iter() + .map(|tx| tx.id.clone()) + .collect::>() + } + + pub fn message_id(&self) -> String { + let height = self.metadata.block_height.clone(); + format!("block_{height}") + } + + pub fn subject(&self) -> String { + let producer = self.metadata.block_producer.clone(); + let height = self.metadata.block_height.clone(); + format!("block_submitted.{producer}.{height}") + } + + pub fn metadata(&self) -> &Metadata { + &self.metadata + } + + pub fn block_height(&self) -> u32 { + self.block.height + } + + pub fn arc(&self) -> Arc { + Arc::new(self.clone()) + } + + pub fn txs_from_fuelcore( + fuel_core: Arc, + sealed_block: &FuelCoreSealedBlock, + metadata: &Metadata, + ) -> Result, ExecutorError> { + let mut transactions: Vec = vec![]; + let blocks_txs = sealed_block.entity.transactions_vec(); + for tx_item in blocks_txs.iter() { + let tx_id = tx_item.id(&metadata.chain_id); + let receipts = fuel_core.get_receipts(&tx_id)?.unwrap_or_default(); + let tx_status = fuel_core.get_tx_status(&tx_id)?; + let tx_status: TransactionStatus = match tx_status { + Some(status) => (&status).into(), + _ => TransactionStatus::None, + }; + let new_transaction = Transaction::new( + &tx_id.into(), + tx_item, + &tx_status, + &metadata.base_asset_id, + &receipts, + ); + transactions.push(new_transaction); + } + Ok(transactions) + } +} + +impl TryFrom for Publish { + type Error = ExecutorError; + fn try_from(payload: BlockPayload) -> Result { + let message_id = payload.message_id(); + Ok(Publish::build() + .message_id(message_id) + .payload(payload.encode()?.into())) + } +} + +pub struct Executor { + pub stream: Arc>, + payload: Arc, + __marker: PhantomData, +} + +impl Executor { + pub fn new(payload: &Arc, stream: &Arc>) -> Self { + Self { + payload: payload.to_owned(), + stream: stream.to_owned(), + __marker: PhantomData, + } + } + + fn publish( + &self, + packet: &PublishPacket, + // _opts: &Arc, + ) -> JoinHandle> { + let payload = Arc::clone(&packet.payload); + let subject = Arc::clone(&packet.subject); + let wildcard = packet.subject.parse(); + let stream = Arc::clone(&self.stream); + let max_threads = *PUBLISHER_MAX_THREADS; + let semaphore = Arc::new(tokio::sync::Semaphore::new(max_threads)); + let permit = Arc::clone(&semaphore); + + // TODO: add telemetry back again + tokio::spawn(async move { + let _permit = permit.acquire().await?; + match stream.publish(&*subject, &payload).await { + Ok(_) => { + tracing::info!( + "Successfully published for stream: {wildcard}" + ); + Ok(()) + } + Err(e) => Err(ExecutorError::PublishFailed(e.to_string())), + } + }) + } + + pub fn payload(&self) -> Arc { + Arc::clone(&self.payload) + } + pub fn metadata(&self) -> &Metadata { + &self.payload.metadata + } + pub fn block(&self) -> &Block { + &self.payload.block + } + pub fn block_height(&self) -> BlockHeight { + let height = self.block().height; + BlockHeight::from(height) + } +} diff --git a/crates/fuel-streams-executors/src/logs.rs b/crates/fuel-streams-executors/src/logs.rs new file mode 100644 index 00000000..f4ac0308 --- /dev/null +++ b/crates/fuel-streams-executors/src/logs.rs @@ -0,0 +1,38 @@ +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx: &Transaction, + ) -> Vec>> { + let block_height = self.block_height(); + let tx_id = tx.id.clone(); + let receipts = tx.receipts.clone(); + let packets = receipts + .par_iter() + .enumerate() + .filter_map(|(index, receipt)| match receipt { + Receipt::Log(LogReceipt { id, .. }) + | Receipt::LogData(LogDataReceipt { id, .. }) => { + Some(PublishPacket::new( + receipt.to_owned().into(), + LogsSubject { + block_height: Some(block_height.clone()), + tx_id: Some(tx_id.to_owned()), + receipt_index: Some(index), + log_id: Some(id.into()), + } + .arc(), + )) + } + _ => None, + }) + .collect::>(); + + packets.iter().map(|packet| self.publish(packet)).collect() + } +} diff --git a/crates/fuel-streams-executors/src/outputs.rs b/crates/fuel-streams-executors/src/outputs.rs new file mode 100644 index 00000000..48e9baa8 --- /dev/null +++ b/crates/fuel-streams-executors/src/outputs.rs @@ -0,0 +1,155 @@ +use std::sync::Arc; + +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx: &Transaction, + ) -> Vec>> { + let tx_id = tx.id.clone(); + let packets: Vec> = tx + .outputs + .par_iter() + .enumerate() + .flat_map(|(index, output)| { + let main_subject = main_subject(output, tx, &tx_id, index); + let identifier_subjects = + identifiers(output, tx, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: OutputsByIdSubject| subject.arc()) + .collect::>(); + + let mut packets = vec![output.to_packet(main_subject)]; + packets.extend( + identifier_subjects + .into_iter() + .map(|subject| output.to_packet(subject)), + ); + + packets + }) + .collect(); + + packets.iter().map(|packet| self.publish(packet)).collect() + } +} + +fn main_subject( + output: &Output, + transaction: &Transaction, + tx_id: &Bytes32, + index: usize, +) -> Arc { + match output { + Output::Coin(OutputCoin { to, asset_id, .. }) => OutputsCoinSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index as u16), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc(), + Output::Contract(contract) => { + let contract_id = + match find_output_contract_id(transaction, contract) { + Some(contract_id) => contract_id, + None => { + tracing::warn!( + "Contract ID not found for output: {:?}", + output + ); + + Default::default() + } + }; + + OutputsContractSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index as u16), + contract_id: Some(contract_id), + } + .arc() + } + Output::Change(OutputChange { to, asset_id, .. }) => { + OutputsChangeSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index as u16), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc() + } + Output::Variable(OutputVariable { to, asset_id, .. }) => { + OutputsVariableSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index as u16), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc() + } + Output::ContractCreated(OutputContractCreated { + contract_id, .. + }) => OutputsContractCreatedSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index as u16), + contract_id: Some(contract_id.to_owned()), + } + .arc(), + } +} + +pub fn identifiers( + output: &Output, + tx: &Transaction, + tx_id: &Bytes32, + index: u8, +) -> Vec { + match output { + Output::Change(OutputChange { to, asset_id, .. }) + | Output::Variable(OutputVariable { to, asset_id, .. }) + | Output::Coin(OutputCoin { to, asset_id, .. }) => { + vec![ + Identifier::Address(tx_id.to_owned(), index, to.into()), + Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), + ] + } + Output::Contract(contract) => find_output_contract_id(tx, contract) + .map(|contract_id| { + vec![Identifier::ContractID( + tx_id.to_owned(), + index, + contract_id.into(), + )] + }) + .unwrap_or_default(), + Output::ContractCreated(OutputContractCreated { + contract_id, .. + }) => { + vec![Identifier::ContractID( + tx_id.to_owned(), + index, + contract_id.into(), + )] + } + } +} + +pub fn find_output_contract_id( + tx: &Transaction, + contract: &OutputContract, +) -> Option { + let input_index = contract.input_index as usize; + tx.inputs.get(input_index).and_then(|input| { + if let Input::Contract(input_contract) = input { + Some(input_contract.contract_id.to_owned().into()) + } else { + None + } + }) +} diff --git a/crates/fuel-streams-executors/src/receipts.rs b/crates/fuel-streams-executors/src/receipts.rs new file mode 100644 index 00000000..c99f03fc --- /dev/null +++ b/crates/fuel-streams-executors/src/receipts.rs @@ -0,0 +1,238 @@ +use std::sync::Arc; + +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx: &Transaction, + ) -> Vec>> { + let tx_id = tx.id.clone(); + let receipts = tx.receipts.clone(); + let packets: Vec> = receipts + .par_iter() + .enumerate() + .flat_map(|(index, receipt)| { + let main_subject = main_subject(receipt, &tx_id, index); + let identifier_subjects = + identifiers(receipt, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: ReceiptsByIdSubject| subject.arc()) + .collect::>(); + + let receipt: Receipt = receipt.to_owned(); + let mut packets = vec![receipt.to_packet(main_subject)]; + packets.extend( + identifier_subjects + .into_iter() + .map(|subject| receipt.to_packet(subject)), + ); + + packets + }) + .collect(); + + packets.iter().map(|packet| self.publish(packet)).collect() + } +} + +fn main_subject( + receipt: &Receipt, + tx_id: &Bytes32, + index: usize, +) -> Arc { + match receipt { + Receipt::Call(CallReceipt { + id: from, + to, + asset_id, + .. + }) => ReceiptsCallSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + from: Some(from.to_owned()), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc(), + Receipt::Return(ReturnReceipt { id, .. }) => ReceiptsReturnSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc(), + Receipt::ReturnData(ReturnDataReceipt { id, .. }) => { + ReceiptsReturnDataSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc() + } + Receipt::Panic(PanicReceipt { id, .. }) => ReceiptsPanicSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc(), + Receipt::Revert(RevertReceipt { id, .. }) => ReceiptsRevertSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc(), + Receipt::Log(LogReceipt { id, .. }) => ReceiptsLogSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc(), + Receipt::LogData(LogDataReceipt { id, .. }) => ReceiptsLogDataSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + id: Some(id.to_owned()), + } + .arc(), + Receipt::Transfer(TransferReceipt { + id: from, + to, + asset_id, + .. + }) => ReceiptsTransferSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + from: Some(from.to_owned()), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc(), + + Receipt::TransferOut(TransferOutReceipt { + id: from, + to, + asset_id, + .. + }) => ReceiptsTransferOutSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + from: Some(from.to_owned()), + to: Some(to.to_owned()), + asset_id: Some(asset_id.to_owned()), + } + .arc(), + + Receipt::ScriptResult(ScriptResultReceipt { .. }) => { + ReceiptsScriptResultSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + } + .arc() + } + Receipt::MessageOut(MessageOutReceipt { + sender, recipient, .. + }) => ReceiptsMessageOutSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + sender: Some(sender.to_owned()), + recipient: Some(recipient.to_owned()), + } + .arc(), + Receipt::Mint(MintReceipt { + contract_id, + sub_id, + .. + }) => ReceiptsMintSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + contract_id: Some(contract_id.to_owned()), + sub_id: Some((*sub_id).to_owned()), + } + .arc(), + Receipt::Burn(BurnReceipt { + contract_id, + sub_id, + .. + }) => ReceiptsBurnSubject { + tx_id: Some(tx_id.to_owned()), + index: Some(index), + contract_id: Some(contract_id.to_owned()), + sub_id: Some((*sub_id).to_owned()), + } + .arc(), + } +} + +pub fn identifiers( + receipt: &Receipt, + tx_id: &Bytes32, + index: u8, +) -> Vec { + match receipt { + Receipt::Call(CallReceipt { + id: from, + to, + asset_id, + .. + }) => { + vec![ + Identifier::ContractID(tx_id.to_owned(), index, from.into()), + Identifier::ContractID(tx_id.to_owned(), index, to.into()), + Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), + ] + } + Receipt::Return(ReturnReceipt { id, .. }) + | Receipt::ReturnData(ReturnDataReceipt { id, .. }) + | Receipt::Panic(PanicReceipt { id, .. }) + | Receipt::Revert(RevertReceipt { id, .. }) + | Receipt::Log(LogReceipt { id, .. }) + | Receipt::LogData(LogDataReceipt { id, .. }) => { + vec![Identifier::ContractID(tx_id.to_owned(), index, id.into())] + } + Receipt::Transfer(TransferReceipt { + id: from, + to, + asset_id, + .. + }) => { + vec![ + Identifier::ContractID(tx_id.to_owned(), index, from.into()), + Identifier::ContractID(tx_id.to_owned(), index, to.into()), + Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), + ] + } + Receipt::TransferOut(TransferOutReceipt { + id: from, + to, + asset_id, + .. + }) => { + vec![ + Identifier::ContractID(tx_id.to_owned(), index, from.into()), + Identifier::ContractID(tx_id.to_owned(), index, to.into()), + Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), + ] + } + Receipt::MessageOut(MessageOutReceipt { + sender, recipient, .. + }) => { + vec![ + Identifier::Address(tx_id.to_owned(), index, sender.into()), + Identifier::Address(tx_id.to_owned(), index, recipient.into()), + ] + } + Receipt::Mint(MintReceipt { contract_id, .. }) + | Receipt::Burn(BurnReceipt { contract_id, .. }) => { + vec![Identifier::ContractID( + tx_id.to_owned(), + index, + contract_id.into(), + )] + } + _ => Vec::new(), + } +} diff --git a/crates/fuel-streams-executors/src/transactions.rs b/crates/fuel-streams-executors/src/transactions.rs new file mode 100644 index 00000000..76c42f28 --- /dev/null +++ b/crates/fuel-streams-executors/src/transactions.rs @@ -0,0 +1,100 @@ +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx_item: (usize, &Transaction), + ) -> Vec>> { + let block_height = self.block_height(); + packets_from_tx(tx_item, &block_height) + .iter() + .map(|packet| self.publish(packet)) + .collect() + } +} + +fn packets_from_tx( + (index, tx): (usize, &Transaction), + block_height: &BlockHeight, +) -> Vec> { + let tx_id = tx.id.clone(); + let tx_status = tx.status.clone(); + let receipts = tx.receipts.clone(); + let main_subject = TransactionsSubject { + block_height: Some(block_height.to_owned()), + index: Some(index), + tx_id: Some(tx_id.to_owned()), + status: Some(tx_status.to_owned()), + kind: Some(tx.kind.to_owned()), + } + .arc(); + + let mut packets = vec![tx.to_packet(main_subject)]; + packets.extend( + identifiers(tx, &tx.kind, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: TransactionsByIdSubject| subject.arc()) + .map(|subject| tx.to_packet(subject)) + .collect::>(), + ); + + let packets_from_inputs: Vec> = tx + .inputs + .par_iter() + .flat_map(|input| { + inputs::identifiers(input, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: TransactionsByIdSubject| subject.arc()) + .map(|subject| tx.to_packet(subject)) + }) + .collect(); + packets.extend(packets_from_inputs); + + let packets_from_outputs: Vec> = tx + .outputs + .par_iter() + .flat_map(|output| { + outputs::identifiers(output, tx, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: TransactionsByIdSubject| subject.arc()) + .map(|subject| tx.to_packet(subject)) + }) + .collect(); + packets.extend(packets_from_outputs); + + let packets_from_receipts: Vec> = receipts + .par_iter() + .flat_map(|receipt| { + receipts::identifiers(receipt, &tx_id, index as u8) + .into_par_iter() + .map(|identifier| identifier.into()) + .map(|subject: TransactionsByIdSubject| subject.arc()) + .map(|subject| tx.to_packet(subject)) + }) + .collect(); + packets.extend(packets_from_receipts); + packets +} + +fn identifiers( + tx: &Transaction, + kind: &TransactionKind, + tx_id: &Bytes32, + index: u8, +) -> Vec { + match kind { + TransactionKind::Script => { + let script_data = &tx.script_data.to_owned().unwrap_or_default().0; + let script_tag = sha256(script_data); + vec![Identifier::ScriptID(tx_id.to_owned(), index, script_tag)] + } + _ => Vec::new(), + } +} diff --git a/crates/fuel-streams-executors/src/utxos.rs b/crates/fuel-streams-executors/src/utxos.rs new file mode 100644 index 00000000..81fdaaf2 --- /dev/null +++ b/crates/fuel-streams-executors/src/utxos.rs @@ -0,0 +1,85 @@ +use fuel_streams_core::prelude::*; +use rayon::prelude::*; +use tokio::task::JoinHandle; + +use crate::*; + +impl Executor { + pub fn process( + &self, + tx: &Transaction, + ) -> Vec>> { + let tx_id = tx.id.clone(); + let packets = tx + .inputs + .par_iter() + .filter_map(|input| utxo_packet(input, &tx_id)) + .collect::>(); + + packets + .into_iter() + .map(|packet| self.publish(&packet)) + .collect() + } +} + +fn utxo_packet(input: &Input, tx_id: &Bytes32) -> Option> { + match input { + Input::Contract(InputContract { utxo_id, .. }) => { + let utxo = Utxo { + utxo_id: utxo_id.to_owned(), + tx_id: tx_id.to_owned(), + ..Default::default() + }; + let subject = UtxosSubject { + utxo_type: Some(UtxoType::Contract), + utxo_id: Some(utxo_id.into()), + } + .arc(); + Some(utxo.to_packet(subject)) + } + Input::Coin(InputCoin { + utxo_id, amount, .. + }) => { + let utxo = Utxo { + utxo_id: utxo_id.to_owned(), + amount: Some(*amount), + tx_id: tx_id.to_owned(), + ..Default::default() + }; + let subject = UtxosSubject { + utxo_type: Some(UtxoType::Coin), + utxo_id: Some(utxo_id.into()), + } + .arc(); + Some(utxo.to_packet(subject)) + } + Input::Message( + input @ InputMessage { + amount, + nonce, + recipient, + sender, + data, + .. + }, + ) => { + let utxo_id = input.computed_utxo_id(); + let utxo = Utxo { + tx_id: tx_id.to_owned(), + utxo_id: utxo_id.to_owned(), + sender: Some(sender.to_owned()), + recipient: Some(recipient.to_owned()), + nonce: Some(nonce.to_owned()), + amount: Some(*amount), + data: Some(data.to_owned()), + }; + let subject = UtxosSubject { + utxo_type: Some(UtxoType::Message), + utxo_id: None, + } + .arc(); + Some(utxo.to_packet(subject)) + } + } +} diff --git a/crates/fuel-streams-publisher/Cargo.toml b/crates/fuel-streams-publisher/Cargo.toml index 3982fc93..6466a81e 100644 --- a/crates/fuel-streams-publisher/Cargo.toml +++ b/crates/fuel-streams-publisher/Cargo.toml @@ -24,25 +24,28 @@ derive_more = { version = "1.0", features = ["full"] } displaydoc = { workspace = true } dotenvy = { workspace = true } elasticsearch = "8.15.0-alpha.1" -fuel-core = { workspace = true } -fuel-core-bin = { workspace = true } -fuel-core-importer = { workspace = true } -fuel-core-services = { workspace = true } -fuel-core-storage = { workspace = true } -fuel-core-types = { workspace = true } -fuel-streams = { workspace = true, features = ["test-helpers"] } +fuel-core = { workspace = true, default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", + "test-helpers", +] } +fuel-core-bin = { workspace = true, default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", +] } +fuel-core-services = { workspace = true, default-features = false, features = ["test-helpers"] } fuel-streams-core = { workspace = true, features = ["test-helpers"] } +fuel-streams-executors = { workspace = true, features = ["test-helpers"] } futures = { workspace = true } -num_cpus = "1.16" parking_lot = { version = "0.12", features = ["serde"] } prometheus = { version = "0.13", features = ["process"] } rand = { workspace = true } -rayon = "1.10.0" rust_decimal = { version = "1.13" } serde = { workspace = true } serde_json = { workspace = true } serde_prometheus = { version = "0.2" } -sha2 = { workspace = true } sysinfo = { version = "0.29" } thiserror = "2.0" tokio = { workspace = true } diff --git a/crates/fuel-streams-publisher/src/lib.rs b/crates/fuel-streams-publisher/src/lib.rs index dbbb3cc0..e2ba33f7 100644 --- a/crates/fuel-streams-publisher/src/lib.rs +++ b/crates/fuel-streams-publisher/src/lib.rs @@ -2,21 +2,8 @@ pub mod cli; pub mod publisher; pub mod server; pub mod telemetry; - -use std::{env, sync::LazyLock}; - pub use publisher::*; -pub static PUBLISHER_MAX_THREADS: LazyLock = LazyLock::new(|| { - let available_cpus = num_cpus::get(); - let default_threads = (available_cpus / 3).max(1); // Use 1/3 of CPUs, minimum 1 - - env::var("PUBLISHER_MAX_THREADS") - .ok() - .and_then(|val| val.parse().ok()) - .unwrap_or(default_threads) -}); - #[cfg(test)] #[macro_use] extern crate assert_matches; diff --git a/crates/fuel-streams-publisher/src/main.rs b/crates/fuel-streams-publisher/src/main.rs index db5c5366..b78b40be 100644 --- a/crates/fuel-streams-publisher/src/main.rs +++ b/crates/fuel-streams-publisher/src/main.rs @@ -4,13 +4,12 @@ use std::{ }; use clap::Parser; +use fuel_streams_core::prelude::*; use fuel_streams_publisher::{ cli::Cli, publisher::shutdown::ShutdownController, server::{http::create_web_server, state::ServerState}, telemetry::Telemetry, - FuelCore, - FuelCoreLike, }; #[tokio::main] diff --git a/crates/fuel-streams-publisher/src/publisher/blocks_streams.rs b/crates/fuel-streams-publisher/src/publisher/blocks_streams.rs index a40c0e00..eb222cd2 100644 --- a/crates/fuel-streams-publisher/src/publisher/blocks_streams.rs +++ b/crates/fuel-streams-publisher/src/publisher/blocks_streams.rs @@ -8,12 +8,10 @@ use futures::{ }; use tokio_stream::wrappers::BroadcastStream; -use crate::{fuel_core_like::FuelCoreLike, fuel_streams::FuelStreamsExt}; - pub fn build_blocks_stream<'a>( fuel_streams: &'a Arc, fuel_core: &'a Arc, - max_retained_blocks: u64, + max_retained_blocks: u32, ) -> BoxStream<'a, anyhow::Result> { #[derive(Debug, Default, Clone)] struct State { @@ -51,7 +49,7 @@ pub fn build_blocks_stream<'a>( let fuel_core = fuel_core.clone(); move |height| { - fuel_core.get_sealed_block_by_height(height as u32) + fuel_core.get_sealed_block_by_height(height) } }) .map(Ok) @@ -90,17 +88,17 @@ pub fn build_blocks_stream<'a>( async fn get_last_published_block_height( fuel_streams: Arc, - latest_block_height: u64, - max_retained_blocks: u64, -) -> anyhow::Result { + latest_block_height: u32, + max_retained_blocks: u32, +) -> anyhow::Result { let max_last_published_block_height = - max(0, latest_block_height as i64 - max_retained_blocks as i64) as u64; + max(0, latest_block_height as i32 - max_retained_blocks as i32) as u32; Ok(fuel_streams .get_last_published_block() .await? - .map(|block| block.height.into()) - .map(|block_height: u64| { + .map(|block| block.height) + .map(|block_height: u32| { max(block_height, max_last_published_block_height) }) .unwrap_or(max_last_published_block_height)) @@ -322,13 +320,14 @@ mod tests { #[async_trait::async_trait] impl FuelCoreLike for FuelCoreLike { - fn get_latest_block_height(&self) -> anyhow::Result; + fn get_latest_block_height(&self) -> anyhow::Result; fn get_sealed_block_by_height(&self, height: u32) -> FuelCoreSealedBlock; fn blocks_subscription(&self) -> broadcast::Receiver; async fn start(&self) -> anyhow::Result<()>; fn is_started(&self) -> bool; async fn await_synced_at_least_once(&self, historical: bool) -> anyhow::Result<()>; async fn stop(&self); + fn fuel_service(&self) -> &fuel_core_bin::FuelService; fn base_asset_id(&self) -> &FuelCoreAssetId; fn chain_id(&self) -> &FuelCoreChainId; fn database(&self) -> &CombinedDatabase; @@ -340,6 +339,10 @@ mod tests { &self, tx_id: &FuelCoreBytes32, ) -> anyhow::Result>>; + fn get_tx_status( + &self, + tx_id: &FuelCoreBytes32, + ) -> anyhow::Result>; } } diff --git a/crates/fuel-streams-publisher/src/publisher/mod.rs b/crates/fuel-streams-publisher/src/publisher/mod.rs index 4a7df81f..6851b301 100644 --- a/crates/fuel-streams-publisher/src/publisher/mod.rs +++ b/crates/fuel-streams-publisher/src/publisher/mod.rs @@ -1,6 +1,3 @@ -pub mod fuel_core_like; -pub mod fuel_streams; -pub mod payloads; pub mod shutdown; mod blocks_streams; @@ -9,17 +6,13 @@ use std::sync::Arc; use anyhow::Context; use blocks_streams::build_blocks_stream; -pub use fuel_core_like::{FuelCore, FuelCoreLike}; -pub use fuel_streams::{FuelStreams, FuelStreamsExt}; use fuel_streams_core::prelude::*; -use futures::{future::try_join_all, stream::FuturesUnordered, StreamExt}; -use tokio::sync::Semaphore; +use fuel_streams_executors::*; +use futures::StreamExt; use super::{ - payloads::blocks, shutdown::{ShutdownToken, GRACEFUL_SHUTDOWN_TIMEOUT}, telemetry::Telemetry, - PUBLISHER_MAX_THREADS, }; #[derive(Clone)] @@ -99,7 +92,7 @@ impl Publisher { } } - const MAX_RETAINED_BLOCKS: u64 = 100; + const MAX_RETAINED_BLOCKS: u32 = 100; pub async fn run( &self, shutdown_token: ShutdownToken, @@ -112,7 +105,6 @@ impl Publisher { .await?; tracing::info!("FuelCore has synced successfully!"); - tracing::info!("Publishing started..."); let mut blocks_stream = build_blocks_stream( @@ -130,7 +122,7 @@ impl Publisher { let fuel_core = &self.fuel_core; let (block, block_producer) = - fuel_core.get_block_and_producer(sealed_block); + fuel_core.get_block_and_producer(sealed_block.to_owned()); // TODO: Avoid awaiting Offchain DB sync for all streams by grouping in their own service fuel_core @@ -138,7 +130,7 @@ impl Publisher { .await .context("Failed to await Offchain DB sync")?; - if let Err(err) = self.publish(&block, &block_producer).await { + if let Err(err) = self.publish(sealed_block).await { tracing::error!("Failed to publish block data: {}", err); self.telemetry.record_failed_publishing(self.fuel_core.chain_id(), &block_producer); } @@ -155,131 +147,20 @@ impl Publisher { } tracing::info!("Publishing stopped successfully!"); - Ok(()) } async fn publish( &self, - block: &FuelCoreBlock, - block_producer: &Address, + sealed_block: FuelCoreSealedBlock, ) -> anyhow::Result<()> { - let start_time = std::time::Instant::now(); - - let semaphore = Arc::new(Semaphore::new(*PUBLISHER_MAX_THREADS)); - let chain_id = Arc::new(*self.fuel_core.chain_id()); - let base_asset_id = Arc::new(*self.fuel_core.base_asset_id()); - let block_producer = Arc::new(block_producer.clone()); - let block_height = block.header().consensus().height; - let txs = block.transactions(); - let transaction_ids = txs - .iter() - .map(|tx| tx.id(&chain_id).into()) - .collect::>(); - - let consensus: Consensus = - self.fuel_core.get_consensus(&block_height)?.into(); - - let fuel_core = &*self.fuel_core; - let offchain_database = fuel_core.offchain_database()?; - - let fuel_streams = &*self.fuel_streams; - let blocks_stream = Arc::new(fuel_streams.blocks().to_owned()); - let opts = &Arc::new(PublishOpts { - semaphore, - chain_id, - base_asset_id, - block_producer: Arc::clone(&block_producer), - block_height: Arc::new(block_height.into()), - telemetry: self.telemetry.clone(), - consensus: Arc::new(consensus), - offchain_database, - }); - - let publish_tasks = payloads::transactions::publish_all_tasks( - txs, - fuel_streams, - opts, - fuel_core, - )? - .into_iter() - .chain(std::iter::once(blocks::publish_task( - block, - blocks_stream, - opts, - transaction_ids, - ))) - .collect::>(); - - try_join_all(publish_tasks).await?; - - let elapsed = start_time.elapsed(); - tracing::info!( - "Published streams for BlockHeight: {} in {:?}", - *block_height, - elapsed - ); - + let metadata = Metadata::new(&self.fuel_core, &sealed_block); + let payload = Arc::new(BlockPayload::new( + Arc::clone(&self.fuel_core), + &sealed_block, + &metadata, + )?); + Executor::::process_all(payload, &self.fuel_streams).await?; Ok(()) } } - -use tokio::task::JoinHandle; - -use crate::fuel_core_like::OffchainDatabase; - -#[derive(Clone)] -pub struct PublishOpts { - pub semaphore: Arc, - pub chain_id: Arc, - pub base_asset_id: Arc, - pub block_producer: Arc
, - pub block_height: Arc, - pub telemetry: Arc, - pub consensus: Arc, - pub offchain_database: Arc, -} - -pub fn publish( - packet: &PublishPacket, - stream: Arc>, - opts: &Arc, -) -> JoinHandle> { - let opts = Arc::clone(opts); - let payload = Arc::clone(&packet.payload); - let subject = Arc::clone(&packet.subject); - let telemetry = Arc::clone(&opts.telemetry); - let wildcard = packet.subject.wildcard(); - - tokio::spawn(async move { - let _permit = opts.semaphore.acquire().await?; - - match stream.publish(&*subject, &payload).await { - Ok(published_data_size) => { - telemetry.log_info(&format!( - "Successfully published for stream: {}", - wildcard - )); - telemetry.update_publisher_success_metrics( - wildcard, - published_data_size, - &opts.chain_id, - &opts.block_producer, - ); - - Ok(()) - } - Err(e) => { - telemetry.log_error(&e.to_string()); - telemetry.update_publisher_error_metrics( - wildcard, - &opts.chain_id, - &opts.block_producer, - &e.to_string(), - ); - - anyhow::bail!("Failed to publish: {}", e.to_string()) - } - } - }) -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/blocks.rs b/crates/fuel-streams-publisher/src/publisher/payloads/blocks.rs deleted file mode 100644 index 5e59f728..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/blocks.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::sync::Arc; - -use fuel_streams_core::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_task( - block: &FuelCoreBlock, - stream: Arc>, - opts: &Arc, - transaction_ids: Vec, -) -> JoinHandle> { - let block_height = (*opts.block_height).clone(); - let block_producer = (*opts.block_producer).clone(); - let consensus = (*opts.consensus).clone(); - - let block = Block::new(block, consensus, transaction_ids); - let packet = PublishPacket::new( - block, - BlocksSubject { - height: Some(block_height), - producer: Some(block_producer), - } - .arc(), - ); - - publish(&packet, stream, opts) -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/inputs.rs b/crates/fuel-streams-publisher/src/publisher/payloads/inputs.rs deleted file mode 100644 index 88048d54..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/inputs.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::sync::Arc; - -use fuel_core_types::fuel_tx::input::{ - coin::{CoinPredicate, CoinSigned}, - message::{ - MessageCoinPredicate, - MessageCoinSigned, - MessageDataPredicate, - MessageDataSigned, - }, -}; -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_tasks( - tx: &FuelCoreTransaction, - tx_id: &Bytes32, - stream: &Stream, - opts: &Arc, -) -> Vec>> { - let packets = tx - .inputs() - .par_iter() - .enumerate() - .flat_map(move |(index, input)| { - let main_subject = main_subject(input, tx_id.clone(), index); - let identifier_subjects = identifiers(input, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: InputsByIdSubject| subject.arc()) - .collect::>(); - - let input: Input = input.into(); - - let mut packets = vec![input.to_packet(main_subject)]; - packets.extend( - identifier_subjects - .into_iter() - .map(|subject| input.to_packet(subject)), - ); - - packets - }) - .collect::>(); - - packets - .iter() - .map(|packet| publish(packet, Arc::new(stream.to_owned()), opts)) - .collect() -} - -fn main_subject( - input: &FuelCoreInput, - tx_id: Bytes32, - index: usize, -) -> Arc { - match input { - FuelCoreInput::Contract(contract) => { - let contract_id = contract.contract_id; - - InputsContractSubject { - tx_id: Some(tx_id), - index: Some(index), - contract_id: Some(contract_id.into()), - } - .arc() - } - FuelCoreInput::CoinSigned(CoinSigned { - owner, asset_id, .. - }) - | FuelCoreInput::CoinPredicate(CoinPredicate { - owner, asset_id, .. - }) => InputsCoinSubject { - tx_id: Some(tx_id), - index: Some(index), - owner: Some(owner.into()), - asset_id: Some(asset_id.into()), - } - .arc(), - FuelCoreInput::MessageCoinSigned(MessageCoinSigned { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageCoinPredicate(MessageCoinPredicate { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageDataSigned(MessageDataSigned { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageDataPredicate(MessageDataPredicate { - sender, - recipient, - .. - }) => InputsMessageSubject { - tx_id: Some(tx_id), - index: Some(index), - sender: Some(sender.into()), - recipient: Some(recipient.into()), - } - .arc(), - } -} - -pub fn identifiers( - input: &FuelCoreInput, - tx_id: &Bytes32, - index: u8, -) -> Vec { - let mut identifiers = match input { - FuelCoreInput::CoinSigned(CoinSigned { - owner, asset_id, .. - }) => { - vec![ - Identifier::Address(tx_id.to_owned(), index, owner.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreInput::CoinPredicate(CoinPredicate { - owner, asset_id, .. - }) => { - vec![ - Identifier::Address(tx_id.to_owned(), index, owner.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreInput::MessageCoinSigned(MessageCoinSigned { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageCoinPredicate(MessageCoinPredicate { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageDataSigned(MessageDataSigned { - sender, - recipient, - .. - }) - | FuelCoreInput::MessageDataPredicate(MessageDataPredicate { - sender, - recipient, - .. - }) => { - vec![ - Identifier::Address(tx_id.to_owned(), index, sender.into()), - Identifier::Address(tx_id.to_owned(), index, recipient.into()), - ] - } - FuelCoreInput::Contract(contract) => { - vec![Identifier::ContractID( - tx_id.to_owned(), - index, - contract.contract_id.into(), - )] - } - }; - - if let Some((predicate_bytecode, _, _)) = input.predicate() { - let predicate_tag = super::sha256(predicate_bytecode); - identifiers.push(Identifier::PredicateID( - tx_id.to_owned(), - index, - predicate_tag, - )); - } - - identifiers -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/logs.rs b/crates/fuel-streams-publisher/src/publisher/payloads/logs.rs deleted file mode 100644 index d443c1fc..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/logs.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::Arc; - -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_tasks( - tx_id: &Bytes32, - stream: &Stream, - opts: &Arc, - receipts: &Vec, -) -> Vec>> { - let block_height = (*opts.block_height).clone(); - let packets = receipts - .par_iter() - .enumerate() - .filter_map(|(index, receipt)| match receipt { - FuelCoreReceipt::Log { id, .. } - | FuelCoreReceipt::LogData { id, .. } => Some(PublishPacket::new( - receipt.to_owned().into(), - LogsSubject { - block_height: Some(block_height.clone()), - tx_id: Some(tx_id.to_owned()), - receipt_index: Some(index), - log_id: Some((*id).into()), - } - .arc(), - )), - _ => None, - }) - .collect::>(); - - packets - .iter() - .map(|packet| publish(packet, Arc::new(stream.to_owned()), opts)) - .collect() -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/mod.rs b/crates/fuel-streams-publisher/src/publisher/payloads/mod.rs deleted file mode 100644 index ac0ce74a..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub mod blocks; -pub mod inputs; -pub mod logs; -pub mod outputs; -pub mod receipts; -pub mod transactions; -pub mod utxos; - -use fuel_streams_core::prelude::Bytes32; -use sha2::{Digest, Sha256}; - -pub fn sha256(bytes: &[u8]) -> Bytes32 { - let mut sha256 = Sha256::new(); - sha256.update(bytes); - let bytes: [u8; 32] = sha256 - .finalize() - .as_slice() - .try_into() - .expect("Must be 32 bytes"); - - bytes.into() -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/outputs.rs b/crates/fuel-streams-publisher/src/publisher/payloads/outputs.rs deleted file mode 100644 index 0a61a974..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/outputs.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::sync::Arc; - -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_tasks( - tx: &FuelCoreTransaction, - tx_id: &Bytes32, - stream: &Stream, - opts: &Arc, -) -> Vec>> { - let packets: Vec> = tx - .outputs() - .par_iter() - .enumerate() - .flat_map(|(index, output)| { - let main_subject = main_subject(output, tx, tx_id, index); - let identifier_subjects = - identifiers(output, tx, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: OutputsByIdSubject| subject.arc()) - .collect::>(); - - let output: Output = output.into(); - - let mut packets = vec![output.to_packet(main_subject)]; - packets.extend( - identifier_subjects - .into_iter() - .map(|subject| output.to_packet(subject)), - ); - - packets - }) - .collect(); - - packets - .iter() - .map(|packet| publish(packet, Arc::new(stream.to_owned()), opts)) - .collect() -} - -fn main_subject( - output: &FuelCoreOutput, - transaction: &FuelCoreTransaction, - tx_id: &Bytes32, - index: usize, -) -> Arc { - match output { - FuelCoreOutput::Coin { to, asset_id, .. } => OutputsCoinSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index as u16), - to: Some((*to).into()), - asset_id: Some((*asset_id).into()), - } - .arc(), - - FuelCoreOutput::Contract(contract) => { - let contract_id = - match find_output_contract_id(transaction, contract) { - Some(contract_id) => contract_id, - None => { - tracing::warn!( - "Contract ID not found for output: {:?}", - output - ); - - Default::default() - } - }; - - OutputsContractSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index as u16), - contract_id: Some(contract_id.into()), - } - .arc() - } - - FuelCoreOutput::Change { to, asset_id, .. } => OutputsChangeSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index as u16), - to: Some((*to).into()), - asset_id: Some((*asset_id).into()), - } - .arc(), - - FuelCoreOutput::Variable { to, asset_id, .. } => { - OutputsVariableSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index as u16), - to: Some((*to).into()), - asset_id: Some((*asset_id).into()), - } - .arc() - } - - FuelCoreOutput::ContractCreated { contract_id, .. } => { - OutputsContractCreatedSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index as u16), - contract_id: Some((*contract_id).into()), - } - .arc() - } - } -} - -pub fn identifiers( - output: &FuelCoreOutput, - tx: &FuelCoreTransaction, - tx_id: &Bytes32, - index: u8, -) -> Vec { - match output { - FuelCoreOutput::Change { to, asset_id, .. } - | FuelCoreOutput::Variable { to, asset_id, .. } - | FuelCoreOutput::Coin { to, asset_id, .. } => { - vec![ - Identifier::Address(tx_id.to_owned(), index, to.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreOutput::Contract(contract) => { - find_output_contract_id(tx, contract) - .map(|contract_id| { - vec![Identifier::ContractID( - tx_id.to_owned(), - index, - contract_id.into(), - )] - }) - .unwrap_or_default() - } - FuelCoreOutput::ContractCreated { contract_id, .. } => { - vec![Identifier::ContractID( - tx_id.to_owned(), - index, - contract_id.into(), - )] - } - } -} - -pub fn find_output_contract_id( - tx: &FuelCoreTransaction, - contract: &FuelCoreOutputContract, -) -> Option { - let input_index = contract.input_index as usize; - tx.inputs().get(input_index).and_then(|input| { - if let FuelCoreInput::Contract(input_contract) = input { - Some(input_contract.contract_id) - } else { - None - } - }) -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/receipts.rs b/crates/fuel-streams-publisher/src/publisher/payloads/receipts.rs deleted file mode 100644 index e0936f5f..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/receipts.rs +++ /dev/null @@ -1,235 +0,0 @@ -use std::sync::Arc; - -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_tasks( - tx_id: &Bytes32, - stream: &Stream, - opts: &Arc, - receipts: &Vec, -) -> Vec>> { - let packets: Vec> = receipts - .par_iter() - .enumerate() - .flat_map(|(index, receipt)| { - let main_subject = main_subject(receipt, tx_id, index); - let identifier_subjects = identifiers(receipt, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: ReceiptsByIdSubject| subject.arc()) - .collect::>(); - - let receipt: Receipt = receipt.into(); - - let mut packets = vec![receipt.to_packet(main_subject)]; - packets.extend( - identifier_subjects - .into_iter() - .map(|subject| receipt.to_packet(subject)), - ); - - packets - }) - .collect(); - - packets - .iter() - .map(|packet| publish(packet, Arc::new(stream.to_owned()), opts)) - .collect() -} - -fn main_subject( - receipt: &FuelCoreReceipt, - tx_id: &Bytes32, - index: usize, -) -> Arc { - match receipt { - FuelCoreReceipt::Call { - id: from, - to, - asset_id, - .. - } => ReceiptsCallSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - from: Some(from.into()), - to: Some(to.into()), - asset_id: Some(asset_id.into()), - } - .arc(), - FuelCoreReceipt::Return { id, .. } => ReceiptsReturnSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::ReturnData { id, .. } => ReceiptsReturnDataSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::Panic { id, .. } => ReceiptsPanicSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::Revert { id, .. } => ReceiptsRevertSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::Log { id, .. } => ReceiptsLogSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::LogData { id, .. } => ReceiptsLogDataSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - id: Some(id.into()), - } - .arc(), - FuelCoreReceipt::Transfer { - id: from, - to, - asset_id, - .. - } => ReceiptsTransferSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - from: Some(from.into()), - to: Some(to.into()), - asset_id: Some(asset_id.into()), - } - .arc(), - - FuelCoreReceipt::TransferOut { - id: from, - to, - asset_id, - .. - } => ReceiptsTransferOutSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - from: Some(from.into()), - to: Some(to.into()), - asset_id: Some(asset_id.into()), - } - .arc(), - - FuelCoreReceipt::ScriptResult { .. } => ReceiptsScriptResultSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - } - .arc(), - FuelCoreReceipt::MessageOut { - sender, recipient, .. - } => ReceiptsMessageOutSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - sender: Some(sender.into()), - recipient: Some(recipient.into()), - } - .arc(), - FuelCoreReceipt::Mint { - contract_id, - sub_id, - .. - } => ReceiptsMintSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - contract_id: Some(contract_id.into()), - sub_id: Some((*sub_id).into()), - } - .arc(), - FuelCoreReceipt::Burn { - contract_id, - sub_id, - .. - } => ReceiptsBurnSubject { - tx_id: Some(tx_id.to_owned()), - index: Some(index), - contract_id: Some(contract_id.into()), - sub_id: Some((*sub_id).into()), - } - .arc(), - } -} - -pub fn identifiers( - receipt: &FuelCoreReceipt, - tx_id: &Bytes32, - index: u8, -) -> Vec { - match receipt { - FuelCoreReceipt::Call { - id: from, - to, - asset_id, - .. - } => { - vec![ - Identifier::ContractID(tx_id.to_owned(), index, from.into()), - Identifier::ContractID(tx_id.to_owned(), index, to.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreReceipt::Return { id, .. } - | FuelCoreReceipt::ReturnData { id, .. } - | FuelCoreReceipt::Panic { id, .. } - | FuelCoreReceipt::Revert { id, .. } - | FuelCoreReceipt::Log { id, .. } - | FuelCoreReceipt::LogData { id, .. } => { - vec![Identifier::ContractID(tx_id.to_owned(), index, id.into())] - } - FuelCoreReceipt::Transfer { - id: from, - to, - asset_id, - .. - } => { - vec![ - Identifier::ContractID(tx_id.to_owned(), index, from.into()), - Identifier::ContractID(tx_id.to_owned(), index, to.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreReceipt::TransferOut { - id: from, - to, - asset_id, - .. - } => { - vec![ - Identifier::ContractID(tx_id.to_owned(), index, from.into()), - Identifier::ContractID(tx_id.to_owned(), index, to.into()), - Identifier::AssetID(tx_id.to_owned(), index, asset_id.into()), - ] - } - FuelCoreReceipt::MessageOut { - sender, recipient, .. - } => { - vec![ - Identifier::Address(tx_id.to_owned(), index, sender.into()), - Identifier::Address(tx_id.to_owned(), index, recipient.into()), - ] - } - FuelCoreReceipt::Mint { contract_id, .. } - | FuelCoreReceipt::Burn { contract_id, .. } => { - vec![Identifier::ContractID( - tx_id.to_owned(), - index, - contract_id.into(), - )] - } - _ => Vec::new(), - } -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/transactions.rs b/crates/fuel-streams-publisher/src/publisher/payloads/transactions.rs deleted file mode 100644 index fc97edc6..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/transactions.rs +++ /dev/null @@ -1,177 +0,0 @@ -use std::sync::Arc; - -use fuel_core_types::fuel_tx::field::ScriptData; -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use super::{ - inputs::{self, publish_tasks as publish_inputs}, - logs::publish_tasks as publish_logs, - outputs::{self, publish_tasks as publish_outputs}, - receipts::{self, publish_tasks as publish_receipts}, - sha256, - utxos::publish_tasks as publish_utxos, -}; -use crate::{publish, FuelCoreLike, FuelStreamsExt, PublishOpts}; - -pub fn publish_all_tasks( - transactions: &[FuelCoreTransaction], - fuel_streams: &dyn FuelStreamsExt, - opts: &Arc, - fuel_core: &dyn FuelCoreLike, -) -> anyhow::Result>>> { - let offchain_database = Arc::clone(&opts.offchain_database); - let mut tasks = vec![]; - - for tx_item @ (_, tx) in transactions.iter().enumerate() { - let tx_id = tx.id(&opts.chain_id); - let tx_status: TransactionStatus = offchain_database - .get_tx_status(&tx_id)? - .map(|status| (&status).into()) - .unwrap_or_default(); - - let receipts = fuel_core.get_receipts(&tx_id)?.unwrap_or_default(); - - let tx_id = tx_id.into(); - - tasks.extend(publish_tasks( - tx_item, - &tx_id, - &tx_status, - fuel_streams.transactions(), - opts, - &receipts, - )); - tasks.extend(publish_inputs(tx, &tx_id, fuel_streams.inputs(), opts)); - tasks.extend(publish_outputs(tx, &tx_id, fuel_streams.outputs(), opts)); - tasks.extend(publish_receipts( - &tx_id, - fuel_streams.receipts(), - opts, - &receipts, - )); - tasks.extend(publish_outputs(tx, &tx_id, fuel_streams.outputs(), opts)); - tasks.extend(publish_logs( - &tx_id, - fuel_streams.logs(), - opts, - &receipts, - )); - tasks.extend(publish_utxos(tx, &tx_id, fuel_streams.utxos(), opts)); - } - - Ok(tasks) -} - -fn publish_tasks( - tx_item: (usize, &FuelCoreTransaction), - tx_id: &Bytes32, - tx_status: &TransactionStatus, - stream: &Stream, - opts: &Arc, - receipts: &Vec, -) -> Vec>> { - let block_height = &opts.block_height; - let base_asset_id = &opts.base_asset_id; - - packets_from_tx( - tx_item, - tx_id, - tx_status, - base_asset_id, - block_height, - receipts, - ) - .iter() - .map(|packet| publish(packet, Arc::new(stream.to_owned()), opts)) - .collect() -} - -fn packets_from_tx( - (index, tx): (usize, &FuelCoreTransaction), - tx_id: &Bytes32, - tx_status: &TransactionStatus, - base_asset_id: &FuelCoreAssetId, - block_height: &BlockHeight, - receipts: &Vec, -) -> Vec> { - let main_subject = TransactionsSubject { - block_height: Some(block_height.to_owned()), - index: Some(index), - tx_id: Some(tx_id.to_owned()), - status: Some(tx_status.to_owned()), - kind: Some(tx.into()), - } - .arc(); - - let transaction = - Transaction::new(tx_id, tx, tx_status, base_asset_id, receipts); - let mut packets = vec![transaction.to_packet(main_subject)]; - - packets.extend( - identifiers(tx, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: TransactionsByIdSubject| subject.arc()) - .map(|subject| transaction.to_packet(subject)) - .collect::>(), - ); - - let packets_from_inputs: Vec> = tx - .inputs() - .par_iter() - .flat_map(|input| { - inputs::identifiers(input, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: TransactionsByIdSubject| subject.arc()) - .map(|subject| transaction.to_packet(subject)) - }) - .collect(); - - packets.extend(packets_from_inputs); - - let packets_from_outputs: Vec> = tx - .outputs() - .par_iter() - .flat_map(|output| { - outputs::identifiers(output, tx, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: TransactionsByIdSubject| subject.arc()) - .map(|subject| transaction.to_packet(subject)) - }) - .collect(); - - packets.extend(packets_from_outputs); - - let packets_from_receipts: Vec> = receipts - .par_iter() - .flat_map(|receipt| { - receipts::identifiers(receipt, tx_id, index as u8) - .into_par_iter() - .map(|identifier| identifier.into()) - .map(|subject: TransactionsByIdSubject| subject.arc()) - .map(|subject| transaction.to_packet(subject)) - }) - .collect(); - - packets.extend(packets_from_receipts); - - packets -} - -fn identifiers( - tx: &FuelCoreTransaction, - tx_id: &Bytes32, - index: u8, -) -> Vec { - match tx { - FuelCoreTransaction::Script(tx) => { - let script_tag = sha256(tx.script_data()); - vec![Identifier::ScriptID(tx_id.to_owned(), index, script_tag)] - } - _ => Vec::new(), - } -} diff --git a/crates/fuel-streams-publisher/src/publisher/payloads/utxos.rs b/crates/fuel-streams-publisher/src/publisher/payloads/utxos.rs deleted file mode 100644 index 0e4d1f89..00000000 --- a/crates/fuel-streams-publisher/src/publisher/payloads/utxos.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::sync::Arc; - -use fuel_core_types::fuel_tx::{ - input::{ - coin::{CoinPredicate, CoinSigned}, - contract::Contract, - message::{ - compute_message_id, - MessageCoinPredicate, - MessageCoinSigned, - MessageDataPredicate, - MessageDataSigned, - }, - }, - UtxoId, -}; -use fuel_streams_core::prelude::*; -use rayon::prelude::*; -use tokio::task::JoinHandle; - -use crate::{publish, PublishOpts}; - -pub fn publish_tasks( - tx: &FuelCoreTransaction, - tx_id: &Bytes32, - stream: &Stream, - opts: &Arc, -) -> Vec>> { - let packets = tx - .inputs() - .par_iter() - .filter_map(|input| utxo_packet(input, tx_id, input.utxo_id().cloned())) - .collect::>(); - - packets - .into_iter() - .map(|packet| publish(&packet, Arc::new(stream.to_owned()), opts)) - .collect() -} - -fn utxo_packet( - input: &FuelCoreInput, - tx_id: &Bytes32, - utxo_id: Option, -) -> Option> { - utxo_id?; - let utxo_id = utxo_id.expect("safe to unwrap utxo"); - - match input { - FuelCoreInput::Contract(Contract { utxo_id, .. }) => { - let utxo = Utxo { - utxo_id: utxo_id.into(), - tx_id: tx_id.to_owned(), - ..Default::default() - }; - - let subject = UtxosSubject { - utxo_type: Some(UtxoType::Contract), - hash: Some(tx_id.to_owned().into()), - } - .arc(); - - Some(utxo.to_packet(subject)) - } - FuelCoreInput::CoinSigned(CoinSigned { - utxo_id, amount, .. - }) - | FuelCoreInput::CoinPredicate(CoinPredicate { - utxo_id, amount, .. - }) => { - let utxo = Utxo { - utxo_id: utxo_id.into(), - amount: Some(*amount), - tx_id: tx_id.to_owned(), - ..Default::default() - }; - - let subject = UtxosSubject { - utxo_type: Some(UtxoType::Coin), - hash: Some(tx_id.to_owned().into()), - } - .arc(); - - Some(utxo.to_packet(subject)) - } - message @ (FuelCoreInput::MessageCoinSigned(MessageCoinSigned { - amount, - nonce, - recipient, - sender, - .. - }) - | FuelCoreInput::MessageCoinPredicate( - MessageCoinPredicate { - amount, - nonce, - recipient, - sender, - .. - }, - ) - | FuelCoreInput::MessageDataSigned(MessageDataSigned { - amount, - nonce, - recipient, - sender, - .. - }) - | FuelCoreInput::MessageDataPredicate( - MessageDataPredicate { - amount, - nonce, - recipient, - sender, - .. - }, - )) => { - let (data, hash) = if let Some(data) = message.input_data() { - let hash: MessageId = - compute_message_id(sender, recipient, nonce, *amount, data) - .into(); - (Some(data.to_vec()), hash) - } else { - (None, tx_id.to_owned().into()) - }; - - let utxo = Utxo { - utxo_id: utxo_id.into(), - sender: Some(sender.into()), - recipient: Some(recipient.into()), - nonce: Some(nonce.into()), - amount: Some(*amount), - tx_id: tx_id.to_owned(), - data, - }; - let subject = UtxosSubject { - utxo_type: Some(UtxoType::Message), - hash: Some(hash), - } - .arc(); - - Some(utxo.to_packet(subject)) - } - } -} diff --git a/crates/fuel-streams-publisher/src/server/http.rs b/crates/fuel-streams-publisher/src/server/http.rs index 32d0ec73..c86eea36 100644 --- a/crates/fuel-streams-publisher/src/server/http.rs +++ b/crates/fuel-streams-publisher/src/server/http.rs @@ -58,7 +58,6 @@ pub fn create_web_server( } #[cfg(test)] -#[cfg(feature = "test-helpers")] mod tests { use std::time::Duration; @@ -66,11 +65,11 @@ mod tests { use fuel_core::service::Config; use fuel_core_bin::FuelService; use fuel_core_services::State; + use fuel_streams_core::fuel_core_like::FuelCore; use crate::{ server::state::{HealthResponse, ServerState}, telemetry::Telemetry, - FuelCore, Publisher, }; diff --git a/crates/fuel-streams-publisher/src/telemetry/system.rs b/crates/fuel-streams-publisher/src/telemetry/system.rs index ec0f14eb..bae499a0 100644 --- a/crates/fuel-streams-publisher/src/telemetry/system.rs +++ b/crates/fuel-streams-publisher/src/telemetry/system.rs @@ -572,26 +572,20 @@ mod tests { kernel_version: "kernel-version".to_string(), uptime: 123456, }, - disk: vec![( - PathBuf::from("disk1"), - Disk { - size: 1000, - free: 877, - usage: Decimal::new(1234, 2), - }, - )] + disk: vec![(PathBuf::from("disk1"), Disk { + size: 1000, + free: 877, + usage: Decimal::new(1234, 2), + })] .into_iter() .collect(), cpu_physical_core_count: 1, cpu_count: 1, - cpu: vec![( - 1, - Cpu { - name: "cpu1".to_string(), - frequency: 12345, - usage: Decimal::new(1234, 2), - }, - )] + cpu: vec![(1, Cpu { + name: "cpu1".to_string(), + frequency: 12345, + usage: Decimal::new(1234, 2), + })] .into_iter() .collect(), }, @@ -600,35 +594,32 @@ mod tests { let output = serde_prometheus::to_string(&metrics, None, &[]) .expect("prometheus"); - assert_eq!( - output.trim_end().split('\n').collect::>(), - vec![ - r#"system_application_pid 0"#, - r#"system_application_name{path = "process"} 1"#, - r#"system_application_cpu_usage 12.34"#, - r#"system_application_size{type = "memory"} 1000"#, - r#"system_application_free{type = "memory"} 877"#, - r#"system_application_usage{type = "memory"} 12.34"#, - r#"system_memory_size{type = "system"} 1000"#, - r#"system_memory_free{type = "system"} 877"#, - r#"system_memory_usage{type = "system"} 12.34"#, - r#"system_memory_size{type = "swap"} 1000"#, - r#"system_memory_free{type = "swap"} 877"#, - r#"system_memory_usage{type = "swap"} 12.34"#, - r#"system_load_average_1 1.2"#, - r#"system_load_average_5 2.3"#, - r#"system_load_average_15 3.4"#, - r#"system_host_os_version{path = "os-version"} 1"#, - r#"system_host_kernel_version{path = "kernel-version"} 1"#, - r#"system_host_uptime 123456"#, - r#"system_disk_size{path = "disk1"} 1000"#, - r#"system_disk_free{path = "disk1"} 877"#, - r#"system_disk_usage{path = "disk1"} 12.34"#, - r#"system_cpu_physical_core_count 1"#, - r#"system_cpu_count 1"#, - r#"system_cpu_frequency{id = "1"} 12345"#, - r#"system_cpu_usage{id = "1"} 12.34"#, - ] - ) + assert_eq!(output.trim_end().split('\n').collect::>(), vec![ + r#"system_application_pid 0"#, + r#"system_application_name{path = "process"} 1"#, + r#"system_application_cpu_usage 12.34"#, + r#"system_application_size{type = "memory"} 1000"#, + r#"system_application_free{type = "memory"} 877"#, + r#"system_application_usage{type = "memory"} 12.34"#, + r#"system_memory_size{type = "system"} 1000"#, + r#"system_memory_free{type = "system"} 877"#, + r#"system_memory_usage{type = "system"} 12.34"#, + r#"system_memory_size{type = "swap"} 1000"#, + r#"system_memory_free{type = "swap"} 877"#, + r#"system_memory_usage{type = "swap"} 12.34"#, + r#"system_load_average_1 1.2"#, + r#"system_load_average_5 2.3"#, + r#"system_load_average_15 3.4"#, + r#"system_host_os_version{path = "os-version"} 1"#, + r#"system_host_kernel_version{path = "kernel-version"} 1"#, + r#"system_host_uptime 123456"#, + r#"system_disk_size{path = "disk1"} 1000"#, + r#"system_disk_free{path = "disk1"} 877"#, + r#"system_disk_usage{path = "disk1"} 12.34"#, + r#"system_cpu_physical_core_count 1"#, + r#"system_cpu_count 1"#, + r#"system_cpu_frequency{id = "1"} 12345"#, + r#"system_cpu_usage{id = "1"} 12.34"#, + ]) } } diff --git a/crates/sv-consumer/Cargo.toml b/crates/sv-consumer/Cargo.toml new file mode 100644 index 00000000..ed27f473 --- /dev/null +++ b/crates/sv-consumer/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "sv-consumer" +description = "Service that consumers new blocks from the emitter" +authors = { workspace = true } +keywords = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +version = { workspace = true } +rust-version = { workspace = true } +publish = false + +[[bin]] +name = "sv-consumer" +path = "src/main.rs" + +[dependencies] +anyhow = { workspace = true } +async-nats = { workspace = true } +clap = { workspace = true } +fuel-core = { workspace = true, default-features = false, features = ["p2p", "relayer", "rocksdb"] } +fuel-streams-core = { workspace = true, features = ["test-helpers"] } +fuel-streams-executors = { workspace = true, features = ["test-helpers"] } +futures = { workspace = true } +serde_json = { workspace = true } +sv-emitter = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tokio-util = "0.7.13" +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["local-time"] } + +[features] +default = [] +test-helpers = [] + +[target.x86_64-unknown-linux-gnu.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.x86_64-unknown-linux-musl.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.aarch64-unknown-linux-gnu.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.aarch64-unknown-linux-musl.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } diff --git a/crates/sv-consumer/src/cli.rs b/crates/sv-consumer/src/cli.rs new file mode 100644 index 00000000..2f893567 --- /dev/null +++ b/crates/sv-consumer/src/cli.rs @@ -0,0 +1,22 @@ +use clap::Parser; + +#[derive(Clone, Parser)] +pub struct Cli { + /// Fuel Network to connect to. + #[arg( + long, + value_name = "NATS_CORE_URL", + env = "NATS_CORE_URL", + default_value = "localhost:4222", + help = "NATS Core URL to connect to." + )] + pub nats_core_url: String, + #[arg( + long, + value_name = "NATS_PUBLISHER_URL", + env = "NATS_PUBLISHER_URL", + default_value = "localhost:4222", + help = "NATS Publisher URL to connect to." + )] + pub nats_publisher_url: String, +} diff --git a/crates/sv-consumer/src/lib.rs b/crates/sv-consumer/src/lib.rs new file mode 100644 index 00000000..ddf67e02 --- /dev/null +++ b/crates/sv-consumer/src/lib.rs @@ -0,0 +1,31 @@ +use std::sync::Arc; + +use fuel_streams_core::prelude::*; + +pub mod cli; + +#[derive(Debug, Clone, Default)] +pub enum Client { + #[default] + Core, + Publisher, +} + +impl Client { + pub fn url(&self, cli: &cli::Cli) -> String { + match self { + Client::Core => cli.nats_core_url.clone(), + Client::Publisher => cli.nats_publisher_url.clone(), + } + } + pub async fn create( + &self, + cli: &cli::Cli, + ) -> Result, NatsError> { + let url = self.url(cli); + let opts = NatsClientOpts::admin_opts(None) + .with_custom_url(url) + .with_domain("CORE".to_string()); + Ok(Arc::new(NatsClient::connect(&opts).await?)) + } +} diff --git a/crates/sv-consumer/src/main.rs b/crates/sv-consumer/src/main.rs new file mode 100644 index 00000000..d764048e --- /dev/null +++ b/crates/sv-consumer/src/main.rs @@ -0,0 +1,134 @@ +use std::{sync::Arc, time::Duration}; + +use async_nats::jetstream::{ + consumer::{ + pull::{BatchErrorKind, Config as ConsumerConfig}, + Consumer, + }, + context::CreateStreamErrorKind, + stream::{ConsumerErrorKind, RetentionPolicy}, +}; +use clap::Parser; +use fuel_streams_core::prelude::*; +use fuel_streams_executors::*; +use futures::StreamExt; +use sv_consumer::{cli::Cli, Client}; +use sv_emitter::shutdown::ShutdownController; +use tokio_util::sync::CancellationToken; +use tracing_subscriber::fmt::time; + +#[derive(thiserror::Error, Debug)] +pub enum ConsumerError { + #[error("Failed to receive batch of messages from NATS: {0}")] + BatchStream(#[from] async_nats::error::Error), + + #[error("Failed to create stream: {0}")] + CreateStream(#[from] async_nats::error::Error), + + #[error("Failed to create consumer: {0}")] + CreateConsumer(#[from] async_nats::error::Error), + + #[error("Failed to connect to NATS client: {0}")] + NatsClient(#[from] NatsError), + + #[error("Failed to communicate with NATS server: {0}")] + Nats(#[from] async_nats::Error), + + #[error("Failed to deserialize block payload from message: {0}")] + Deserialization(#[from] serde_json::Error), + + #[error("Failed to publish block to stream: {0}")] + Publish(#[from] ExecutorError), + + #[error("Failed to decode UTF-8: {0}")] + Utf8(#[from] std::str::Utf8Error), +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Initialize tracing subscriber + tracing_subscriber::fmt() + .with_env_filter("sv_consumer=trace,fuel_streams_executors=trace") + .with_timer(time::LocalTime::rfc_3339()) + .with_target(false) + .with_thread_ids(false) + .with_file(true) + .with_line_number(true) + .with_level(true) + .init(); + + let cli = Cli::parse(); + let shutdown = Arc::new(ShutdownController::new()); + shutdown.clone().spawn_signal_handler(); + + tracing::info!("Consumer started. Waiting for messages..."); + tokio::select! { + result = async { + process_messages(&cli, shutdown.token()) + .await + } => { + result?; + tracing::info!("Processing complete"); + } + _ = shutdown.wait_for_shutdown() => { + tracing::info!("Shutdown signal received"); + } + }; + + tracing::info!("Shutdown complete"); + Ok(()) +} + +async fn setup_nats( + cli: &Cli, +) -> Result< + (Arc, Arc, Consumer), + ConsumerError, +> { + let core_client = Client::Core.create(cli).await?; + let publisher_client = Client::Publisher.create(cli).await?; + let stream_name = publisher_client.namespace.stream_name("block_importer"); + let stream = publisher_client + .jetstream + .get_or_create_stream(async_nats::jetstream::stream::Config { + name: stream_name, + subjects: vec!["block_submitted.>".to_string()], + retention: RetentionPolicy::WorkQueue, + duplicate_window: Duration::from_secs(1), + allow_rollup: true, + ..Default::default() + }) + .await?; + + let consumer = stream + .get_or_create_consumer("block_importer", ConsumerConfig { + durable_name: Some("block_importer".to_string()), + ack_policy: AckPolicy::Explicit, + ..Default::default() + }) + .await?; + + Ok((core_client, publisher_client, consumer)) +} + +async fn process_messages( + cli: &Cli, + token: &CancellationToken, +) -> Result<(), ConsumerError> { + let (core_client, publisher_client, consumer) = setup_nats(cli).await?; + let (_, publisher_stream) = + FuelStreams::setup_all(&core_client, &publisher_client).await; + let fuel_streams: Arc = publisher_stream.arc(); + while !token.is_cancelled() { + let messages = consumer.fetch().max_messages(100).messages().await?; + tokio::pin!(messages); + while let Some(msg) = messages.next().await { + let msg = msg?; + let msg_str = std::str::from_utf8(&msg.payload)?; + let payload = Arc::new(BlockPayload::decode(msg_str)?); + Executor::::process_all(payload, &fuel_streams).await?; + msg.ack().await?; + } + } + Ok(()) +} diff --git a/crates/sv-emitter/Cargo.lock b/crates/sv-emitter/Cargo.lock new file mode 100644 index 00000000..046abc4a --- /dev/null +++ b/crates/sv-emitter/Cargo.lock @@ -0,0 +1,7553 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "asn1-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + +[[package]] +name = "async-graphql" +version = "4.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ed522678d412d77effe47b3c82314ac36952a35e6e852093dd48287c421f80" +dependencies = [ + "async-graphql-derive", + "async-graphql-parser", + "async-graphql-value", + "async-stream", + "async-trait", + "base64 0.13.1", + "bytes", + "fnv", + "futures-util", + "http", + "indexmap 1.9.3", + "mime", + "multer", + "num-traits", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "static_assertions", + "tempfile", + "thiserror", + "tracing", + "tracing-futures", +] + +[[package]] +name = "async-graphql-derive" +version = "4.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c121a894495d7d3fc3d4e15e0a9843e422e4d1d9e3c514d8062a1c94b35b005d" +dependencies = [ + "Inflector", + "async-graphql-parser", + "darling 0.14.4", + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "async-graphql-parser" +version = "4.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6c386f398145c6180206c1869c2279f5a3d45db5be4e0266148c6ac5c6ad68" +dependencies = [ + "async-graphql-value", + "pest", + "serde", + "serde_json", +] + +[[package]] +name = "async-graphql-value" +version = "4.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a941b499fead4a3fb5392cabf42446566d18c86313f69f2deab69560394d65f" +dependencies = [ + "bytes", + "indexmap 1.9.3", + "serde", + "serde_json", +] + +[[package]] +name = "async-io" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-nats" +version = "0.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8df97cb8fc4a884af29ab383e9292ea0939cfcdd7d2a17179086dc6c427e7f" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "memchr", + "nkeys", + "nuid", + "once_cell", + "portable-atomic", + "rand", + "regex", + "ring 0.17.8", + "rustls-native-certs", + "rustls-pemfile 2.1.2", + "rustls-webpki 0.102.4", + "serde", + "serde_json", + "serde_nanos", + "serde_repr", + "thiserror", + "time", + "tokio", + "tokio-rustls 0.26.0", + "tracing", + "tryhard", + "url", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "asynchronous-codec" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http", + "log", + "url", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "serde", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.66", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.8", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.5", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive 3.2.25", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive 4.5.4", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex 0.7.0", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2", + "rand", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496c993b62bdfbe9b4c518b8b3e1fdba9f89ef89fcccc050ab61d91dfba9fbaf" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b922abb6be41fc383f5e9da65b58d32d0d0a32c87dfe3bbbcb61a09119506c" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.5", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634c2ed9ef8a04ca42535a3e2e7917e4b551f2f306f4df2d935a6e71e346c167" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00cde1425b4da28bb0d5ff010030ea9cc9be7aded342ae099b394284f17cefce" + +[[package]] +name = "cranelift-control" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1622125c99f1864aaf44e57971770c4a918d081d4b4af0bb597bdf624660ed66" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea97887aca1c0cbe7f8513874dc3603e9744fb1cfa78840ca8897bd2766bd35b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cdade4c14183fe41482071ed77d6a38cb95a17c7a0a05e629152e6292c4f8cb" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbbe4d3ad7bd4bf4a8d916c8460b441cf92417f5cdeacce4dd1d96eee70b18a2" + +[[package]] +name = "cranelift-native" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c46be4ed1fc8f36df4e2a442b8c30a39d8c03c1868182978f4c04ba2c25c9d4f" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.105.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d4c4a785a7866da89d20df159e3c4f96a5f14feb83b1f5998cfd5fe2e74d06" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools 0.10.5", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +dependencies = [ + "darling_core 0.20.9", + "darling_macro 0.20.9", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.66", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +dependencies = [ + "darling_core 0.20.9", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-encoding-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2 0.10.8", + "signature", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.66", + "toml 0.8.13", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.66", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum 0.26.2", + "syn 2.0.66", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethnum" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuel-asm" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42df651415e443094f86102473b7f9fa23633ab6c3c98dd3f713adde251acf0f" +dependencies = [ + "bitflags 2.5.0", + "fuel-types", + "serde", + "strum 0.24.1", +] + +[[package]] +name = "fuel-core" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b030e12851d70598e12722886b899e28884d168367fc20d9a809951dd599004" +dependencies = [ + "anyhow", + "async-graphql", + "async-trait", + "axum", + "clap 4.5.4", + "derive_more", + "enum-iterator", + "fuel-core-chain-config", + "fuel-core-consensus-module", + "fuel-core-database", + "fuel-core-executor", + "fuel-core-importer", + "fuel-core-metrics", + "fuel-core-p2p", + "fuel-core-poa", + "fuel-core-producer", + "fuel-core-relayer", + "fuel-core-services", + "fuel-core-storage", + "fuel-core-sync", + "fuel-core-txpool", + "fuel-core-types", + "fuel-core-upgradable-executor", + "futures", + "hex", + "hyper", + "indicatif", + "itertools 0.12.1", + "num_cpus", + "rand", + "rocksdb", + "serde", + "serde_json", + "strum 0.25.0", + "strum_macros 0.25.3", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower-http", + "tracing", + "uuid", +] + +[[package]] +name = "fuel-core-bin" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5ff2b6ce36b11e79f338b22fe436962d8d587b60a8d751c6bef2b7cb5d89bb" +dependencies = [ + "anyhow", + "async-trait", + "clap 4.5.4", + "const_format", + "dirs", + "dotenvy", + "fuel-core", + "fuel-core-chain-config", + "fuel-core-types", + "hex", + "humantime", + "pyroscope", + "pyroscope_pprofrs", + "serde_json", + "tikv-jemallocator", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "fuel-core-chain-config" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d202fe1dfeb98882bdc5a0206a58e469d76fd09d952c4050bb979102bd690398" +dependencies = [ + "anyhow", + "bech32", + "derivative", + "fuel-core-storage", + "fuel-core-types", + "itertools 0.12.1", + "postcard", + "serde", + "serde_json", + "serde_with", + "tracing", +] + +[[package]] +name = "fuel-core-consensus-module" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f99179c08972efffe7628f0ff8d59028218b126347a6f9eba86f71e20966eeb" +dependencies = [ + "anyhow", + "fuel-core-chain-config", + "fuel-core-poa", + "fuel-core-storage", + "fuel-core-types", +] + +[[package]] +name = "fuel-core-database" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b1fd08a72609ebf0c8106359a37a4b205055be15e9f4fc30a4c0b5f0644c6b" +dependencies = [ + "anyhow", + "derive_more", + "fuel-core-storage", + "fuel-core-types", +] + +[[package]] +name = "fuel-core-executor" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f98d89798007bc781d56e02681144683f5c645ee0725e7717e38694e8e5e31d" +dependencies = [ + "anyhow", + "fuel-core-storage", + "fuel-core-types", + "hex", + "parking_lot", + "serde", + "tracing", +] + +[[package]] +name = "fuel-core-importer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51837a53f2d8b78a701aee61b99c7f1873f23e864f01f4b4d0644a06e1f7c41" +dependencies = [ + "anyhow", + "derive_more", + "fuel-core-metrics", + "fuel-core-storage", + "fuel-core-types", + "tokio", + "tokio-rayon", + "tracing", +] + +[[package]] +name = "fuel-core-metrics" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bacc62bc4fec2fe6a818a1a7145b892bd486d69266190ca8dd31a036a3a327b7" +dependencies = [ + "axum", + "once_cell", + "pin-project-lite", + "prometheus-client", + "regex", + "tracing", +] + +[[package]] +name = "fuel-streams-publisher" +version = "0.26.0" +dependencies = [ + "anyhow", + "async-nats", + "clap 4.5.4", + "fuel-core", + "fuel-core-bin", + "fuel-core-services", + "fuel-core-types", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "fuel-core-p2p" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6496068f0f5736f9e51bba8f8bb04cb83f68df2f6142e410fe62854b47621b3" +dependencies = [ + "anyhow", + "async-trait", + "fuel-core-chain-config", + "fuel-core-metrics", + "fuel-core-services", + "fuel-core-storage", + "fuel-core-types", + "futures", + "hex", + "ip_network", + "libp2p", + "libp2p-mplex", + "postcard", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand", + "serde", + "serde_with", + "sha2 0.10.8", + "thiserror", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "fuel-core-poa" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d189ecd635688ddc896b44c8497b29c04bb4a3719a24eea0ca9691a6f76d5e" +dependencies = [ + "anyhow", + "async-trait", + "fuel-core-chain-config", + "fuel-core-services", + "fuel-core-storage", + "fuel-core-types", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "fuel-core-producer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d2901a7ba2c0e724bbb88a3111fdb9844f5faf9f0bd4005944f61f093730b4d" +dependencies = [ + "anyhow", + "async-trait", + "derive_more", + "fuel-core-storage", + "fuel-core-types", + "tokio", + "tokio-rayon", + "tracing", +] + +[[package]] +name = "fuel-core-relayer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da1aa686ec4a05b77f4c4dfae68e6f17701b5bc21a49a8a505c6d9dc6dcf9183" +dependencies = [ + "anyhow", + "async-trait", + "enum-iterator", + "ethers-contract", + "ethers-core", + "ethers-providers", + "fuel-core-services", + "fuel-core-storage", + "fuel-core-types", + "futures", + "once_cell", + "strum 0.25.0", + "strum_macros 0.25.3", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "fuel-core-services" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2ab4d3931b8cafdb2e69fe8ca97918a168d74c73c070481ca0e552cc37bb93" +dependencies = [ + "anyhow", + "async-trait", + "fuel-core-metrics", + "futures", + "parking_lot", + "tokio", + "tracing", +] + +[[package]] +name = "fuel-core-storage" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e039c1c6ebef314c74c34728e1f2199dcf9ede041d6f5c6e11479517c8f4d320" +dependencies = [ + "anyhow", + "derive_more", + "enum-iterator", + "fuel-core-types", + "fuel-vm", + "impl-tools", + "itertools 0.12.1", + "num_enum", + "paste", + "postcard", + "primitive-types", + "serde", + "strum 0.25.0", + "strum_macros 0.25.3", +] + +[[package]] +name = "fuel-core-sync" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059ee4c3dbf1e9340d7cd88eccf2e10c631306d8038ab20160e6434deb79c1b" +dependencies = [ + "anyhow", + "async-trait", + "fuel-core-services", + "fuel-core-types", + "futures", + "rand", + "tokio", + "tracing", +] + +[[package]] +name = "fuel-core-txpool" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985684e2d67d5018e9227a4f9ed79cac02b23b207e457ee95833ab047769c2ac" +dependencies = [ + "anyhow", + "async-trait", + "fuel-core-metrics", + "fuel-core-services", + "fuel-core-storage", + "fuel-core-types", + "futures", + "parking_lot", + "tokio", + "tokio-rayon", + "tokio-stream", + "tracing", +] + +[[package]] +name = "fuel-core-types" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf038dd8df8d3aa665a13295c9ef888ba8118600cccdf8fb4587410e0e102fdf" +dependencies = [ + "anyhow", + "bs58", + "derivative", + "derive_more", + "fuel-vm", + "secrecy", + "serde", + "tai64", + "thiserror", + "zeroize", +] + +[[package]] +name = "fuel-core-upgradable-executor" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc54c84a7dc13f76930761ebca391b167caa096dc2bdb2413b5a2400bf65f99d" +dependencies = [ + "anyhow", + "fuel-core-executor", + "fuel-core-storage", + "fuel-core-types", + "fuel-core-wasm-executor", + "parking_lot", + "postcard", + "tracing", + "wasmtime", +] + +[[package]] +name = "fuel-core-wasm-executor" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a201e4fa5f94efb36cda172947875483d90a88b060cb9c6f9a496313d171aae8" +dependencies = [ + "anyhow", + "fuel-core-executor", + "fuel-core-storage", + "fuel-core-types", + "postcard", + "serde", +] + +[[package]] +name = "fuel-crypto" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71cef93970fb8a26d3a683ae211833c6bbf391066887f501bd5859f29992b59a" +dependencies = [ + "coins-bip32", + "coins-bip39", + "ecdsa", + "ed25519-dalek", + "fuel-types", + "k256", + "lazy_static", + "p256", + "rand", + "secp256k1", + "serde", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "fuel-derive" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b85e8e508b26d088262075fcfe9921b7009c931fef1cc55fe1dafb116c99884" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + +[[package]] +name = "fuel-merkle" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5198b4eab5a19b0034971da88199dae7dd61806ebd8df366d6af1f17cda2e151" +dependencies = [ + "derive_more", + "digest 0.10.7", + "fuel-storage", + "hashbrown 0.13.2", + "hex", + "serde", + "sha2 0.10.8", +] + +[[package]] +name = "fuel-storage" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa738e9c244f3f312af09faef108ec9a285f02afcefbc579c19c242cea742dd0" + +[[package]] +name = "fuel-tx" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4b4ea79ffe711af7bbf363b25f383fc6e481e652cf55a5ef8b5a458fcf4ef9" +dependencies = [ + "bitflags 2.5.0", + "derivative", + "derive_more", + "fuel-asm", + "fuel-crypto", + "fuel-merkle", + "fuel-types", + "hashbrown 0.14.5", + "itertools 0.10.5", + "postcard", + "rand", + "serde", + "serde_json", + "strum 0.24.1", + "strum_macros 0.24.3", +] + +[[package]] +name = "fuel-types" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455cf5275d96f6907e81ed1825c4e6a9dd79f7c1c37a4e15134562f83024c7e7" +dependencies = [ + "fuel-derive", + "hex", + "serde", +] + +[[package]] +name = "fuel-vm" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8811f949db8ce61cc68dcf81644047df4ee23be55879efcfe9f1aa5adc378965" +dependencies = [ + "async-trait", + "backtrace", + "bitflags 2.5.0", + "derivative", + "derive_more", + "ethnum", + "fuel-asm", + "fuel-crypto", + "fuel-merkle", + "fuel-storage", + "fuel-tx", + "fuel-types", + "hashbrown 0.14.5", + "itertools 0.10.5", + "libm", + "paste", + "percent-encoding", + "primitive-types", + "serde", + "serde_with", + "sha3", + "static_assertions", + "strum 0.24.1", + "tai64", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-bounded" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e2774cc104e198ef3d3e1ff4ab40f86fa3245d6cb6a3a46174f21463cee173" +dependencies = [ + "futures-timer", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "futures-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +dependencies = [ + "futures-io", + "rustls 0.21.12", +] + +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls 0.23.8", + "rustls-pki-types", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-ticker" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9763058047f713632a52e916cc7f6a4b3fc6e9fc1ff8c5b1dc49e5a89041682e" +dependencies = [ + "futures", + "futures-timer", + "instant", +] + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "indexmap 2.2.6", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin 0.9.8", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "socket2", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "system-configuration", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http", + "hyper", + "log", + "rand", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-tools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82c305b1081f1a99fda262883c788e50ab57d36c00830bdd7e0a82894ad965c" +dependencies = [ + "autocfg", + "impl-tools-lib", + "proc-macro-error", + "syn 2.0.66", +] + +[[package]] +name = "impl-tools-lib" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85d3946d886eaab0702fa0c6585adcced581513223fa9df7ccfabbd9fa331a88" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ip_network" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem 1.1.1", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libflate" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" +dependencies = [ + "adler32", + "crc32fast", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" +dependencies = [ + "rle-decode-fast", +] + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libp2p" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom", + "instant", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-kad", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-noise", + "libp2p-quic", + "libp2p-request-response", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-upnp", + "libp2p-websocket", + "libp2p-yamux", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + +[[package]] +name = "libp2p-core" +version = "0.41.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8130a8269e65a2554d55131c770bdf4bcd94d2b8d4efb24ca23699be65066c05" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-identity", + "multiaddr", + "multihash", + "multistream-select", + "once_cell", + "parking_lot", + "pin-project", + "quick-protobuf", + "rand", + "rw-stream-sink", + "smallvec", + "thiserror", + "tracing", + "unsigned-varint 0.8.0", + "void", +] + +[[package]] +name = "libp2p-dns" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17cbcf7160ff35c3e8e560de4a068fe9d6cb777ea72840e48eb76ff9576c4b6" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d665144a616dadebdc5fff186b1233488cdcd8bfb1223218ff084b6d052c94f7" +dependencies = [ + "asynchronous-codec 0.7.0", + "base64 0.21.7", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-ticker", + "getrandom", + "hex_fmt", + "instant", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand", + "regex", + "sha2 0.10.8", + "smallvec", + "tracing", + "void", +] + +[[package]] +name = "libp2p-identify" +version = "0.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5d635ebea5ca0c3c3e77d414ae9b67eccf2a822be06091b9c1a0d13029a1e2f" +dependencies = [ + "asynchronous-codec 0.7.0", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "lru", + "quick-protobuf", + "quick-protobuf-codec", + "smallvec", + "thiserror", + "tracing", + "void", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "hkdf", + "libsecp256k1", + "multihash", + "quick-protobuf", + "rand", + "sha2 0.10.8", + "thiserror", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-kad" +version = "0.45.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc5767727d062c4eac74dd812c998f0e488008e82cce9c33b463d38423f9ad2" +dependencies = [ + "arrayvec", + "asynchronous-codec 0.7.0", + "bytes", + "either", + "fnv", + "futures", + "futures-bounded", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "rand", + "sha2 0.10.8", + "smallvec", + "thiserror", + "tracing", + "uint", + "void", +] + +[[package]] +name = "libp2p-mdns" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49007d9a339b3e1d7eeebc4d67c05dbf23d300b7d091193ec2d3f26802d7faf2" +dependencies = [ + "data-encoding", + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand", + "smallvec", + "socket2", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-metrics" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdac91ae4f291046a3b2660c039a2830c931f84df2ee227989af92f7692d3357" +dependencies = [ + "futures", + "instant", + "libp2p-core", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-kad", + "libp2p-swarm", + "pin-project", + "prometheus-client", +] + +[[package]] +name = "libp2p-mplex" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e895765e27e30217b25f7cb7ac4686dad1ff80bf2fdeffd1d898566900a924" +dependencies = [ + "asynchronous-codec 0.6.2", + "bytes", + "futures", + "libp2p-core", + "libp2p-identity", + "nohash-hasher", + "parking_lot", + "rand", + "smallvec", + "tracing", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "libp2p-noise" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecd0545ce077f6ea5434bcb76e8d0fe942693b4380aaad0d34a358c2bd05793" +dependencies = [ + "asynchronous-codec 0.7.0", + "bytes", + "curve25519-dalek", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand", + "sha2 0.10.8", + "snow", + "static_assertions", + "thiserror", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-quic" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "parking_lot", + "quinn", + "rand", + "ring 0.17.8", + "rustls 0.23.8", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-request-response" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6946e5456240b3173187cc37a17cb40c3cd1f7138c76e2c773e0d792a42a8de1" +dependencies = [ + "async-trait", + "futures", + "futures-bounded", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand", + "smallvec", + "tracing", + "void", +] + +[[package]] +name = "libp2p-swarm" +version = "0.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm-derive", + "lru", + "multistream-select", + "once_cell", + "rand", + "smallvec", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5daceb9dd908417b6dfcfe8e94098bc4aac54500c282e78120b885dadc09b999" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "libp2p-tcp" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2460fc2748919adff99ecbc1aab296e4579e41f374fb164149bd2c9e529d4c" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core", + "libp2p-identity", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251b17aebdd29df7e8f80e4d94b782fae42e934c49086e1a81ba23b60a8314f2" +dependencies = [ + "futures", + "futures-rustls 0.26.0", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring 0.17.8", + "rustls 0.23.8", + "rustls-webpki 0.101.7", + "thiserror", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccf04b0e3ff3de52d07d5fd6c3b061d0e7f908ffc683c32d9638caedce86fc8" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-websocket" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4846d51afd08180e164291c3754ba30dd4fbac6fac65571be56403c16431a5e" +dependencies = [ + "either", + "futures", + "futures-rustls 0.24.0", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "pin-project-lite", + "rw-stream-sink", + "soketto", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "libp2p-yamux" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200cbe50349a44760927d50b431d77bed79b9c0a3959de1af8d24a63434b71e5" +dependencies = [ + "either", + "futures", + "libp2p-core", + "thiserror", + "tracing", + "yamux 0.12.1", + "yamux 0.13.2", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "librocksdb-sys" +version = "0.11.0+8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libz-sys" +version = "1.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memfd" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix", +] + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + +[[package]] +name = "multiaddr" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.7.2", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +dependencies = [ + "core2", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "names" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +dependencies = [ + "clap 3.2.25", + "rand", +] + +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nkeys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc522a19199a0795776406619aa6aa78e1e55690fbeb3181b8db5265fd0e89ce" +dependencies = [ + "data-encoding", + "ed25519", + "ed25519-dalek", + "getrandom", + "log", + "rand", + "signatory", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "nuid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc895af95856f929163a0aa20c26a78d26bfdc839f51b9d5aa7a5b79e52b7e83" +dependencies = [ + "rand", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "crc32fast", + "hashbrown 0.14.5", + "indexmap 2.2.6", + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "polling" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.3.9", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "heapless", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "pprof" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978385d59daf9269189d052ca8a84c1acfd0715c0599a5d5188d4acc078ca46a" +dependencies = [ + "backtrace", + "cfg-if", + "findshlibs", + "libc", + "log", + "nix 0.26.4", + "once_cell", + "parking_lot", + "smallvec", + "symbolic-demangle", + "tempfile", + "thiserror", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.66", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prometheus-client" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.5.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.3", + "unarray", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "pyroscope" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8a53ce01af1087eaeee6ce7c4fbf50ea4040ab1825c0115c4bafa039644ba9" +dependencies = [ + "json", + "libc", + "libflate", + "log", + "names", + "prost", + "reqwest", + "thiserror", + "url", + "winapi", +] + +[[package]] +name = "pyroscope_pprofrs" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f010b2a981a7f8449a650f25f309e520b5206ea2d89512dcb146aaa5518ff4" +dependencies = [ + "log", + "pprof", + "pyroscope", + "thiserror", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec 0.7.0", + "bytes", + "quick-protobuf", + "thiserror", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "quinn" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904e3d3ba178131798c6d9375db2b13b34337d489b089fc5ba0825a2ff1bee73" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.8", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e974563a4b1c2206bbc61191ca4da9c22e4308b4c455e8906751cc7828393f08" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash", + "rustls 0.23.8", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4f0def2590301f4f667db5a77f9694fb004f82796dc1a8b1508fafa3d0e8b72" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +dependencies = [ + "pem 3.0.4", + "ring 0.16.20", + "time", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rocksdb" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" +dependencies = [ + "libc", + "librocksdb-sys", +] + +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix 0.24.3", + "thiserror", + "tokio", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79adb16721f56eb2d843e67676896a61ce7a0fa622dc18d3e372477a029d2740" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +dependencies = [ + "rand", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_nanos" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93142f0367a4cc53ae0fead1bcda39e85beccfad3dcd717656cacab94b12985" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +dependencies = [ + "darling 0.20.9", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signatory" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e303f8205714074f6068773f0e29527e0453937fe837c9717d066635b65f31" +dependencies = [ + "pkcs8", + "rand_core", + "signature", + "zeroize", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core", + "ring 0.17.8", + "rustc_version", + "sha2 0.10.8", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand", + "sha-1", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] + +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.66", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.66", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "symbolic-common" +version = "12.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "12.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tai64" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7401421025f4132e6c1f7af5e7f8287383969f36e6628016cd509b8d3da9dc" +dependencies = [ + "serde", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.5.4+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tokio-rayon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cf33a76e0b1dd03b778f83244137bd59887abf25c0e87bc3e7071105f457693" +dependencies = [ + "rayon", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.8", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.13", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.9", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "futures", + "futures-task", + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tryhard" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9f0a709784e86923586cff0d872dba54cd2d2e116b3bc57587d15737cfce9d" +dependencies = [ + "futures", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls 0.21.12", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +dependencies = [ + "asynchronous-codec 0.6.2", + "bytes", +] + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.66", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-encoder" +version = "0.41.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "972f97a5d8318f908dded23594188a90bcd09365986b1163e66d70170e5287ae" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.121.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" +dependencies = [ + "bitflags 2.5.0", + "indexmap 2.2.6", + "semver", +] + +[[package]] +name = "wasmtime" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69472708b96ee90579a482bdbb908ce97e53a9e5ebbcab59cc29c3977bcab512" +dependencies = [ + "anyhow", + "bincode", + "bumpalo", + "cfg-if", + "gimli", + "indexmap 2.2.6", + "libc", + "log", + "object", + "once_cell", + "paste", + "rayon", + "rustix", + "serde", + "serde_derive", + "serde_json", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.52.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86292d6a9bf30c669582a40c4a4b8e0b8640e951f3635ee8e0acf7f87809961e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a180017db1233c902b992fea9484640d265f2fedf03db60eed57894cb2effcc" +dependencies = [ + "anyhow", + "base64 0.21.7", + "bincode", + "directories-next", + "log", + "rustix", + "serde", + "serde_derive", + "sha2 0.10.8", + "toml 0.5.11", + "windows-sys 0.52.0", + "zstd", +] + +[[package]] +name = "wasmtime-cranelift" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b57d58e220ae223855c5d030ef20753377bc716d0c81b34c1fe74c9f44268774" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba2cfdfdbde42f0f3baeddb62f3555524dee9f836c96da8d466e299f75f5eee" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abbf3075d9ee7eb1263dc67949aced64d0f0bf27be8098d34d8e5826cf0ff0f2" +dependencies = [ + "anyhow", + "bincode", + "cranelift-entity", + "gimli", + "indexmap 2.2.6", + "log", + "object", + "serde", + "serde_derive", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dacd2aa30fb20fd8cd0eb4e664024a1ab28a02958529fa05bf52117532a098fc" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d14e97c4bb36d91bcdd194745446d595e67ce8b89916806270fdbee640c747fd" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap 2.2.6", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "psm", + "rustix", + "sptr", + "wasm-encoder", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", + "windows-sys 0.52.0", +] + +[[package]] +name = "wasmtime-types" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "530b94c627a454d24f520173d3145112d1b807c44c82697a57e1d8e28390cde4" +dependencies = [ + "cranelift-entity", + "serde", + "serde_derive", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5399c175ddba4a471b9da45105dea3493059d52b2d54860eadb0df04c813948d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "wasmtime-wmemcheck" +version = "18.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1711f429111e782fac0537e0b3eb2ab6f821613cf1ec3013f2a0ff3fde41745" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core 0.51.1", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f97202f6b125031b95d83e01dc57292b529384f80bfae4677e4bbc10178cf72" +dependencies = [ + "futures", + "instant", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/crates/sv-emitter/Cargo.toml b/crates/sv-emitter/Cargo.toml new file mode 100644 index 00000000..7433d14e --- /dev/null +++ b/crates/sv-emitter/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "sv-emitter" +description = "Service that emitts new blocks using fuel-core block subscription" +authors = { workspace = true } +keywords = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +version = { workspace = true } +rust-version = { workspace = true } +publish = false + +[[bin]] +name = "sv-emitter" +path = "src/main.rs" + +[dependencies] +anyhow = { workspace = true } +async-nats = { workspace = true } +clap = { workspace = true } +fuel-core = { workspace = true, default-features = false, features = ["p2p", "relayer", "rocksdb"] } +fuel-core-bin = { workspace = true, default-features = false, features = [ + "p2p", + "relayer", + "rocksdb", +] } +fuel-core-types = { workspace = true, default-features = false, features = ["std", "serde"] } +fuel-streams-core = { workspace = true, features = ["test-helpers"] } +fuel-streams-executors = { workspace = true, features = ["test-helpers"] } +futures = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tokio-util = "0.7.13" +tracing = { workspace = true } + +[features] +default = [] +test-helpers = [] + +[target.x86_64-unknown-linux-gnu.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.x86_64-unknown-linux-musl.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.aarch64-unknown-linux-gnu.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } + +[target.aarch64-unknown-linux-musl.dependencies] +openssl = { version = "0.10.68", features = ["vendored"] } diff --git a/crates/sv-emitter/src/cli.rs b/crates/sv-emitter/src/cli.rs new file mode 100644 index 00000000..377b3f2f --- /dev/null +++ b/crates/sv-emitter/src/cli.rs @@ -0,0 +1,24 @@ +//! This binary subscribes to events emitted from a Fuel client or node +//! to publish streams that can consumed via the `fuel-streams` SDK. + +use clap::Parser; + +/// CLI structure for parsing command-line arguments. +/// +/// - `network`: The fuel network we want to connect to. +/// - `fuel_core_config`: Configuration for the Fuel Core service, parsed using a flattened command. +#[derive(Clone, Parser)] +pub struct Cli { + /// Fuel Network to connect to. + #[arg( + long, + value_name = "NATS_URL", + env = "NATS_URL", + default_value = "localhost:4222", + help = "NATS URL to connect to." + )] + pub nats_url: String, + /// Flattened command structure for Fuel Core configuration. + #[command(flatten)] + pub fuel_core_config: fuel_core_bin::cli::run::Command, +} diff --git a/crates/sv-emitter/src/lib.rs b/crates/sv-emitter/src/lib.rs new file mode 100644 index 00000000..5bf4a4b0 --- /dev/null +++ b/crates/sv-emitter/src/lib.rs @@ -0,0 +1,2 @@ +pub mod cli; +pub mod shutdown; diff --git a/crates/sv-emitter/src/main.rs b/crates/sv-emitter/src/main.rs new file mode 100644 index 00000000..b7bd5bdc --- /dev/null +++ b/crates/sv-emitter/src/main.rs @@ -0,0 +1,205 @@ +use std::{sync::Arc, time::Duration}; + +use async_nats::jetstream::{ + context::PublishErrorKind, + stream::RetentionPolicy, + Context, +}; +use clap::Parser; +use fuel_core_types::blockchain::SealedBlock; +use fuel_streams_core::prelude::*; +use fuel_streams_executors::*; +use futures::StreamExt; +use sv_emitter::{cli::Cli, shutdown::ShutdownController}; +use thiserror::Error; +use tokio_util::sync::CancellationToken; + +#[derive(Error, Debug)] +pub enum LiveBlockProcessingError { + #[error("Failed to publish block: {0}")] + PublishError(#[from] PublishError), + + #[error("Processing was cancelled")] + Cancelled, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + let config = cli.fuel_core_config; + let fuel_core: Arc = FuelCore::new(config).await?; + fuel_core.start().await?; + + let nats_client = setup_nats(&cli.nats_url).await?; + let last_block_height = Arc::new(fuel_core.get_latest_block_height()?); + let last_published = + Arc::new(find_last_published_height(&nats_client).await?); + + let shutdown = Arc::new(ShutdownController::new()); + shutdown.clone().spawn_signal_handler(); + + tracing::info!("Last published height: {}", last_published); + tracing::info!("Last block height: {}", last_block_height); + + tokio::select! { + result = async { + let historical = process_historical_blocks( + &nats_client, + fuel_core.clone(), + last_block_height, + last_published, + shutdown.token().clone(), + ); + + let live = process_live_blocks( + &nats_client.jetstream, + fuel_core.clone(), + shutdown.token().clone(), + ); + + tokio::join!(historical, live) + } => { + result.0?; + result.1?; + } + _ = shutdown.wait_for_shutdown() => { + tracing::info!("Shutdown signal received, waiting for processing to complete..."); + fuel_core.stop().await + } + } + + tracing::info!("Shutdown complete"); + Ok(()) +} + +async fn setup_nats(nats_url: &str) -> anyhow::Result { + let opts = NatsClientOpts::admin_opts(None) + .with_custom_url(nats_url.to_string()) + .with_domain("CORE".to_string()); + let nats_client = NatsClient::connect(&opts).await?; + let stream_name = nats_client.namespace.stream_name("block_importer"); + nats_client + .jetstream + .get_or_create_stream(async_nats::jetstream::stream::Config { + name: stream_name, + subjects: vec!["block_submitted.>".to_string()], + retention: RetentionPolicy::WorkQueue, + duplicate_window: Duration::from_secs(1), + ..Default::default() + }) + .await?; + + Ok(nats_client) +} + +async fn find_last_published_height( + nats_client: &NatsClient, +) -> anyhow::Result { + let block_stream = Stream::::get_or_init(nats_client).await; + let last_publish_height = block_stream + .get_last_published(BlocksSubject::WILDCARD) + .await?; + match last_publish_height { + Some(block) => Ok(block.height), + None => Ok(0), + } +} + +fn get_historical_block_range( + last_published_height: Arc, + last_block_height: Arc, +) -> Option> { + let last_published_height = *last_published_height; + let last_block_height = *last_block_height; + let start_height = last_published_height + 1; + let end_height = last_block_height; + if start_height > end_height { + tracing::info!("No historical blocks to process"); + return None; + } + let block_count = end_height - start_height + 1; + let heights: Vec = (start_height..=end_height).collect(); + tracing::info!( + "Processing {block_count} historical blocks from height {start_height} to {end_height}" + ); + Some(heights) +} + +fn process_historical_blocks( + nats_client: &NatsClient, + fuel_core: Arc, + last_block_height: Arc, + last_published_height: Arc, + token: CancellationToken, +) -> tokio::task::JoinHandle<()> { + let jetstream = nats_client.jetstream.clone(); + tokio::spawn(async move { + let Some(heights) = get_historical_block_range( + last_published_height, + last_block_height, + ) else { + return; + }; + futures::stream::iter(heights) + .map(|height| { + let jetstream = jetstream.clone(); + let fuel_core = fuel_core.clone(); + let sealed_block = fuel_core.get_sealed_block_by_height(height); + let sealed_block = Arc::new(sealed_block); + async move { + publish_block(&jetstream, &fuel_core, &sealed_block).await + } + }) + .buffer_unordered(100) + .take_until(token.cancelled()) + .collect::>() + .await; + }) +} + +async fn process_live_blocks( + jetstream: &Context, + fuel_core: Arc, + token: CancellationToken, +) -> Result<(), LiveBlockProcessingError> { + let mut subscription = fuel_core.blocks_subscription(); + while let Ok(data) = subscription.recv().await { + if token.is_cancelled() { + break; + } + let sealed_block = Arc::new(data.sealed_block.clone()); + publish_block(jetstream, &fuel_core, &sealed_block).await?; + } + Ok(()) +} + +#[derive(Error, Debug)] +pub enum PublishError { + #[error("Failed to publish block to NATS server: {0}")] + NatsPublish(#[from] async_nats::error::Error), + + #[error("Failed to create block payload due to: {0}")] + BlockPayload(#[from] ExecutorError), + + #[error("Failed to access offchain database: {0}")] + OffchainDatabase(String), +} + +async fn publish_block( + jetstream: &Context, + fuel_core: &Arc, + sealed_block: &Arc, +) -> Result<(), PublishError> { + let metadata = Metadata::new(fuel_core, sealed_block); + let fuel_core = Arc::clone(fuel_core); + let payload = BlockPayload::new(fuel_core, sealed_block, &metadata)?; + jetstream + .send_publish(payload.subject(), payload.to_owned().try_into()?) + .await + .map_err(PublishError::NatsPublish)? + .await + .map_err(PublishError::NatsPublish)?; + + tracing::info!("New block submitted: {}", payload.block_height()); + Ok(()) +} diff --git a/crates/sv-emitter/src/shutdown.rs b/crates/sv-emitter/src/shutdown.rs new file mode 100644 index 00000000..6d66e7b1 --- /dev/null +++ b/crates/sv-emitter/src/shutdown.rs @@ -0,0 +1,104 @@ +use std::sync::Arc; + +use tokio_util::sync::CancellationToken; + +#[derive(Clone)] +pub struct ShutdownController { + token: CancellationToken, +} + +impl Default for ShutdownController { + fn default() -> Self { + Self::new() + } +} + +impl ShutdownController { + pub fn new() -> Self { + Self { + token: CancellationToken::new(), + } + } + + pub fn token(&self) -> &CancellationToken { + &self.token + } + + pub fn spawn_signal_handler(self: Arc) -> Arc { + tokio::spawn({ + let shutdown = self.clone(); + async move { + tokio::signal::ctrl_c() + .await + .expect("Failed to listen for ctrl+c"); + tracing::info!("Received shutdown signal"); + shutdown.initiate_shutdown(); + } + }); + self + } + + pub fn initiate_shutdown(&self) { + tracing::info!("Initiating graceful shutdown..."); + self.token.cancel(); + } + + pub fn is_shutdown_initiated(&self) -> bool { + self.token.is_cancelled() + } + + pub async fn wait_for_shutdown(&self) { + self.token.cancelled().await; + } +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use super::*; + + #[tokio::test] + async fn test_manual_shutdown() { + let controller = ShutdownController::new(); + assert!( + !controller.is_shutdown_initiated(), + "Controller should not be shutdown initially" + ); + + controller.initiate_shutdown(); + assert!( + controller.is_shutdown_initiated(), + "Controller should be shutdown after initiation" + ); + } + + #[tokio::test] + async fn test_wait_for_shutdown_timeout() { + let controller = ShutdownController::new(); + + let timeout = Duration::from_millis(50); + let result = + tokio::time::timeout(timeout, controller.wait_for_shutdown()).await; + + assert!( + result.is_err(), + "wait_for_shutdown should not complete without initiation" + ); + } + + #[tokio::test] + async fn test_clone_behavior() { + let controller = ShutdownController::new(); + let cloned = controller.clone(); + + // Initiate shutdown from clone + cloned.initiate_shutdown(); + + assert!( + controller.is_shutdown_initiated(), + "Original should be shutdown" + ); + assert!(cloned.is_shutdown_initiated(), "Clone should be shutdown"); + } +} diff --git a/examples/multiple-streams.rs b/examples/multiple-streams.rs index 0511434b..ebc0e5c0 100644 --- a/examples/multiple-streams.rs +++ b/examples/multiple-streams.rs @@ -274,25 +274,6 @@ async fn stream_contract( ReceiptsMintSubject::new().with_contract_id(Some(contract_id.into())), ); - let mut sub = receipt_stream.subscribe().await?; - - while let Some(bytes) = sub.next().await { - let decoded_msg = Receipt::decode_raw(bytes.unwrap().to_vec()).await; - let receipt = decoded_msg.payload; - - // Check if the receipt has a contract_id and if it matches our target - if let Some(receipt_contract_id) = &receipt.contract_id { - if *receipt_contract_id == contract_id.into() { - let receipt_subject = decoded_msg.subject; - let receipt_published_at = decoded_msg.timestamp; - println!( - "Received contract receipt: data={:?}, subject={}, published_at={}", - receipt, receipt_subject, receipt_published_at - ); - } - } - } - Ok(()) } diff --git a/scripts/run_publisher.sh b/scripts/run_publisher.sh index 7d29d677..b6240036 100755 --- a/scripts/run_publisher.sh +++ b/scripts/run_publisher.sh @@ -28,6 +28,13 @@ usage() { exit 1 } +# Set default values from environment variables with fallbacks +NETWORK=${NETWORK:-"testnet"} +MODE=${MODE:-"profiling"} +PORT=${PORT:-"4004"} +TELEMETRY_PORT=${TELEMETRY_PORT:-"8080"} +PACKAGE=${PACKAGE:-"fuel-streams-publisher"} + while [[ "$#" -gt 0 ]]; do case $1 in --network) @@ -63,7 +70,7 @@ done # ------------------------------ # Load Environment # ------------------------------ -source ./scripts/set_env.sh +source ./scripts/set_env.sh NETWORK=${NETWORK} # Print the configuration being used echo -e "\n==========================================" @@ -94,31 +101,33 @@ echo -e "==========================================\n" # Define common arguments COMMON_ARGS=( "--enable-relayer" + "--service-name" "fuel-${NETWORK}-node" "--keypair" "${KEYPAIR}" "--relayer" "${RELAYER}" "--ip=0.0.0.0" - "--service-name" "fuel-${NETWORK}-node" - "--db-path" "./cluster/docker/db-${NETWORK}" - "--snapshot" "./cluster/chain-config/${NETWORK}" - "--nats-url" "nats://localhost:4222" "--port" "${PORT}" - "--telemetry-port" "${TELEMETRY_PORT}" "--peering-port" "30333" + "--db-path" "./cluster/docker/db-${NETWORK}" + "--snapshot" "./cluster/chain-config/${NETWORK}" "--utxo-validation" "--poa-instant" "false" "--enable-p2p" - "--sync-header-batch-size" "${SYNC_HEADER_BATCH_SIZE}" - "--relayer-log-page-size=${RELAYER_LOG_PAGE_SIZE}" - "--sync-block-stream-buffer-size" "30" - "--bootstrap-nodes" "${RESERVED_NODES}" + "--reserved-nodes" "${RESERVED_NODES}" "--relayer-v2-listening-contracts=${RELAYER_V2_LISTENING_CONTRACTS}" "--relayer-da-deploy-height=${RELAYER_DA_DEPLOY_HEIGHT}" + "--relayer-log-page-size=${RELAYER_LOG_PAGE_SIZE}" + "--sync-block-stream-buffer-size" "50" + "--nats-url" "nats://localhost:4222" + "--max-database-cache-size" "17179869184" + "--state-rewind-duration" "136y" + "--request-timeout" "60" + "--graphql-max-complexity" "1000000000" ) # Execute based on mode if [ "$MODE" == "dev" ]; then - cargo run -p fuel-streams-publisher -- "${COMMON_ARGS[@]}" ${EXTRA_ARGS} + cargo run -p ${PACKAGE} -- "${COMMON_ARGS[@]}" ${EXTRA_ARGS} else - cargo build --profile profiling --package fuel-streams-publisher - samply record ./target/profiling/fuel-streams-publisher "${COMMON_ARGS[@]}" ${EXTRA_ARGS} + cargo build --profile profiling --package ${PACKAGE} + samply record ./target/profiling/${PACKAGE} "${COMMON_ARGS[@]}" ${EXTRA_ARGS} fi diff --git a/scripts/set_env.sh b/scripts/set_env.sh index b2f56cdf..9b67f661 100755 --- a/scripts/set_env.sh +++ b/scripts/set_env.sh @@ -40,12 +40,12 @@ cleanup_env() { fi } -# Load initial environment -load_env - # Clean up previous auto-generated content cleanup_env +# Load initial environment +load_env + # Set and export network-specific variables export RESERVED_NODES=$(eval echo "\$${NETWORK_UPPER}_RESERVED_NODES") export RELAYER_V2_LISTENING_CONTRACTS=$(eval echo "\$${NETWORK_UPPER}_RELAYER_V2_LISTENING_CONTRACTS") diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 9f1c81b8..943b0e62 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -26,7 +26,7 @@ anyhow = { workspace = true } async-trait = { workspace = true } fuel-core = { workspace = true, features = ["test-helpers"] } fuel-core-importer = { workspace = true, features = ["test-helpers"] } -fuel-core-types = { workspace = true } +fuel-core-types = { workspace = true, features = ["test-helpers"] } fuel-streams = { workspace = true, features = ["test-helpers"] } fuel-streams-core = { workspace = true, features = ["test-helpers"] } fuel-streams-publisher = { workspace = true, features = ["test-helpers"] } diff --git a/tests/tests/publisher.rs b/tests/tests/publisher.rs index 42ae9e85..81620ab8 100644 --- a/tests/tests/publisher.rs +++ b/tests/tests/publisher.rs @@ -1,15 +1,15 @@ -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::{collections::HashMap, sync::Arc}; -use fuel_core::combined_database::CombinedDatabase; +use fuel_core::{ + combined_database::CombinedDatabase, + service::{Config, FuelService}, + ShutdownListener, +}; use fuel_core_importer::ImporterResult; use fuel_core_types::blockchain::SealedBlock; use fuel_streams_core::prelude::*; use fuel_streams_publisher::{ publisher::shutdown::ShutdownController, - FuelCoreLike, Publisher, }; use futures::StreamExt; @@ -17,6 +17,7 @@ use tokio::sync::broadcast::{self, Receiver, Sender}; // TODO - Re-implement with `mockall` and `mock` macros struct TestFuelCore { + fuel_service: FuelService, chain_id: FuelCoreChainId, base_asset_id: FuelCoreAssetId, database: CombinedDatabase, @@ -28,7 +29,15 @@ impl TestFuelCore { fn default( blocks_broadcaster: Sender, ) -> Self { + let mut shutdown = ShutdownListener::spawn(); + let service = FuelService::new( + Default::default(), + Config::local_node(), + &mut shutdown, + ) + .unwrap(); Self { + fuel_service: service, chain_id: FuelCoreChainId::default(), base_asset_id: FuelCoreAssetId::zeroed(), database: CombinedDatabase::default(), @@ -53,6 +62,9 @@ impl FuelCoreLike for TestFuelCore { fn is_started(&self) -> bool { true } + fn fuel_service(&self) -> &FuelService { + &self.fuel_service + } async fn await_synced_at_least_once( &self, _historical: bool, @@ -91,6 +103,20 @@ impl FuelCoreLike for TestFuelCore { ) -> anyhow::Result>> { Ok(self.receipts.clone()) } + + fn get_tx_status( + &self, + _tx_id: &FuelCoreBytes32, + ) -> anyhow::Result> { + Ok(Some(FuelCoreTransactionStatus::Success { + receipts: self.receipts.clone().unwrap_or_default(), + block_height: 0.into(), + result: None, + time: FuelCoreTai64::now(), + total_gas: 0, + total_fee: 0, + })) + } } #[tokio::test(flavor = "multi_thread")] @@ -240,10 +266,61 @@ async fn publishes_receipts() { .await .unwrap(); - let receipts: HashSet = receipts.iter().map(Into::into).collect(); + let expected_receipts: Vec = + receipts.iter().map(Into::into).collect(); + let mut found_receipts = Vec::new(); + while let Some(Some(receipt)) = receipts_stream.next().await { - assert!(receipts.contains(&receipt)); + found_receipts.push(receipt); } + + assert_eq!( + found_receipts.len(), + expected_receipts.len(), + "Number of receipts doesn't match" + ); + + // Create sets of receipt identifiers + let found_ids: std::collections::HashSet<_> = found_receipts + .into_iter() + .map(|r| match r { + Receipt::Call(r) => r.id, + Receipt::Return(r) => r.id, + Receipt::ReturnData(r) => r.id, + Receipt::Revert(r) => r.id, + Receipt::Log(r) => r.id, + Receipt::LogData(r) => r.id, + Receipt::Transfer(r) => r.id, + Receipt::TransferOut(r) => r.id, + Receipt::Mint(r) => r.contract_id, + Receipt::Burn(r) => r.contract_id, + Receipt::Panic(r) => r.id, + _ => unreachable!(), + }) + .collect(); + + let expected_ids: std::collections::HashSet<_> = expected_receipts + .into_iter() + .map(|r| match r { + Receipt::Call(r) => r.id, + Receipt::Return(r) => r.id, + Receipt::ReturnData(r) => r.id, + Receipt::Revert(r) => r.id, + Receipt::Log(r) => r.id, + Receipt::LogData(r) => r.id, + Receipt::Transfer(r) => r.id, + Receipt::TransferOut(r) => r.id, + Receipt::Mint(r) => r.contract_id, + Receipt::Burn(r) => r.contract_id, + Receipt::Panic(r) => r.id, + _ => unreachable!(), + }) + .collect(); + + assert_eq!( + found_ids, expected_ids, + "Published receipt IDs don't match expected IDs" + ); } #[tokio::test(flavor = "multi_thread")]