From bffc711470c46ed0f191bfbaf4a716a91b554f54 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Tue, 10 Mar 2026 14:58:06 +0300 Subject: [PATCH 01/10] refactor: move `sequencer_` directories into `sequencer` --- .github/workflows/publish_images.yml | 8 +++--- .gitignore | 2 +- Cargo.lock | 4 +-- Cargo.toml | 4 +-- Justfile | 8 +++--- README.md | 8 +++--- .../sequencer/sequencer_config.json | 2 +- docker-compose.override.yml | 4 +-- docker-compose.yml | 2 +- integration_tests/Cargo.toml | 2 +- integration_tests/src/lib.rs | 4 +-- {sequencer_core => sequencer/core}/Cargo.toml | 0 .../core}/src/block_settlement_client.rs | 0 .../core}/src/block_store.rs | 0 .../core}/src/config.rs | 0 .../core}/src/indexer_client.rs | 0 {sequencer_core => sequencer/core}/src/lib.rs | 0 .../core}/src/mock.rs | 0 .../service}/Cargo.toml | 2 +- .../service}/Dockerfile | 28 +++++++++---------- .../configs/debug/sequencer_config.json | 0 .../configs/docker/sequencer_config.json | 2 +- sequencer/service/docker-compose.yml | 14 ++++++++++ .../service}/docker-entrypoint.sh | 4 +-- .../service/rpc}/Cargo.toml | 0 .../service/rpc}/src/lib.rs | 0 .../service/rpc}/src/net_utils.rs | 0 .../service/rpc}/src/process.rs | 0 .../service/rpc}/src/types/err_rpc.rs | 0 .../service/rpc}/src/types/mod.rs | 0 .../service}/src/lib.rs | 0 .../service}/src/main.rs | 2 +- sequencer_runner/docker-compose.yml | 14 ---------- wallet/src/main.rs | 2 +- 34 files changed, 58 insertions(+), 58 deletions(-) rename {sequencer_core => sequencer/core}/Cargo.toml (100%) rename {sequencer_core => sequencer/core}/src/block_settlement_client.rs (100%) rename {sequencer_core => sequencer/core}/src/block_store.rs (100%) rename {sequencer_core => sequencer/core}/src/config.rs (100%) rename {sequencer_core => sequencer/core}/src/indexer_client.rs (100%) rename {sequencer_core => sequencer/core}/src/lib.rs (100%) rename {sequencer_core => sequencer/core}/src/mock.rs (100%) rename {sequencer_runner => sequencer/service}/Cargo.toml (96%) rename {sequencer_runner => sequencer/service}/Dockerfile (79%) rename {sequencer_runner => sequencer/service}/configs/debug/sequencer_config.json (100%) rename {sequencer_runner => sequencer/service}/configs/docker/sequencer_config.json (98%) create mode 100644 sequencer/service/docker-compose.yml rename {sequencer_runner => sequencer/service}/docker-entrypoint.sh (81%) rename {sequencer_rpc => sequencer/service/rpc}/Cargo.toml (100%) rename {sequencer_rpc => sequencer/service/rpc}/src/lib.rs (100%) rename {sequencer_rpc => sequencer/service/rpc}/src/net_utils.rs (100%) rename {sequencer_rpc => sequencer/service/rpc}/src/process.rs (100%) rename {sequencer_rpc => sequencer/service/rpc}/src/types/err_rpc.rs (100%) rename {sequencer_rpc => sequencer/service/rpc}/src/types/mod.rs (100%) rename {sequencer_runner => sequencer/service}/src/lib.rs (100%) rename {sequencer_runner => sequencer/service}/src/main.rs (91%) delete mode 100644 sequencer_runner/docker-compose.yml diff --git a/.github/workflows/publish_images.yml b/.github/workflows/publish_images.yml index 619a6209..5076a430 100644 --- a/.github/workflows/publish_images.yml +++ b/.github/workflows/publish_images.yml @@ -12,12 +12,12 @@ jobs: strategy: matrix: include: - - name: sequencer_runner - dockerfile: ./sequencer_runner/Dockerfile + - name: sequencer_service + dockerfile: ./sequencer/service/Dockerfile build_args: | STANDALONE=false - - name: sequencer_runner-standalone - dockerfile: ./sequencer_runner/Dockerfile + - name: sequencer_service-standalone + dockerfile: ./sequencer/service/Dockerfile build_args: | STANDALONE=true - name: indexer_service diff --git a/.gitignore b/.gitignore index e4898102..b265e9aa 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ data/ .idea/ .vscode/ rocksdb -sequencer_runner/data/ +sequencer/service/data/ storage.json result wallet-ffi/wallet_ffi.h diff --git a/Cargo.lock b/Cargo.lock index 6bb8255c..d8b51cbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3839,7 +3839,7 @@ dependencies = [ "nssa", "nssa_core", "sequencer_core", - "sequencer_runner", + "sequencer_service", "serde_json", "tempfile", "testcontainers", @@ -7479,7 +7479,7 @@ dependencies = [ ] [[package]] -name = "sequencer_runner" +name = "sequencer_service" version = "0.1.0" dependencies = [ "actix", diff --git a/Cargo.toml b/Cargo.toml index bcd11651..78d5adb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ members = [ "programs/token", "sequencer_core", "sequencer_rpc", - "sequencer_runner", + "sequencer_service", "indexer/core", "indexer/service", "indexer/service/protocol", @@ -44,7 +44,7 @@ storage = { path = "storage" } key_protocol = { path = "key_protocol" } sequencer_core = { path = "sequencer_core" } sequencer_rpc = { path = "sequencer_rpc" } -sequencer_runner = { path = "sequencer_runner" } +sequencer_service = { path = "sequencer/service" } indexer_core = { path = "indexer/core" } indexer_service = { path = "indexer/service" } indexer_service_protocol = { path = "indexer/service/protocol" } diff --git a/Justfile b/Justfile index b4ec3a98..e6eab8d9 100644 --- a/Justfile +++ b/Justfile @@ -30,10 +30,10 @@ run-bedrock: docker compose up # Run Sequencer -[working-directory: 'sequencer_runner'] +[working-directory: 'sequencer/service'] run-sequencer: @echo "🧠 Running sequencer" - RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_runner configs/debug + RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_service configs/debug # Run Indexer [working-directory: 'indexer/service'] @@ -62,8 +62,8 @@ run-wallet +args: # Clean runtime data clean: @echo "🧹 Cleaning run artifacts" - rm -rf sequencer_runner/bedrock_signing_key - rm -rf sequencer_runner/rocksdb + rm -rf sequencer/service/bedrock_signing_key + rm -rf sequencer/service/rocksdb rm -rf indexer/service/rocksdb rm -rf wallet/configs/debug/storage.json rm -rf rocksdb diff --git a/README.md b/README.md index 1619747b..a08b81fb 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ The sequencer and logos blockchain node can be run locally: - `RUST_LOG=info cargo run -p indexer_service indexer/service/configs/indexer_config.json` 3. On another terminal go to the `logos-blockchain/lssa` repo and run the sequencer: - - `RUST_LOG=info cargo run -p sequencer_runner sequencer_runner/configs/debug` + - `RUST_LOG=info cargo run -p sequencer_service sequencer/service/configs/debug/sequencer_config.json` 4. (To run the explorer): on another terminal go to `logos-blockchain/lssa/explorer_service` and run the following: - `cargo install cargo-leptos` - `cargo leptos build --release` @@ -171,8 +171,8 @@ The sequencer and logos blockchain node can be run locally: After stopping services above you need to remove 3 folders to start cleanly: 1. In the `logos-blockchain/logos-blockchain` folder `state` (not needed in case of docker setup) - 2. In the `lssa` folder `sequencer_runner/rocksdb` - 3. In the `lssa` file `sequencer_runner/bedrock_signing_key` + 2. In the `lssa` folder `sequencer/service/rocksdb` + 3. In the `lssa` file `sequencer/service/bedrock_signing_key` 4. In the `lssa` folder `indexer/service/rocksdb` ### Normal mode (`just` commands) @@ -220,7 +220,7 @@ This will use a wallet binary built from this repo and not the one installed in ### Standalone mode The sequencer can be run in standalone mode with: ```bash -RUST_LOG=info cargo run --features standalone -p sequencer_runner sequencer_runner/configs/debug +RUST_LOG=info cargo run --features standalone -p sequencer_service sequencer/service/configs/debug ``` ## Running with Docker diff --git a/configs/docker-all-in-one/sequencer/sequencer_config.json b/configs/docker-all-in-one/sequencer/sequencer_config.json index 8fc34911..c03cbf5e 100644 --- a/configs/docker-all-in-one/sequencer/sequencer_config.json +++ b/configs/docker-all-in-one/sequencer/sequencer_config.json @@ -1,5 +1,5 @@ { - "home": "/var/lib/sequencer_runner", + "home": "/var/lib/sequencer_service", "override_rust_log": null, "genesis_id": 1, "is_genesis_random": true, diff --git a/docker-compose.override.yml b/docker-compose.override.yml index fe0d18f9..af70ddd6 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -7,12 +7,12 @@ services: environment: - RUST_LOG=error - sequencer_runner: + sequencer_service: depends_on: - logos-blockchain-node-0 - indexer_service volumes: !override - - ./configs/docker-all-in-one/sequencer:/etc/sequencer_runner + - ./configs/docker-all-in-one/sequencer:/etc/sequencer_service indexer_service: depends_on: diff --git a/docker-compose.yml b/docker-compose.yml index 93b5896b..4fd3910f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ include: - path: bedrock/docker-compose.yml - path: - sequencer_runner/docker-compose.yml + sequencer/service/docker-compose.yml - path: indexer/service/docker-compose.yml - path: diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index b18b782f..a68609a3 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -11,7 +11,7 @@ workspace = true nssa_core = { workspace = true, features = ["host"] } nssa.workspace = true sequencer_core = { workspace = true, features = ["default", "testnet"] } -sequencer_runner.workspace = true +sequencer_service.workspace = true wallet.workspace = true common.workspace = true key_protocol.workspace = true diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 6929ec92..d7324f8a 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -11,7 +11,7 @@ use log::{debug, error, warn}; use nssa::{AccountId, PrivacyPreservingTransaction}; use nssa_core::Commitment; use sequencer_core::indexer_client::{IndexerClient, IndexerClientTrait as _}; -use sequencer_runner::SequencerHandle; +use sequencer_service::SequencerHandle; use tempfile::TempDir; use testcontainers::compose::DockerCompose; use wallet::{WalletCore, config::WalletConfigOverrides}; @@ -229,7 +229,7 @@ impl TestContext { ) .context("Failed to create Sequencer config")?; - let sequencer_handle = sequencer_runner::startup_sequencer(config).await?; + let sequencer_handle = sequencer_service::startup_sequencer(config).await?; Ok((sequencer_handle, temp_sequencer_dir)) } diff --git a/sequencer_core/Cargo.toml b/sequencer/core/Cargo.toml similarity index 100% rename from sequencer_core/Cargo.toml rename to sequencer/core/Cargo.toml diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer/core/src/block_settlement_client.rs similarity index 100% rename from sequencer_core/src/block_settlement_client.rs rename to sequencer/core/src/block_settlement_client.rs diff --git a/sequencer_core/src/block_store.rs b/sequencer/core/src/block_store.rs similarity index 100% rename from sequencer_core/src/block_store.rs rename to sequencer/core/src/block_store.rs diff --git a/sequencer_core/src/config.rs b/sequencer/core/src/config.rs similarity index 100% rename from sequencer_core/src/config.rs rename to sequencer/core/src/config.rs diff --git a/sequencer_core/src/indexer_client.rs b/sequencer/core/src/indexer_client.rs similarity index 100% rename from sequencer_core/src/indexer_client.rs rename to sequencer/core/src/indexer_client.rs diff --git a/sequencer_core/src/lib.rs b/sequencer/core/src/lib.rs similarity index 100% rename from sequencer_core/src/lib.rs rename to sequencer/core/src/lib.rs diff --git a/sequencer_core/src/mock.rs b/sequencer/core/src/mock.rs similarity index 100% rename from sequencer_core/src/mock.rs rename to sequencer/core/src/mock.rs diff --git a/sequencer_runner/Cargo.toml b/sequencer/service/Cargo.toml similarity index 96% rename from sequencer_runner/Cargo.toml rename to sequencer/service/Cargo.toml index 71404d13..235b4d71 100644 --- a/sequencer_runner/Cargo.toml +++ b/sequencer/service/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sequencer_runner" +name = "sequencer_service" version = "0.1.0" edition = "2024" license = { workspace = true } diff --git a/sequencer_runner/Dockerfile b/sequencer/service/Dockerfile similarity index 79% rename from sequencer_runner/Dockerfile rename to sequencer/service/Dockerfile index 0efdf561..73db0336 100644 --- a/sequencer_runner/Dockerfile +++ b/sequencer/service/Dockerfile @@ -40,7 +40,7 @@ RUN r0vm --version # Install logos blockchain circuits RUN curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/main/scripts/setup-logos-blockchain-circuits.sh | bash -WORKDIR /sequencer_runner +WORKDIR /sequencer_service # Build argument to enable standalone feature (defaults to false) ARG STANDALONE=false @@ -48,17 +48,17 @@ ARG STANDALONE=false # Planner stage - generates dependency recipe FROM chef AS planner COPY . . -RUN cargo chef prepare --bin sequencer_runner --recipe-path recipe.json +RUN cargo chef prepare --bin sequencer_service --recipe-path recipe.json # Builder stage - builds dependencies and application FROM chef AS builder ARG STANDALONE -COPY --from=planner /sequencer_runner/recipe.json recipe.json +COPY --from=planner /sequencer_service/recipe.json recipe.json # Build dependencies only (this layer will be cached) RUN if [ "$STANDALONE" = "true" ]; then \ - cargo chef cook --bin sequencer_runner --features standalone --release --recipe-path recipe.json; \ + cargo chef cook --bin sequencer_service --features standalone --release --recipe-path recipe.json; \ else \ - cargo chef cook --bin sequencer_runner --release --recipe-path recipe.json; \ + cargo chef cook --bin sequencer_service --release --recipe-path recipe.json; \ fi # Copy source code @@ -66,13 +66,13 @@ COPY . . # Build the actual application RUN if [ "$STANDALONE" = "true" ]; then \ - cargo build --release --features standalone --bin sequencer_runner; \ + cargo build --release --features standalone --bin sequencer_service; \ else \ - cargo build --release --bin sequencer_runner; \ + cargo build --release --bin sequencer_service; \ fi # Strip debug symbols to reduce binary size -RUN strip /sequencer_runner/target/release/sequencer_runner +RUN strip /sequencer_service/target/release/sequencer_service # Runtime stage - minimal image FROM debian:trixie-slim @@ -84,11 +84,11 @@ RUN apt-get update \ # Create non-root user for security RUN useradd -m -u 1000 -s /bin/bash sequencer_user && \ - mkdir -p /sequencer_runner /etc/sequencer_runner && \ - chown -R sequencer_user:sequencer_user /sequencer_runner /etc/sequencer_runner + mkdir -p /sequencer_service /etc/sequencer_service && \ + chown -R sequencer_user:sequencer_user /sequencer_service /etc/sequencer_service # Copy binary from builder -COPY --from=builder --chown=sequencer_user:sequencer_user /sequencer_runner/target/release/sequencer_runner /usr/local/bin/sequencer_runner +COPY --from=builder --chown=sequencer_user:sequencer_user /sequencer_service/target/release/sequencer_service /usr/local/bin/sequencer_service # Copy r0vm binary from builder COPY --from=builder --chown=sequencer_user:sequencer_user /usr/local/bin/r0vm /usr/local/bin/r0vm @@ -97,7 +97,7 @@ COPY --from=builder --chown=sequencer_user:sequencer_user /usr/local/bin/r0vm /u COPY --from=builder --chown=sequencer_user:sequencer_user /root/.logos-blockchain-circuits /home/sequencer_user/.logos-blockchain-circuits # Copy entrypoint script -COPY sequencer_runner/docker-entrypoint.sh /docker-entrypoint.sh +COPY sequencer_service/docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh # Expose default port @@ -124,5 +124,5 @@ USER root ENTRYPOINT ["/docker-entrypoint.sh"] -WORKDIR /sequencer_runner -CMD ["sequencer_runner", "/etc/sequencer_runner"] +WORKDIR /sequencer_service +CMD ["sequencer_service", "/etc/sequencer_service"] diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer/service/configs/debug/sequencer_config.json similarity index 100% rename from sequencer_runner/configs/debug/sequencer_config.json rename to sequencer/service/configs/debug/sequencer_config.json diff --git a/sequencer_runner/configs/docker/sequencer_config.json b/sequencer/service/configs/docker/sequencer_config.json similarity index 98% rename from sequencer_runner/configs/docker/sequencer_config.json rename to sequencer/service/configs/docker/sequencer_config.json index 45cef1b6..adefe1f4 100644 --- a/sequencer_runner/configs/docker/sequencer_config.json +++ b/sequencer/service/configs/docker/sequencer_config.json @@ -1,5 +1,5 @@ { - "home": "/var/lib/sequencer_runner", + "home": "/var/lib/sequencer_service", "override_rust_log": null, "genesis_id": 1, "is_genesis_random": true, diff --git a/sequencer/service/docker-compose.yml b/sequencer/service/docker-compose.yml new file mode 100644 index 00000000..ebc024d6 --- /dev/null +++ b/sequencer/service/docker-compose.yml @@ -0,0 +1,14 @@ +services: + sequencer_service: + image: lssa/sequencer_service + build: + context: .. + dockerfile: sequencer/service/Dockerfile + container_name: sequencer_service + ports: + - "3040:3040" + volumes: + # Mount configuration folder + - ./configs/docker:/etc/sequencer_service + # Mount data folder + - ./data:/var/lib/sequencer_service diff --git a/sequencer_runner/docker-entrypoint.sh b/sequencer/service/docker-entrypoint.sh similarity index 81% rename from sequencer_runner/docker-entrypoint.sh rename to sequencer/service/docker-entrypoint.sh index fb117131..131c83e6 100644 --- a/sequencer_runner/docker-entrypoint.sh +++ b/sequencer/service/docker-entrypoint.sh @@ -1,11 +1,11 @@ #!/bin/sh -# This is an entrypoint script for the sequencer_runner Docker container, +# This is an entrypoint script for the sequencer_service Docker container, # it's not meant to be executed outside of the container. set -e -CONFIG="/etc/sequencer_runner/sequencer_config.json" +CONFIG="/etc/sequencer/service/sequencer_config.json" # Check config file exists if [ ! -f "$CONFIG" ]; then diff --git a/sequencer_rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml similarity index 100% rename from sequencer_rpc/Cargo.toml rename to sequencer/service/rpc/Cargo.toml diff --git a/sequencer_rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs similarity index 100% rename from sequencer_rpc/src/lib.rs rename to sequencer/service/rpc/src/lib.rs diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer/service/rpc/src/net_utils.rs similarity index 100% rename from sequencer_rpc/src/net_utils.rs rename to sequencer/service/rpc/src/net_utils.rs diff --git a/sequencer_rpc/src/process.rs b/sequencer/service/rpc/src/process.rs similarity index 100% rename from sequencer_rpc/src/process.rs rename to sequencer/service/rpc/src/process.rs diff --git a/sequencer_rpc/src/types/err_rpc.rs b/sequencer/service/rpc/src/types/err_rpc.rs similarity index 100% rename from sequencer_rpc/src/types/err_rpc.rs rename to sequencer/service/rpc/src/types/err_rpc.rs diff --git a/sequencer_rpc/src/types/mod.rs b/sequencer/service/rpc/src/types/mod.rs similarity index 100% rename from sequencer_rpc/src/types/mod.rs rename to sequencer/service/rpc/src/types/mod.rs diff --git a/sequencer_runner/src/lib.rs b/sequencer/service/src/lib.rs similarity index 100% rename from sequencer_runner/src/lib.rs rename to sequencer/service/src/lib.rs diff --git a/sequencer_runner/src/main.rs b/sequencer/service/src/main.rs similarity index 91% rename from sequencer_runner/src/main.rs rename to sequencer/service/src/main.rs index 3bf4ee2d..d0c51073 100644 --- a/sequencer_runner/src/main.rs +++ b/sequencer/service/src/main.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use sequencer_runner::main_runner; +use sequencer_service::main_runner; pub const NUM_THREADS: usize = 4; diff --git a/sequencer_runner/docker-compose.yml b/sequencer_runner/docker-compose.yml deleted file mode 100644 index 5301962c..00000000 --- a/sequencer_runner/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -services: - sequencer_runner: - image: lssa/sequencer_runner - build: - context: .. - dockerfile: sequencer_runner/Dockerfile - container_name: sequencer_runner - ports: - - "3040:3040" - volumes: - # Mount configuration folder - - ./configs/docker:/etc/sequencer_runner - # Mount data folder - - ./data:/var/lib/sequencer_runner diff --git a/wallet/src/main.rs b/wallet/src/main.rs index 4704675b..e055bd63 100644 --- a/wallet/src/main.rs +++ b/wallet/src/main.rs @@ -15,7 +15,7 @@ use wallet::{ // TODO #169: We have sample configs for sequencer, but not for wallet // TODO #168: Why it requires config as a directory? Maybe better to deduce directory from config // file path? -// TODO #172: Why it requires config as env var while sequencer_runner accepts as +// TODO #172: Why it requires config as env var while sequencer_service accepts as // argument? #[tokio::main] async fn main() -> Result<()> { From be94e133fa773c5ccc373ceb937a38d75fec1769 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Thu, 12 Mar 2026 15:43:18 +0300 Subject: [PATCH 02/10] feat: refactor sequencer RPC server-side --- Cargo.lock | 411 ++------- Cargo.toml | 10 +- common/src/block.rs | 12 +- common/src/error.rs | 43 - common/src/lib.rs | 3 - common/src/rpc_primitives/errors.rs | 194 ----- common/src/rpc_primitives/message.rs | 588 ------------- common/src/rpc_primitives/mod.rs | 57 -- common/src/rpc_primitives/parser.rs | 29 - common/src/rpc_primitives/requests.rs | 219 ----- common/src/sequencer_client.rs | 361 -------- common/src/transaction.rs | 4 +- indexer/service/Cargo.toml | 1 - indexer/service/protocol/src/convert.rs | 31 +- indexer/service/protocol/src/lib.rs | 2 +- indexer/service/src/lib.rs | 8 +- indexer/service/src/mock_service.rs | 11 +- indexer/service/src/service.rs | 4 +- nssa/Cargo.toml | 2 + nssa/src/base64.rs | 14 + nssa/src/lib.rs | 1 + .../privacy_preserving_transaction/circuit.rs | 5 +- .../privacy_preserving_transaction/message.rs | 5 +- .../transaction.rs | 3 +- .../witness_set.rs | 3 +- .../program_deployment_transaction/message.rs | 4 +- .../transaction.rs | 3 +- nssa/src/public_transaction/message.rs | 4 +- nssa/src/public_transaction/transaction.rs | 3 +- nssa/src/public_transaction/witness_set.rs | 3 +- nssa/src/signature/mod.rs | 23 +- nssa/src/signature/private_key.rs | 28 +- nssa/src/signature/public_key.rs | 23 +- sequencer/core/src/block_store.rs | 6 +- sequencer/core/src/config.rs | 4 - sequencer/core/src/lib.rs | 3 +- sequencer/service/Cargo.toml | 13 +- sequencer/service/rpc/Cargo.toml | 32 +- sequencer/service/rpc/src/lib.rs | 111 ++- sequencer/service/rpc/src/net_utils.rs | 104 --- sequencer/service/rpc/src/process.rs | 786 ------------------ sequencer/service/rpc/src/types/err_rpc.rs | 49 -- sequencer/service/rpc/src/types/mod.rs | 1 - sequencer/service/src/lib.rs | 161 ++-- sequencer/service/src/main.rs | 70 +- sequencer/service/src/service.rs | 202 +++++ storage/src/error.rs | 7 + storage/src/indexer.rs | 32 +- storage/src/sequencer.rs | 24 +- wallet/configs/debug/wallet_config.json | 70 +- wallet/src/lib.rs | 16 + 51 files changed, 677 insertions(+), 3126 deletions(-) delete mode 100644 common/src/error.rs delete mode 100644 common/src/rpc_primitives/errors.rs delete mode 100644 common/src/rpc_primitives/message.rs delete mode 100644 common/src/rpc_primitives/mod.rs delete mode 100644 common/src/rpc_primitives/parser.rs delete mode 100644 common/src/rpc_primitives/requests.rs delete mode 100644 common/src/sequencer_client.rs create mode 100644 nssa/src/base64.rs delete mode 100644 sequencer/service/rpc/src/net_utils.rs delete mode 100644 sequencer/service/rpc/src/process.rs delete mode 100644 sequencer/service/rpc/src/types/err_rpc.rs delete mode 100644 sequencer/service/rpc/src/types/mod.rs create mode 100644 sequencer/service/src/service.rs diff --git a/Cargo.lock b/Cargo.lock index d8b51cbc..1695180d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,229 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "actix" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" -dependencies = [ - "actix-macros", - "actix-rt", - "actix_derive", - "bitflags 2.11.0", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", -] - -[[package]] -name = "actix-codec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" -dependencies = [ - "bitflags 2.11.0", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-cors" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d" -dependencies = [ - "actix-utils", - "actix-web", - "derive_more", - "futures-util", - "log", - "once_cell", - "smallvec", -] - -[[package]] -name = "actix-http" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f860ee6746d0c5b682147b2f7f8ef036d4f92fe518251a3a35ffa3650eafdf0e" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "bitflags 2.11.0", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "foldhash", - "futures-core", - "http 0.2.12", - "httparse", - "httpdate", - "itoa", - "language-tags", - "mime", - "percent-encoding", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "actix-router" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f8c75c51892f18d9c46150c5ac7beb81c95f78c8b83a634d49f4ca32551fe7" -dependencies = [ - "bytestring", - "cfg-if", - "http 0.2.12", - "regex-lite", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.10", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87453bc3b56e9b2b23c1cc0b1be8797184accf51d2abe0f8a33ec275d316bf" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "bytes", - "bytestring", - "cfg-if", - "derive_more", - "encoding_rs", - "foldhash", - "futures-core", - "futures-util", - "impl-more", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex-lite", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.6.3", - "time", - "tracing", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "actix_derive" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ac1e58cded18cb28ddc17143c4dea5345b3ad575e14f32f66e4054a56eb271" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "addchain" version = "0.2.1" @@ -1011,7 +788,7 @@ dependencies = [ "axum-core 0.4.5", "bytes", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -1045,7 +822,7 @@ dependencies = [ "bytes", "form_urlencoded", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -1080,7 +857,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "mime", @@ -1099,7 +876,7 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "http-body-util", "mime", @@ -1313,7 +1090,7 @@ dependencies = [ "futures-util", "hex", "home", - "http 1.4.0", + "http", "http-body-util", "hyper", "hyper-named-pipe", @@ -1466,15 +1243,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "bytestring" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" -dependencies = [ - "bytes", -] - [[package]] name = "bzip2-sys" version = "0.1.13+1.0.8" @@ -1877,15 +1645,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "convert_case" version = "0.11.0" @@ -1992,15 +1751,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -2297,7 +2047,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", @@ -3099,7 +2848,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.4.0", + "http", "js-sys", "pin-project", "serde", @@ -3163,7 +2912,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap 2.13.0", "slab", "tokio", @@ -3318,17 +3067,6 @@ dependencies = [ "utf8-width", ] -[[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" version = "1.4.0" @@ -3346,7 +3084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -3357,7 +3095,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "pin-project-lite", ] @@ -3432,7 +3170,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http", "http-body", "httparse", "httpdate", @@ -3465,7 +3203,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", + "http", "hyper", "hyper-util", "log", @@ -3516,14 +3254,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2", "system-configuration", "tokio", "tower-service", @@ -3684,12 +3422,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "impl-more" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" - [[package]] name = "include_bytes_aligned" version = "0.1.4" @@ -3725,7 +3457,6 @@ version = "0.1.0" dependencies = [ "anyhow", "arc-swap", - "async-trait", "clap", "env_logger", "futures", @@ -4048,7 +3779,7 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http 1.4.0", + "http", "jsonrpsee-core", "pin-project", "rustls", @@ -4073,7 +3804,7 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "jsonrpsee-types", @@ -4134,7 +3865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c51b7c290bb68ce3af2d029648148403863b982f138484a73f02a9dd52dbd7f" dependencies = [ "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -4160,7 +3891,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc88ff4688e43cc3fa9883a8a95c6fa27aa2e76c96e610b737b6554d650d7fd5" dependencies = [ - "http 1.4.0", + "http", "serde", "serde_json", "thiserror 2.0.18", @@ -4184,7 +3915,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6fceceeb05301cc4c065ab3bd2fa990d41ff4eb44e4ca1b30fa99c057c3e79" dependencies = [ - "http 1.4.0", + "http", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -4238,12 +3969,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "language-tags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - [[package]] name = "lazy-regex" version = "3.6.0" @@ -4620,12 +4345,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "local-waker" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" - [[package]] name = "lock_api" version = "0.4.14" @@ -5384,7 +5103,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] @@ -5398,7 +5116,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.4.0", + "http", "httparse", "memchr", "mime", @@ -5533,6 +5251,7 @@ name = "nssa" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.22.1", "borsh", "env_logger", "hex", @@ -5545,6 +5264,7 @@ dependencies = [ "risc0-zkvm", "secp256k1", "serde", + "serde_with", "sha2", "test-case", "test_program_methods", @@ -6270,7 +5990,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -6307,7 +6027,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -6581,12 +6301,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" - [[package]] name = "regex-syntax" version = "0.8.10" @@ -6606,7 +6320,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -7452,48 +7166,39 @@ dependencies = [ "url", ] -[[package]] -name = "sequencer_rpc" -version = "0.1.0" -dependencies = [ - "actix-cors", - "actix-web", - "anyhow", - "base58", - "base64 0.22.1", - "bedrock_client", - "borsh", - "bytesize", - "common", - "futures", - "hex", - "itertools 0.14.0", - "log", - "mempool", - "nssa", - "sequencer_core", - "serde", - "serde_json", - "tempfile", - "tokio", -] - [[package]] name = "sequencer_service" version = "0.1.0" dependencies = [ - "actix", - "actix-web", "anyhow", + "borsh", + "bytesize", "clap", "common", "env_logger", "futures", "indexer_service_rpc", + "jsonrpsee", "log", + "mempool", + "nssa", + "nssa_core", "sequencer_core", - "sequencer_rpc", + "sequencer_service_rpc", "tokio", + "tokio-util", +] + +[[package]] +name = "sequencer_service_rpc" +version = "0.1.0" +dependencies = [ + "common", + "jsonrpsee", + "nssa", + "nssa_core", + "schemars 1.2.1", + "serde_json", ] [[package]] @@ -7689,7 +7394,7 @@ dependencies = [ "const_format", "futures", "gloo-net", - "http 1.4.0", + "http", "http-body-util", "hyper", "inventory", @@ -7826,16 +7531,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -7855,7 +7550,7 @@ dependencies = [ "base64 0.22.1", "bytes", "futures", - "http 1.4.0", + "http", "httparse", "log", "rand 0.8.5", @@ -8161,7 +7856,7 @@ dependencies = [ "etcetera", "ferroid", "futures", - "http 1.4.0", + "http", "itertools 0.14.0", "log", "memchr", @@ -8321,7 +8016,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -8518,7 +8213,7 @@ dependencies = [ "base64 0.22.1", "bytes", "h2", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -8526,7 +8221,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.3", + "socket2", "sync_wrapper", "tokio", "tokio-stream", @@ -8576,7 +8271,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "http-range-header", @@ -8678,7 +8373,7 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http", "httparse", "log", "rand 0.9.2", @@ -8860,7 +8555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" dependencies = [ "base64 0.22.1", - "http 1.4.0", + "http", "httparse", "log", ] diff --git a/Cargo.toml b/Cargo.toml index 78d5adb7..abe84745 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,9 @@ members = [ "programs/amm", "programs/token/core", "programs/token", - "sequencer_core", - "sequencer_rpc", - "sequencer_service", + "sequencer/core", + "sequencer/service", + "sequencer/service/rpc", "indexer/core", "indexer/service", "indexer/service/protocol", @@ -42,8 +42,8 @@ common = { path = "common" } mempool = { path = "mempool" } storage = { path = "storage" } key_protocol = { path = "key_protocol" } -sequencer_core = { path = "sequencer_core" } -sequencer_rpc = { path = "sequencer_rpc" } +sequencer_core = { path = "sequencer/core" } +sequencer_service_rpc = { path = "sequencer/service/rpc" } sequencer_service = { path = "sequencer/service" } indexer_core = { path = "indexer/core" } indexer_service = { path = "indexer/service" } diff --git a/common/src/block.rs b/common/src/block.rs index 8ef2eb0c..7759333a 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -10,7 +10,7 @@ pub type BlockHash = HashType; pub type BlockId = u64; pub type TimeStamp = u64; -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct BlockMeta { pub id: BlockId, pub hash: BlockHash, @@ -31,7 +31,7 @@ impl OwnHasher { } } -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: BlockHash, @@ -40,19 +40,19 @@ pub struct BlockHeader { pub signature: nssa::Signature, } -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct BlockBody { pub transactions: Vec, } -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub enum BedrockStatus { Pending, Safe, Finalized, } -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct Block { pub header: BlockHeader, pub body: BlockBody, @@ -60,7 +60,7 @@ pub struct Block { pub bedrock_parent_id: MantleMsgId, } -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, diff --git a/common/src/error.rs b/common/src/error.rs deleted file mode 100644 index 1e348a32..00000000 --- a/common/src/error.rs +++ /dev/null @@ -1,43 +0,0 @@ -use nssa::AccountId; -use serde::Deserialize; - -use crate::rpc_primitives::errors::RpcError; - -#[derive(Debug, Clone, Deserialize)] -pub struct SequencerRpcError { - pub jsonrpc: String, - pub error: RpcError, - pub id: u64, -} - -#[derive(thiserror::Error, Debug)] -pub enum SequencerClientError { - #[error("HTTP error")] - HTTPError(#[from] reqwest::Error), - #[error("Serde error")] - SerdeError(#[from] serde_json::Error), - #[error("Internal error: {0:?}")] - InternalError(SequencerRpcError), -} - -impl From for SequencerClientError { - fn from(value: SequencerRpcError) -> Self { - Self::InternalError(value) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum ExecutionFailureKind { - #[error("Failed to get data from sequencer")] - SequencerError(#[source] anyhow::Error), - #[error("Inputs amounts does not match outputs")] - AmountMismatchError, - #[error("Accounts key not found")] - KeyNotFoundError, - #[error("Sequencer client error: {0:?}")] - SequencerClientError(#[from] SequencerClientError), - #[error("Can not pay for operation")] - InsufficientFundsError, - #[error("Account {0} data is invalid")] - AccountDataError(AccountId), -} diff --git a/common/src/lib.rs b/common/src/lib.rs index da07a602..57d70b64 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -5,9 +5,6 @@ use serde_with::{DeserializeFromStr, SerializeDisplay}; pub mod block; pub mod config; -pub mod error; -pub mod rpc_primitives; -pub mod sequencer_client; pub mod transaction; // Module for tests utility functions diff --git a/common/src/rpc_primitives/errors.rs b/common/src/rpc_primitives/errors.rs deleted file mode 100644 index 28ec0b63..00000000 --- a/common/src/rpc_primitives/errors.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::fmt; - -use serde_json::{Value, to_value}; - -#[derive(serde::Serialize)] -pub struct RpcParseError(pub String); - -/// This struct may be returned from JSON RPC server in case of error. -/// -/// It is expected that that this struct has impls From<_> all other RPC errors -/// like [`RpcBlockError`](crate::types::blocks::RpcBlockError). -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -pub struct RpcError { - #[serde(flatten)] - pub error_struct: Option, - /// Deprecated please use the `error_struct` instead. - pub code: i64, - /// Deprecated please use the `error_struct` instead. - pub message: String, - /// Deprecated please use the `error_struct` instead. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)] -#[serde(tag = "name", content = "cause", rename_all = "SCREAMING_SNAKE_CASE")] -pub enum RpcErrorKind { - RequestValidationError(RpcRequestValidationErrorKind), - HandlerError(Value), - InternalError(Value), -} - -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)] -#[serde(tag = "name", content = "info", rename_all = "SCREAMING_SNAKE_CASE")] -pub enum RpcRequestValidationErrorKind { - MethodNotFound { method_name: String }, - ParseError { error_message: String }, -} - -/// A general Server Error. -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum ServerError { - Timeout, - Closed, -} - -impl RpcError { - /// A generic constructor. - /// - /// Mostly for completeness, doesn't do anything but filling in the corresponding fields. - #[must_use] - pub const fn new(code: i64, message: String, data: Option) -> Self { - Self { - code, - message, - data, - error_struct: None, - } - } - - /// Create an Invalid Param error. - pub fn invalid_params(data: impl serde::Serialize) -> Self { - let value = match to_value(data) { - Ok(value) => value, - Err(err) => { - return Self::server_error(Some(format!( - "Failed to serialize invalid parameters error: {:?}", - err.to_string() - ))); - } - }; - Self::new(-32_602, "Invalid params".to_owned(), Some(value)) - } - - /// Create a server error. - pub fn server_error(e: Option) -> Self { - Self::new( - -32_000, - "Server error".to_owned(), - e.map(|v| to_value(v).expect("Must be representable in JSON")), - ) - } - - /// Create a parse error. - #[must_use] - pub fn parse_error(e: String) -> Self { - Self { - code: -32_700, - message: "Parse error".to_owned(), - data: Some(Value::String(e.clone())), - error_struct: Some(RpcErrorKind::RequestValidationError( - RpcRequestValidationErrorKind::ParseError { error_message: e }, - )), - } - } - - #[must_use] - pub fn serialization_error(e: &str) -> Self { - Self::new_internal_error(Some(Value::String(e.to_owned())), e) - } - - /// Helper method to define extract `INTERNAL_ERROR` in separate `RpcErrorKind` - /// Returns `HANDLER_ERROR` if the error is not internal one. - #[must_use] - pub fn new_internal_or_handler_error(error_data: Option, error_struct: Value) -> Self { - if error_struct["name"] == "INTERNAL_ERROR" { - let error_message = match error_struct["info"].get("error_message") { - Some(Value::String(error_message)) => error_message.as_str(), - _ => "InternalError happened during serializing InternalError", - }; - Self::new_internal_error(error_data, error_message) - } else { - Self::new_handler_error(error_data, error_struct) - } - } - - #[must_use] - pub fn new_internal_error(error_data: Option, info: &str) -> Self { - Self { - code: -32_000, - message: "Server error".to_owned(), - data: error_data, - error_struct: Some(RpcErrorKind::InternalError(serde_json::json!({ - "name": "INTERNAL_ERROR", - "info": serde_json::json!({"error_message": info}) - }))), - } - } - - fn new_handler_error(error_data: Option, error_struct: Value) -> Self { - Self { - code: -32_000, - message: "Server error".to_owned(), - data: error_data, - error_struct: Some(RpcErrorKind::HandlerError(error_struct)), - } - } - - /// Create a method not found error. - #[must_use] - pub fn method_not_found(method: String) -> Self { - Self { - code: -32_601, - message: "Method not found".to_owned(), - data: Some(Value::String(method.clone())), - error_struct: Some(RpcErrorKind::RequestValidationError( - RpcRequestValidationErrorKind::MethodNotFound { - method_name: method, - }, - )), - } - } -} - -impl fmt::Display for RpcError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self:?}") - } -} - -impl From for RpcError { - fn from(parse_error: RpcParseError) -> Self { - Self::parse_error(parse_error.0) - } -} - -impl From for RpcError { - fn from(_: std::convert::Infallible) -> Self { - // SAFETY: Infallible error can never be constructed, so this code can never be reached. - unsafe { core::hint::unreachable_unchecked() } - } -} - -impl fmt::Display for ServerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Timeout => write!(f, "ServerError: Timeout"), - Self::Closed => write!(f, "ServerError: Closed"), - } - } -} - -impl From for RpcError { - fn from(e: ServerError) -> Self { - let error_data = match to_value(&e) { - Ok(value) => value, - Err(_err) => { - return Self::new_internal_error(None, "Failed to serialize ServerError"); - } - }; - Self::new_internal_error(Some(error_data), e.to_string().as_str()) - } -} diff --git a/common/src/rpc_primitives/message.rs b/common/src/rpc_primitives/message.rs deleted file mode 100644 index de7f132e..00000000 --- a/common/src/rpc_primitives/message.rs +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright 2017 tokio-jsonrpc Developers -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! JSON-RPC 2.0 messages. -//! -//! The main entrypoint here is the [Message](enum.Message.html). The others are just building -//! blocks and you should generally work with `Message` instead. -use std::fmt::{Formatter, Result as FmtResult}; - -use serde::{ - de::{Deserializer, Error, Unexpected, Visitor}, - ser::{SerializeStruct as _, Serializer}, -}; -use serde_json::{Result as JsonResult, Value}; - -use super::errors::RpcError; - -pub type Parsed = Result; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -struct Version; - -impl serde::Serialize for Version { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str("2.0") - } -} - -impl<'de> serde::Deserialize<'de> for Version { - #[expect( - clippy::renamed_function_params, - reason = "More readable than original serde parameter names" - )] - fn deserialize>(deserializer: D) -> Result { - struct VersionVisitor; - impl Visitor<'_> for VersionVisitor { - type Value = Version; - - fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult { - formatter.write_str("a version string") - } - - fn visit_str(self, value: &str) -> Result { - match value { - "2.0" => Ok(Version), - _ => Err(E::invalid_value(Unexpected::Str(value), &"value 2.0")), - } - } - } - deserializer.deserialize_str(VersionVisitor) - } -} - -/// An RPC request. -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -#[expect( - clippy::partial_pub_fields, - reason = "We don't want to allow access to the version, but the others are public for ease of use" -)] -pub struct Request { - jsonrpc: Version, - pub method: String, - #[serde(default, skip_serializing_if = "Value::is_null")] - pub params: Value, - pub id: Value, -} - -impl Request { - #[must_use] - pub fn from_payload_version_2_0(method: String, payload: serde_json::Value) -> Self { - Self { - jsonrpc: Version, - method, - params: payload, - // ToDo: Correct checking of id - id: 1.into(), - } - } - - /// Answer the request with a (positive) reply. - /// - /// The ID is taken from the request. - #[must_use] - pub fn reply(&self, reply: Value) -> Message { - Message::Response(Response { - jsonrpc: Version, - result: Ok(reply), - id: self.id.clone(), - }) - } - - /// Answer the request with an error. - #[must_use] - pub fn error(&self, error: RpcError) -> Message { - Message::Response(Response { - jsonrpc: Version, - result: Err(error), - id: self.id.clone(), - }) - } -} - -/// A response to an RPC. -/// -/// It is created by the methods on [Request](struct.Request.html). -#[expect( - clippy::partial_pub_fields, - reason = "We don't want to allow access to the version, but the others are public for ease of use" -)] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Response { - jsonrpc: Version, - pub result: Result, - pub id: Value, -} - -impl serde::Serialize for Response { - fn serialize(&self, serializer: S) -> Result { - let mut sub = serializer.serialize_struct("Response", 3)?; - sub.serialize_field("jsonrpc", &self.jsonrpc)?; - match &self.result { - Ok(value) => sub.serialize_field("result", value), - Err(err) => sub.serialize_field("error", err), - }?; - sub.serialize_field("id", &self.id)?; - sub.end() - } -} - -/// A helper trick for deserialization. -#[derive(serde::Deserialize)] -#[serde(deny_unknown_fields)] -struct WireResponse { - // It is actually used to eat and sanity check the deserialized text - #[serde(rename = "jsonrpc")] - _jsonrpc: Version, - // Make sure we accept null as Some(Value::Null), instead of going to None - #[serde(default, deserialize_with = "some_value")] - result: Option, - error: Option, - id: Value, -} - -// Implementing deserialize is hard. We sidestep the difficulty by deserializing a similar -// structure that directly corresponds to whatever is on the wire and then convert it to our more -// convenient representation. -impl<'de> serde::Deserialize<'de> for Response { - fn deserialize>(deserializer: D) -> Result { - let wr: WireResponse = serde::Deserialize::deserialize(deserializer)?; - let result = match (wr.result, wr.error) { - (Some(res), None) => Ok(res), - (None, Some(err)) => Err(err), - _ => { - let err = D::Error::custom("Either 'error' or 'result' is expected, but not both"); - return Err(err); - } - }; - Ok(Self { - jsonrpc: Version, - result, - id: wr.id, - }) - } -} - -/// A notification (doesn't expect an answer). -#[expect( - clippy::partial_pub_fields, - reason = "We don't want to allow access to the version, but the others are public for ease of use" -)] -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -pub struct Notification { - jsonrpc: Version, - pub method: String, - #[serde(default, skip_serializing_if = "Value::is_null")] - pub params: Value, -} - -/// One message of the JSON RPC protocol. -/// -/// One message, directly mapped from the structures of the protocol. See the -/// [specification](http://www.jsonrpc.org/specification) for more details. -/// -/// Since the protocol allows one endpoint to be both client and server at the same time, the -/// message can decode and encode both directions of the protocol. -/// -/// The `Batch` variant is supposed to be created directly, without a constructor. -/// -/// The `UnmatchedSub` variant is used when a request is an array and some of the subrequests -/// aren't recognized as valid json rpc 2.0 messages. This is never returned as a top-level -/// element, it is returned as `Err(Broken::Unmatched)`. -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -#[serde(untagged)] -pub enum Message { - /// An RPC request. - Request(Request), - /// A response to a Request. - Response(Response), - /// A notification. - Notification(Notification), - /// A batch of more requests or responses. - /// - /// The protocol allows bundling multiple requests, notifications or responses to a single - /// message. - /// - /// This variant has no direct constructor and is expected to be constructed manually. - Batch(Vec), - /// An unmatched sub entry in a `Batch`. - /// - /// When there's a `Batch` and an element doesn't comform to the JSONRPC 2.0 format, that one - /// is represented by this. This is never produced as a top-level value when parsing, the - /// `Err(Broken::Unmatched)` is used instead. It is not possible to serialize. - #[serde(skip_serializing)] - UnmatchedSub(Value), -} - -impl Message { - /// A constructor for a request. - /// - /// The ID is auto-set to dontcare. - #[must_use] - pub fn request(method: String, params: Value) -> Self { - let id = Value::from("dontcare"); - Self::Request(Request { - jsonrpc: Version, - method, - params, - id, - }) - } - - /// Create a top-level error (without an ID). - #[must_use] - pub const fn error(error: RpcError) -> Self { - Self::Response(Response { - jsonrpc: Version, - result: Err(error), - id: Value::Null, - }) - } - - /// A constructor for a notification. - #[must_use] - pub const fn notification(method: String, params: Value) -> Self { - Self::Notification(Notification { - jsonrpc: Version, - method, - params, - }) - } - - /// A constructor for a response. - #[must_use] - pub const fn response(id: Value, result: Result) -> Self { - Self::Response(Response { - jsonrpc: Version, - result, - id, - }) - } - - /// Returns id or Null if there is no id. - #[must_use] - pub fn id(&self) -> Value { - match self { - Self::Request(req) => req.id.clone(), - Self::Response(response) => response.id.clone(), - Self::Notification(_) | Self::Batch(_) | Self::UnmatchedSub(_) => Value::Null, - } - } -} - -impl From for String { - fn from(val: Message) -> Self { - ::serde_json::ser::to_string(&val).expect("message serialization to json should not fail") - } -} - -impl From for Vec { - fn from(val: Message) -> Self { - ::serde_json::ser::to_vec(&val) - .expect("message serialization to json bytes should not fail") - } -} - -/// A broken message. -/// -/// Protocol-level errors. -#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize)] -#[serde(untagged)] -pub enum Broken { - /// It was valid JSON, but doesn't match the form of a JSONRPC 2.0 message. - Unmatched(Value), - /// Invalid JSON. - #[serde(skip_deserializing)] - SyntaxError(String), -} - -impl Broken { - /// Generate an appropriate error message. - /// - /// The error message for these things are specified in the RFC, so this just creates an error - /// with the right values. - #[must_use] - pub fn reply(&self) -> Message { - match self { - Self::Unmatched(_) => Message::error(RpcError::parse_error( - "JSON RPC Request format was expected".to_owned(), - )), - Self::SyntaxError(e) => Message::error(RpcError::parse_error(e.clone())), - } - } -} - -/// A trick to easily deserialize and detect valid JSON, but invalid Message. -#[derive(serde::Deserialize)] -#[serde(untagged)] -pub enum WireMessage { - Message(Message), - Broken(Broken), -} - -pub fn decoded_to_parsed(res: JsonResult) -> Parsed { - match res { - Ok(WireMessage::Message(Message::UnmatchedSub(value))) => Err(Broken::Unmatched(value)), - Ok(WireMessage::Message(m)) => Ok(m), - Ok(WireMessage::Broken(b)) => Err(b), - Err(e) => Err(Broken::SyntaxError(e.to_string())), - } -} - -/// Read a [Message](enum.Message.html) from a slice. -/// -/// Invalid JSON or JSONRPC messages are reported as [Broken](enum.Broken.html). -pub fn from_slice(s: &[u8]) -> Parsed { - decoded_to_parsed(::serde_json::de::from_slice(s)) -} - -/// Read a [Message](enum.Message.html) from a string. -/// -/// Invalid JSON or JSONRPC messages are reported as [Broken](enum.Broken.html). -pub fn from_str(s: &str) -> Parsed { - from_slice(s.as_bytes()) -} - -/// Deserializer for `Option` that produces `Some(Value::Null)`. -/// -/// The usual one produces None in that case. But we need to know the difference between -/// `{x: null}` and `{}`. -fn some_value<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { - serde::Deserialize::deserialize(deserializer).map(Some) -} - -#[cfg(test)] -mod tests { - use serde_json::{Value, de::from_slice, json, ser::to_vec}; - - use super::*; - - /// Test serialization and deserialization of the Message. - /// - /// We first deserialize it from a string. That way we check deserialization works. - /// But since serialization doesn't have to produce the exact same result (order, spaces, …), - /// we then serialize and deserialize the thing again and check it matches. - #[test] - fn message_serde() { - // A helper for running one message test - fn one(input: &str, expected: &Message) { - let parsed: Message = from_str(input).unwrap(); - assert_eq!(*expected, parsed); - let serialized = to_vec(&parsed).unwrap(); - let deserialized: Message = from_slice(&serialized).unwrap(); - assert_eq!(parsed, deserialized); - } - - // A request without parameters - one( - r#"{"jsonrpc": "2.0", "method": "call", "id": 1}"#, - &Message::Request(Request { - jsonrpc: Version, - method: "call".to_owned(), - params: Value::Null, - id: json!(1), - }), - ); - // A request with parameters - one( - r#"{"jsonrpc": "2.0", "method": "call", "params": [1, 2, 3], "id": 2}"#, - &Message::Request(Request { - jsonrpc: Version, - method: "call".to_owned(), - params: json!([1, 2, 3]), - id: json!(2), - }), - ); - // A notification (with parameters) - one( - r#"{"jsonrpc": "2.0", "method": "notif", "params": {"x": "y"}}"#, - &Message::Notification(Notification { - jsonrpc: Version, - method: "notif".to_owned(), - params: json!({"x": "y"}), - }), - ); - // A successful response - one( - r#"{"jsonrpc": "2.0", "result": 42, "id": 3}"#, - &Message::Response(Response { - jsonrpc: Version, - result: Ok(json!(42)), - id: json!(3), - }), - ); - // A successful response - one( - r#"{"jsonrpc": "2.0", "result": null, "id": 3}"#, - &Message::Response(Response { - jsonrpc: Version, - result: Ok(Value::Null), - id: json!(3), - }), - ); - // An error - one( - r#"{"jsonrpc": "2.0", "error": {"code": 42, "message": "Wrong!"}, "id": null}"#, - &Message::Response(Response { - jsonrpc: Version, - result: Err(RpcError::new(42, "Wrong!".to_owned(), None)), - id: Value::Null, - }), - ); - // A batch - one( - r#"[ - {"jsonrpc": "2.0", "method": "notif"}, - {"jsonrpc": "2.0", "method": "call", "id": 42} - ]"#, - &Message::Batch(vec![ - Message::Notification(Notification { - jsonrpc: Version, - method: "notif".to_owned(), - params: Value::Null, - }), - Message::Request(Request { - jsonrpc: Version, - method: "call".to_owned(), - params: Value::Null, - id: json!(42), - }), - ]), - ); - // Some handling of broken messages inside a batch - let parsed = from_str( - r#"[ - {"jsonrpc": "2.0", "method": "notif"}, - {"jsonrpc": "2.0", "method": "call", "id": 42}, - true - ]"#, - ) - .unwrap(); - assert_eq!( - Message::Batch(vec![ - Message::Notification(Notification { - jsonrpc: Version, - method: "notif".to_owned(), - params: Value::Null, - }), - Message::Request(Request { - jsonrpc: Version, - method: "call".to_owned(), - params: Value::Null, - id: json!(42), - }), - Message::UnmatchedSub(Value::Bool(true)), - ]), - parsed - ); - to_vec(&Message::UnmatchedSub(Value::Null)).unwrap_err(); - } - - /// A helper for the `broken` test. - /// - /// Check that the given JSON string parses, but is not recognized as a valid RPC message. - /// - /// Test things that are almost but not entirely JSONRPC are rejected. - /// - /// The reject is done by returning it as Unmatched. - #[test] - fn broken() { - // A helper with one test - fn one(input: &str) { - let msg = from_str(input); - match msg { - Err(Broken::Unmatched(_)) => (), - _ => panic!("{input} recognized as an RPC message: {msg:?}!"), - } - } - - // Missing the version - one(r#"{"method": "notif"}"#); - // Wrong version - one(r#"{"jsonrpc": 2.0, "method": "notif"}"#); - // A response with both result and error - one(r#"{"jsonrpc": "2.0", "result": 42, "error": {"code": 42, "message": "!"}, "id": 1}"#); - // A response without an id - one(r#"{"jsonrpc": "2.0", "result": 42}"#); - // An extra field - one(r#"{"jsonrpc": "2.0", "method": "weird", "params": 42, "others": 43, "id": 2}"#); - // Something completely different - one(r#"{"x": [1, 2, 3]}"#); - - match from_str("{]") { - Err(Broken::SyntaxError(_)) => (), - other => panic!("Something unexpected: {other:?}"), - } - } - - /// Test some non-trivial aspects of the constructors. - /// - /// This doesn't have a full coverage, because there's not much to actually test there. - /// Most of it is related to the ids. - #[test] - #[ignore = "Not a full coverage test"] - fn constructors() { - let msg1 = Message::request("call".to_owned(), json!([1, 2, 3])); - let msg2 = Message::request("call".to_owned(), json!([1, 2, 3])); - // They differ, even when created with the same parameters - assert_ne!(msg1, msg2); - // And, specifically, they differ in the ID's - let (req1, req2) = if let (Message::Request(req1), Message::Request(req2)) = (msg1, msg2) { - assert_ne!(req1.id, req2.id); - assert!(req1.id.is_string()); - assert!(req2.id.is_string()); - (req1, req2) - } else { - panic!("Non-request received"); - }; - let id1 = req1.id.clone(); - // When we answer a message, we get the same ID - if let Message::Response(resp) = req1.reply(json!([1, 2, 3])) { - assert_eq!( - resp, - Response { - jsonrpc: Version, - result: Ok(json!([1, 2, 3])), - id: id1 - } - ); - } else { - panic!("Not a response"); - } - let id2 = req2.id.clone(); - // The same with an error - if let Message::Response(resp) = req2.error(RpcError::new(42, "Wrong!".to_owned(), None)) { - assert_eq!( - resp, - Response { - jsonrpc: Version, - result: Err(RpcError::new(42, "Wrong!".to_owned(), None)), - id: id2, - } - ); - } else { - panic!("Not a response"); - } - // When we have unmatched, we generate a top-level error with Null id. - if let Message::Response(resp) = - Message::error(RpcError::new(43, "Also wrong!".to_owned(), None)) - { - assert_eq!( - resp, - Response { - jsonrpc: Version, - result: Err(RpcError::new(43, "Also wrong!".to_owned(), None)), - id: Value::Null, - } - ); - } else { - panic!("Not a response"); - } - } -} diff --git a/common/src/rpc_primitives/mod.rs b/common/src/rpc_primitives/mod.rs deleted file mode 100644 index cd643712..00000000 --- a/common/src/rpc_primitives/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use bytesize::ByteSize; -use serde::{Deserialize, Serialize}; - -pub mod errors; -pub mod message; -pub mod parser; -pub mod requests; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct RpcLimitsConfig { - /// Maximum byte size of the json payload. - pub json_payload_max_size: ByteSize, -} - -impl Default for RpcLimitsConfig { - fn default() -> Self { - Self { - json_payload_max_size: ByteSize::mib(10), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct RpcConfig { - pub addr: String, - pub cors_allowed_origins: Vec, - #[serde(default)] - pub limits_config: RpcLimitsConfig, -} - -impl Default for RpcConfig { - fn default() -> Self { - Self { - addr: "0.0.0.0:3040".to_owned(), - cors_allowed_origins: vec!["*".to_owned()], - limits_config: RpcLimitsConfig::default(), - } - } -} - -impl RpcConfig { - #[must_use] - pub fn new(addr: &str) -> Self { - Self { - addr: addr.to_owned(), - ..Default::default() - } - } - - #[must_use] - pub fn with_port(port: u16) -> Self { - Self { - addr: format!("0.0.0.0:{port}"), - ..Default::default() - } - } -} diff --git a/common/src/rpc_primitives/parser.rs b/common/src/rpc_primitives/parser.rs deleted file mode 100644 index 0b918c94..00000000 --- a/common/src/rpc_primitives/parser.rs +++ /dev/null @@ -1,29 +0,0 @@ -use serde::de::DeserializeOwned; -use serde_json::Value; - -use super::errors::RpcParseError; - -#[macro_export] -macro_rules! parse_request { - ($request_name:ty) => { - impl RpcRequest for $request_name { - fn parse(value: Option) -> Result { - parse_params::(value) - } - } - }; -} - -pub trait RpcRequest: Sized { - fn parse(value: Option) -> Result; -} - -pub fn parse_params(value: Option) -> Result { - value.map_or_else( - || Err(RpcParseError("Require at least one parameter".to_owned())), - |value| { - serde_json::from_value(value) - .map_err(|err| RpcParseError(format!("Failed parsing args: {err}"))) - }, - ) -} diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs deleted file mode 100644 index fd566c89..00000000 --- a/common/src/rpc_primitives/requests.rs +++ /dev/null @@ -1,219 +0,0 @@ -use std::collections::HashMap; - -use nssa::AccountId; -use nssa_core::program::ProgramId; -use serde::{Deserialize, Serialize}; -use serde_json::Value; - -use super::{ - errors::RpcParseError, - parser::{RpcRequest, parse_params}, -}; -use crate::{HashType, parse_request}; - -mod base64_deser { - use base64::{Engine as _, engine::general_purpose}; - use serde::{self, Deserialize, Deserializer, Serializer, ser::SerializeSeq as _}; - - pub mod vec { - use super::*; - - pub fn serialize(bytes_vec: &[Vec], serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(bytes_vec.len()))?; - for bytes in bytes_vec { - let s = general_purpose::STANDARD.encode(bytes); - seq.serialize_element(&s)?; - } - seq.end() - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result>, D::Error> - where - D: Deserializer<'de>, - { - let base64_strings: Vec = Deserialize::deserialize(deserializer)?; - base64_strings - .into_iter() - .map(|s| { - general_purpose::STANDARD - .decode(&s) - .map_err(serde::de::Error::custom) - }) - .collect() - } - } - - pub fn serialize(bytes: &[u8], serializer: S) -> Result - where - S: Serializer, - { - let base64_string = general_purpose::STANDARD.encode(bytes); - serializer.serialize_str(&base64_string) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let base64_string: String = Deserialize::deserialize(deserializer)?; - general_purpose::STANDARD - .decode(&base64_string) - .map_err(serde::de::Error::custom) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct HelloRequest; - -#[derive(Serialize, Deserialize, Debug)] -pub struct RegisterAccountRequest { - pub account_id: [u8; 32], -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct SendTxRequest { - #[serde(with = "base64_deser")] - pub transaction: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetBlockDataRequest { - pub block_id: u64, -} - -/// Get a range of blocks from `start_block_id` to `end_block_id` (inclusive). -#[derive(Serialize, Deserialize, Debug)] -pub struct GetBlockRangeDataRequest { - pub start_block_id: u64, - pub end_block_id: u64, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetGenesisIdRequest; - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetLastBlockRequest; - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetInitialTestnetAccountsRequest; - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountBalanceRequest { - pub account_id: AccountId, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetTransactionByHashRequest { - pub hash: HashType, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountsNoncesRequest { - pub account_ids: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountRequest { - pub account_id: AccountId, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetProofForCommitmentRequest { - pub commitment: nssa_core::Commitment, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetProgramIdsRequest; - -parse_request!(HelloRequest); -parse_request!(RegisterAccountRequest); -parse_request!(SendTxRequest); -parse_request!(GetBlockDataRequest); -parse_request!(GetBlockRangeDataRequest); -parse_request!(GetGenesisIdRequest); -parse_request!(GetLastBlockRequest); -parse_request!(GetInitialTestnetAccountsRequest); -parse_request!(GetAccountBalanceRequest); -parse_request!(GetTransactionByHashRequest); -parse_request!(GetAccountsNoncesRequest); -parse_request!(GetProofForCommitmentRequest); -parse_request!(GetAccountRequest); -parse_request!(GetProgramIdsRequest); - -#[derive(Serialize, Deserialize, Debug)] -pub struct HelloResponse { - pub greeting: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct RegisterAccountResponse { - pub status: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct SendTxResponse { - pub status: String, - pub tx_hash: HashType, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetBlockDataResponse { - #[serde(with = "base64_deser")] - pub block: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetBlockRangeDataResponse { - #[serde(with = "base64_deser::vec")] - pub blocks: Vec>, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetGenesisIdResponse { - pub genesis_id: u64, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetLastBlockResponse { - pub last_block: u64, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountBalanceResponse { - pub balance: u128, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountsNoncesResponse { - pub nonces: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetTransactionByHashResponse { - pub transaction: Option, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountResponse { - pub account: nssa::Account, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetProofForCommitmentResponse { - pub membership_proof: Option, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetProgramIdsResponse { - pub program_ids: HashMap, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct GetInitialTestnetAccountsResponse { - /// Hex encoded account id. - pub account_id: String, - pub balance: u64, -} diff --git a/common/src/sequencer_client.rs b/common/src/sequencer_client.rs deleted file mode 100644 index d52e4585..00000000 --- a/common/src/sequencer_client.rs +++ /dev/null @@ -1,361 +0,0 @@ -use std::{collections::HashMap, ops::RangeInclusive}; - -use anyhow::Result; -use nssa::AccountId; -use nssa_core::program::ProgramId; -use reqwest::Client; -use serde::Deserialize; -use serde_json::Value; -use url::Url; - -use super::rpc_primitives::requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse, - GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest, -}; -use crate::{ - HashType, - config::BasicAuth, - error::{SequencerClientError, SequencerRpcError}, - rpc_primitives::{ - self, - requests::{ - GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, - GetAccountsNoncesResponse, GetBlockRangeDataRequest, GetBlockRangeDataResponse, - GetInitialTestnetAccountsResponse, GetLastBlockRequest, GetLastBlockResponse, - GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest, - GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, SendTxRequest, SendTxResponse, - }, - }, - transaction::NSSATransaction, -}; - -#[derive(Debug, Clone, Deserialize)] -struct SequencerRpcResponse { - #[serde(rename = "jsonrpc")] - _jsonrpc: String, - result: serde_json::Value, - #[serde(rename = "id")] - _id: u64, -} - -#[derive(Clone)] -pub struct SequencerClient { - pub client: reqwest::Client, - pub sequencer_addr: Url, - pub basic_auth: Option, -} - -impl SequencerClient { - pub fn new(sequencer_addr: Url) -> Result { - Self::new_with_auth(sequencer_addr, None) - } - - pub fn new_with_auth(sequencer_addr: Url, basic_auth: Option) -> Result { - Ok(Self { - client: Client::builder() - // Add more fields if needed - .timeout(std::time::Duration::from_secs(60)) - // Should be kept in sync with server keep-alive settings - .pool_idle_timeout(std::time::Duration::from_secs(5)) - .build()?, - sequencer_addr, - basic_auth, - }) - } - - pub async fn call_method_with_payload( - &self, - method: &str, - payload: Value, - ) -> Result { - let request = - rpc_primitives::message::Request::from_payload_version_2_0(method.to_owned(), payload); - - log::debug!( - "Calling method {method} with payload {request:?} to sequencer at {}", - self.sequencer_addr - ); - - let strategy = tokio_retry::strategy::FixedInterval::from_millis(10000).take(60); - - let response_vall = tokio_retry::Retry::spawn(strategy, || async { - let mut call_builder = self.client.post(self.sequencer_addr.clone()); - - if let Some(BasicAuth { username, password }) = &self.basic_auth { - call_builder = call_builder.basic_auth(username, password.as_deref()); - } - - let call_res_res = call_builder.json(&request).send().await; - - match call_res_res { - Err(err) => Err(err), - Ok(call_res) => call_res.json::().await, - } - }) - .await?; - - if let Ok(response) = serde_json::from_value::(response_vall.clone()) - { - Ok(response.result) - } else { - let err_resp = serde_json::from_value::(response_vall)?; - - Err(err_resp.into()) - } - } - - /// Get block data at `block_id` from sequencer. - pub async fn get_block( - &self, - block_id: u64, - ) -> Result { - let block_req = GetBlockDataRequest { block_id }; - - let req = serde_json::to_value(block_req)?; - - let resp = self.call_method_with_payload("get_block", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - pub async fn get_block_range( - &self, - range: RangeInclusive, - ) -> Result { - let block_req = GetBlockRangeDataRequest { - start_block_id: *range.start(), - end_block_id: *range.end(), - }; - - let req = serde_json::to_value(block_req)?; - - let resp = self - .call_method_with_payload("get_block_range", req) - .await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get last known `blokc_id` from sequencer. - pub async fn get_last_block(&self) -> Result { - let block_req = GetLastBlockRequest {}; - - let req = serde_json::to_value(block_req)?; - - let resp = self.call_method_with_payload("get_last_block", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get account public balance for `account_id`. `account_id` must be a valid hex-string for 32 - /// bytes. - pub async fn get_account_balance( - &self, - account_id: AccountId, - ) -> Result { - let block_req = GetAccountBalanceRequest { account_id }; - - let req = serde_json::to_value(block_req)?; - - let resp = self - .call_method_with_payload("get_account_balance", req) - .await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get accounts nonces for `account_ids`. `account_ids` must be a list of valid hex-strings for - /// 32 bytes. - pub async fn get_accounts_nonces( - &self, - account_ids: Vec, - ) -> Result { - let block_req = GetAccountsNoncesRequest { account_ids }; - - let req = serde_json::to_value(block_req)?; - - let resp = self - .call_method_with_payload("get_accounts_nonces", req) - .await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - pub async fn get_account( - &self, - account_id: AccountId, - ) -> Result { - let block_req = GetAccountRequest { account_id }; - - let req = serde_json::to_value(block_req)?; - - let resp = self.call_method_with_payload("get_account", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get transaction details for `hash`. - pub async fn get_transaction_by_hash( - &self, - hash: HashType, - ) -> Result { - let block_req = GetTransactionByHashRequest { hash }; - - let req = serde_json::to_value(block_req)?; - - let resp = self - .call_method_with_payload("get_transaction_by_hash", req) - .await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Send transaction to sequencer. - pub async fn send_tx_public( - &self, - transaction: nssa::PublicTransaction, - ) -> Result { - let transaction = NSSATransaction::Public(transaction); - - let tx_req = SendTxRequest { - transaction: borsh::to_vec(&transaction).unwrap(), - }; - - let req = serde_json::to_value(tx_req)?; - - let resp = self.call_method_with_payload("send_tx", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Send transaction to sequencer. - pub async fn send_tx_private( - &self, - transaction: nssa::PrivacyPreservingTransaction, - ) -> Result { - let transaction = NSSATransaction::PrivacyPreserving(transaction); - - let tx_req = SendTxRequest { - transaction: borsh::to_vec(&transaction).unwrap(), - }; - - let req = serde_json::to_value(tx_req)?; - - let resp = self.call_method_with_payload("send_tx", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get genesis id from sequencer. - pub async fn get_genesis_id(&self) -> Result { - let genesis_req = GetGenesisIdRequest {}; - - let req = serde_json::to_value(genesis_req).unwrap(); - - let resp = self - .call_method_with_payload("get_genesis", req) - .await - .unwrap(); - - let resp_deser = serde_json::from_value(resp).unwrap(); - - Ok(resp_deser) - } - - /// Get initial testnet accounts from sequencer. - pub async fn get_initial_testnet_accounts( - &self, - ) -> Result, SequencerClientError> { - let acc_req = GetInitialTestnetAccountsRequest {}; - - let req = serde_json::to_value(acc_req).unwrap(); - - let resp = self - .call_method_with_payload("get_initial_testnet_accounts", req) - .await - .unwrap(); - - let resp_deser = serde_json::from_value(resp).unwrap(); - - Ok(resp_deser) - } - - /// Get proof for commitment. - pub async fn get_proof_for_commitment( - &self, - commitment: nssa_core::Commitment, - ) -> Result, SequencerClientError> { - let acc_req = GetProofForCommitmentRequest { commitment }; - - let req = serde_json::to_value(acc_req).unwrap(); - - let resp = self - .call_method_with_payload("get_proof_for_commitment", req) - .await - .unwrap(); - - let resp_deser = serde_json::from_value::(resp) - .unwrap() - .membership_proof; - - Ok(resp_deser) - } - - pub async fn send_tx_program( - &self, - transaction: nssa::ProgramDeploymentTransaction, - ) -> Result { - let transaction = NSSATransaction::ProgramDeployment(transaction); - - let tx_req = SendTxRequest { - transaction: borsh::to_vec(&transaction).unwrap(), - }; - - let req = serde_json::to_value(tx_req)?; - - let resp = self.call_method_with_payload("send_tx", req).await?; - - let resp_deser = serde_json::from_value(resp)?; - - Ok(resp_deser) - } - - /// Get Ids of the programs used by the node. - pub async fn get_program_ids( - &self, - ) -> Result, SequencerClientError> { - let acc_req = GetProgramIdsRequest {}; - - let req = serde_json::to_value(acc_req).unwrap(); - - let resp = self - .call_method_with_payload("get_program_ids", req) - .await - .unwrap(); - - let resp_deser = serde_json::from_value::(resp) - .unwrap() - .program_ids; - - Ok(resp_deser) - } -} diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 8fdc2074..e11b91c3 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::HashType; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub enum NSSATransaction { Public(nssa::PublicTransaction), PrivacyPreserving(nssa::PrivacyPreservingTransaction), @@ -87,7 +87,7 @@ impl From for NSSATransaction { } #[derive( - Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize, + Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize, )] pub enum TxKind { Public, diff --git a/indexer/service/Cargo.toml b/indexer/service/Cargo.toml index 911121fd..a07a2285 100644 --- a/indexer/service/Cargo.toml +++ b/indexer/service/Cargo.toml @@ -21,7 +21,6 @@ log.workspace = true jsonrpsee.workspace = true serde_json.workspace = true futures.workspace = true -async-trait = "0.1.89" arc-swap = "1.8.1" [features] diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index 499baa4c..dd01e28a 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -359,12 +359,16 @@ impl From for nssa::program_deployment_transaction::Me // WitnessSet conversions // ============================================================================ -impl TryFrom for WitnessSet { - type Error = (); - - fn try_from(_value: nssa::public_transaction::WitnessSet) -> Result { - // Public transaction witness sets don't have proofs, so we can't convert them directly - Err(()) +impl From for WitnessSet { + fn from(value: nssa::public_transaction::WitnessSet) -> Self { + Self { + signatures_and_public_keys: value + .signatures_and_public_keys() + .iter() + .map(|(sig, pk)| (sig.clone().into(), pk.clone().into())) + .collect(), + proof: None, + } } } @@ -376,7 +380,7 @@ impl From for Wit .into_iter() .map(|(sig, pk)| (sig.into(), pk.into())) .collect(), - proof: proof.into(), + proof: Some(proof.into()), } } } @@ -396,7 +400,9 @@ impl TryFrom for nssa::privacy_preserving_transaction::witness_set:: Ok(Self::from_raw_parts( signatures_and_public_keys, - proof.into(), + proof + .map(Into::into) + .ok_or_else(|| nssa::error::NssaError::InvalidInput("Missing proof".to_string()))?, )) } } @@ -416,14 +422,7 @@ impl From for PublicTransaction { Self { hash, message: message.into(), - witness_set: WitnessSet { - signatures_and_public_keys: witness_set - .signatures_and_public_keys() - .iter() - .map(|(sig, pk)| (sig.clone().into(), pk.clone().into())) - .collect(), - proof: Proof(vec![]), // Public transactions don't have proofs - }, + witness_set: witness_set.into(), } } } diff --git a/indexer/service/protocol/src/lib.rs b/indexer/service/protocol/src/lib.rs index 98ef5650..d61f62a6 100644 --- a/indexer/service/protocol/src/lib.rs +++ b/indexer/service/protocol/src/lib.rs @@ -240,7 +240,7 @@ pub struct PrivacyPreservingMessage { #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub struct WitnessSet { pub signatures_and_public_keys: Vec<(Signature, PublicKey)>, - pub proof: Proof, + pub proof: Option, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] diff --git a/indexer/service/src/lib.rs b/indexer/service/src/lib.rs index 1f87e929..48e4f876 100644 --- a/indexer/service/src/lib.rs +++ b/indexer/service/src/lib.rs @@ -13,6 +13,7 @@ pub mod mock_service; pub struct IndexerHandle { addr: SocketAddr, + /// Option because of `Drop` which forbids to simply move out of `self` in `stopped()`. server_handle: Option, } impl IndexerHandle { @@ -28,6 +29,7 @@ impl IndexerHandle { self.addr } + /// Wait for all Indexer tasks to stop. pub async fn stopped(mut self) { let handle = self .server_handle @@ -37,15 +39,11 @@ impl IndexerHandle { handle.stopped().await; } - #[expect( - clippy::redundant_closure_for_method_calls, - reason = "Clippy suggested path jsonrpsee::jsonrpsee_server::ServerHandle is not accessible" - )] #[must_use] pub fn is_stopped(&self) -> bool { self.server_handle .as_ref() - .is_none_or(|handle| handle.is_stopped()) + .is_none_or(ServerHandle::is_stopped) } } diff --git a/indexer/service/src/mock_service.rs b/indexer/service/src/mock_service.rs index bc131740..b52123bc 100644 --- a/indexer/service/src/mock_service.rs +++ b/indexer/service/src/mock_service.rs @@ -15,7 +15,10 @@ use indexer_service_protocol::{ ProgramDeploymentTransaction, ProgramId, PublicMessage, PublicTransaction, Signature, Transaction, WitnessSet, }; -use jsonrpsee::{core::SubscriptionResult, types::ErrorObjectOwned}; +use jsonrpsee::{ + core::{SubscriptionResult, async_trait}, + types::ErrorObjectOwned, +}; /// A mock implementation of the `IndexerService` RPC for testing purposes. pub struct MockIndexerService { @@ -92,7 +95,7 @@ impl MockIndexerService { }, witness_set: WitnessSet { signatures_and_public_keys: vec![], - proof: indexer_service_protocol::Proof(vec![0; 32]), + proof: None, }, }), // PrivacyPreserving transactions @@ -124,7 +127,7 @@ impl MockIndexerService { }, witness_set: WitnessSet { signatures_and_public_keys: vec![], - proof: indexer_service_protocol::Proof(vec![0; 32]), + proof: Some(indexer_service_protocol::Proof(vec![0; 32])), }, }), // ProgramDeployment transactions (rare) @@ -171,7 +174,7 @@ impl MockIndexerService { } } -#[async_trait::async_trait] +#[async_trait] impl indexer_service_rpc::RpcServer for MockIndexerService { async fn subscribe_to_finalized_blocks( &self, diff --git a/indexer/service/src/service.rs b/indexer/service/src/service.rs index 256ef33d..049d4a0c 100644 --- a/indexer/service/src/service.rs +++ b/indexer/service/src/service.rs @@ -7,7 +7,7 @@ use indexer_core::{IndexerCore, config::IndexerConfig}; use indexer_service_protocol::{Account, AccountId, Block, BlockId, HashType, Transaction}; use jsonrpsee::{ SubscriptionSink, - core::{Serialize, SubscriptionResult}, + core::{Serialize, SubscriptionResult, async_trait}, types::{ErrorCode, ErrorObject, ErrorObjectOwned}, }; use log::{debug, error, info, warn}; @@ -30,7 +30,7 @@ impl IndexerService { } } -#[async_trait::async_trait] +#[async_trait] impl indexer_service_rpc::RpcServer for IndexerService { async fn subscribe_to_finalized_blocks( &self, diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index b50f189b..89dae607 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -14,10 +14,12 @@ anyhow.workspace = true thiserror.workspace = true risc0-zkvm.workspace = true serde.workspace = true +serde_with.workspace = true sha2.workspace = true rand.workspace = true borsh.workspace = true hex.workspace = true +base64.workspace = true secp256k1 = "0.31.1" risc0-binfmt = "3.0.2" log.workspace = true diff --git a/nssa/src/base64.rs b/nssa/src/base64.rs new file mode 100644 index 00000000..cc782e9c --- /dev/null +++ b/nssa/src/base64.rs @@ -0,0 +1,14 @@ +use base64::prelude::{BASE64_STANDARD, Engine as _}; +use serde::{Deserialize as _, Deserializer, Serialize as _, Serializer}; + +pub fn serialize(v: &[u8], s: S) -> Result { + let base64 = BASE64_STANDARD.encode(v); + String::serialize(&base64, s) +} + +pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { + let base64 = String::deserialize(d)?; + BASE64_STANDARD + .decode(base64.as_bytes()) + .map_err(serde::de::Error::custom) +} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index bc7cf121..973433ee 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -18,6 +18,7 @@ pub use public_transaction::PublicTransaction; pub use signature::{PrivateKey, PublicKey, Signature}; pub use state::V02State; +mod base64; pub mod encoding; pub mod error; mod merkle_tree; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 2ab141a3..9f0bf83f 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -8,6 +8,7 @@ use nssa_core::{ program::{ChainedCall, InstructionData, ProgramId, ProgramOutput}, }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; +use serde::{Deserialize, Serialize}; use crate::{ error::NssaError, @@ -17,8 +18,8 @@ use crate::{ }; /// Proof of the privacy preserving execution circuit. -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] -pub struct Proof(pub(crate) Vec); +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +pub struct Proof(#[serde(with = "crate::base64")] pub(crate) Vec); impl Proof { #[must_use] diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index 4b93e820..a2d6812e 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -4,13 +4,14 @@ use nssa_core::{ account::{Account, Nonce}, encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey}, }; +use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256}; use crate::{AccountId, error::NssaError}; pub type ViewTag = u8; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct EncryptedAccountData { pub ciphertext: Ciphertext, pub epk: EphemeralPublicKey, @@ -44,7 +45,7 @@ impl EncryptedAccountData { } } -#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct Message { pub public_account_ids: Vec, pub nonces: Vec, diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 2b268c07..012b3bd5 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -8,6 +8,7 @@ use nssa_core::{ Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput, account::{Account, AccountWithMetadata}, }; +use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use super::{message::Message, witness_set::WitnessSet}; @@ -17,7 +18,7 @@ use crate::{ privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData}, }; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct PrivacyPreservingTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/nssa/src/privacy_preserving_transaction/witness_set.rs index 373bbc9c..4f570a22 100644 --- a/nssa/src/privacy_preserving_transaction/witness_set.rs +++ b/nssa/src/privacy_preserving_transaction/witness_set.rs @@ -1,11 +1,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; use crate::{ PrivateKey, PublicKey, Signature, privacy_preserving_transaction::{circuit::Proof, message::Message}, }; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, pub(crate) proof: Proof, diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index a51e4149..d4758ae2 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -1,7 +1,9 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct Message { + #[serde(with = "crate::base64")] pub(crate) bytecode: Vec, } diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/nssa/src/program_deployment_transaction/transaction.rs index 1e53388d..939d81be 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/nssa/src/program_deployment_transaction/transaction.rs @@ -1,12 +1,13 @@ use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::account::AccountId; +use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message, }; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct ProgramDeploymentTransaction { pub message: Message, } diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index d4838b87..e3651ba3 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -3,11 +3,11 @@ use nssa_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::{AccountId, error::NssaError, program::Program}; -#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct Message { pub program_id: ProgramId, pub account_ids: Vec, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 8c84d83c..00d29a05 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -6,6 +6,7 @@ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata}, program::{ChainedCall, DEFAULT_PROGRAM_ID, validate_execution}, }; +use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ @@ -15,7 +16,7 @@ use crate::{ state::MAX_NUMBER_CHAINED_CALLS, }; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct PublicTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index d6b32891..e796fbfe 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -1,8 +1,9 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message}; -#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, } diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 63377f15..f0e5a863 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -1,22 +1,43 @@ +use std::str::FromStr; + use borsh::{BorshDeserialize, BorshSerialize}; pub use private_key::PrivateKey; pub use public_key::PublicKey; use rand::{RngCore as _, rngs::OsRng}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; mod private_key; mod public_key; -#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[derive( + Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr, BorshSerialize, BorshDeserialize, +)] pub struct Signature { pub value: [u8; 64], } impl std::fmt::Debug for Signature { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +impl std::fmt::Display for Signature { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex::encode(self.value)) } } +impl FromStr for Signature { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + let mut bytes = [0_u8; 64]; + hex::decode_to_slice(s, &mut bytes)?; + Ok(Self { value: bytes }) + } +} + impl Signature { #[must_use] pub fn new(key: &PrivateKey, message: &[u8]) -> Self { diff --git a/nssa/src/signature/private_key.rs b/nssa/src/signature/private_key.rs index d8ece0e0..e73e0e4f 100644 --- a/nssa/src/signature/private_key.rs +++ b/nssa/src/signature/private_key.rs @@ -1,13 +1,37 @@ +use std::str::FromStr; + use rand::{Rng as _, rngs::OsRng}; -use serde::{Deserialize, Serialize}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; use crate::error::NssaError; // TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons // TODO: Implement Zeroize -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, SerializeDisplay, DeserializeFromStr, PartialEq, Eq)] pub struct PrivateKey([u8; 32]); +impl std::fmt::Debug for PrivateKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +impl std::fmt::Display for PrivateKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(self.0)) + } +} + +impl FromStr for PrivateKey { + type Err = NssaError; + + fn from_str(s: &str) -> Result { + let mut bytes = [0_u8; 32]; + hex::decode_to_slice(s, &mut bytes).map_err(|_err| NssaError::InvalidPrivateKey)?; + Self::try_new(bytes) + } +} + impl PrivateKey { #[must_use] pub fn new_os_random() -> Self { diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index 9cdac761..ee0f5dbc 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -1,19 +1,38 @@ +use std::str::FromStr; + use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::account::AccountId; -use serde::{Deserialize, Serialize}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; use sha2::{Digest as _, Sha256}; use crate::{PrivateKey, error::NssaError}; -#[derive(Clone, PartialEq, Eq, BorshSerialize, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, SerializeDisplay, DeserializeFromStr)] pub struct PublicKey([u8; 32]); impl std::fmt::Debug for PublicKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +impl std::fmt::Display for PublicKey { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex::encode(self.0)) } } +impl FromStr for PublicKey { + type Err = NssaError; + + fn from_str(s: &str) -> Result { + let mut bytes = [0_u8; 32]; + hex::decode_to_slice(s, &mut bytes) + .map_err(|_err| NssaError::InvalidPublicKey(secp256k1::Error::InvalidPublicKey))?; + Self::try_new(bytes) + } +} + impl BorshDeserialize for PublicKey { fn deserialize_reader(reader: &mut R) -> std::io::Result { let mut buf = [0_u8; 32]; diff --git a/sequencer/core/src/block_store.rs b/sequencer/core/src/block_store.rs index eb541188..51355f5f 100644 --- a/sequencer/core/src/block_store.rs +++ b/sequencer/core/src/block_store.rs @@ -7,7 +7,7 @@ use common::{ transaction::NSSATransaction, }; use nssa::V02State; -use storage::sequencer::RocksDBIO; +use storage::{error::DbError, sequencer::RocksDBIO}; pub struct SequencerStore { dbio: RocksDBIO, @@ -42,8 +42,8 @@ impl SequencerStore { }) } - pub fn get_block_at_id(&self, id: u64) -> Result { - Ok(self.dbio.get_block(id)?) + pub fn get_block_at_id(&self, id: u64) -> Result { + self.dbio.get_block(id) } pub fn delete_block_at_id(&mut self, block_id: u64) -> Result<()> { diff --git a/sequencer/core/src/config.rs b/sequencer/core/src/config.rs index 097d1391..9dd10680 100644 --- a/sequencer/core/src/config.rs +++ b/sequencer/core/src/config.rs @@ -22,8 +22,6 @@ use url::Url; pub struct SequencerConfig { /// Home dir of sequencer storage. pub home: PathBuf, - /// Override rust log (env var logging level). - pub override_rust_log: Option, /// Genesis id. pub genesis_id: u64, /// If `True`, then adds random sequence of bytes to genesis block. @@ -41,8 +39,6 @@ pub struct SequencerConfig { /// Interval in which pending blocks are retried. #[serde(with = "humantime_serde")] pub retry_pending_blocks_timeout: Duration, - /// Port to listen. - pub port: u16, /// List of initial accounts data. pub initial_accounts: Vec, /// List of initial commitments. diff --git a/sequencer/core/src/lib.rs b/sequencer/core/src/lib.rs index c844c193..7f58faf4 100644 --- a/sequencer/core/src/lib.rs +++ b/sequencer/core/src/lib.rs @@ -27,6 +27,8 @@ pub mod block_store; pub mod config; pub mod indexer_client; +pub use storage::error::DbError; + #[cfg(feature = "mock")] pub mod mock; @@ -394,7 +396,6 @@ mod tests { max_block_size: bytesize::ByteSize::mib(1), mempool_max_size: 10000, block_create_timeout: Duration::from_secs(1), - port: 8080, initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), diff --git a/sequencer/service/Cargo.toml b/sequencer/service/Cargo.toml index 235b4d71..3efb380d 100644 --- a/sequencer/service/Cargo.toml +++ b/sequencer/service/Cargo.toml @@ -9,20 +9,25 @@ workspace = true [dependencies] common.workspace = true +nssa.workspace = true +nssa_core.workspace = true +mempool.workspace = true +borsh.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } -sequencer_rpc.workspace = true +sequencer_service_rpc = { workspace = true, features = ["server"] } indexer_service_rpc = { workspace = true, features = ["client"] } clap = { workspace = true, features = ["derive", "env"] } anyhow.workspace = true env_logger.workspace = true log.workspace = true -actix.workspace = true -actix-web.workspace = true tokio.workspace = true +tokio-util.workspace = true +jsonrpsee.workspace = true futures.workspace = true +bytesize.workspace = true [features] default = [] # Runs the sequencer in standalone mode without depending on Bedrock and Indexer services. -standalone = ["sequencer_core/mock", "sequencer_rpc/standalone"] +standalone = ["sequencer_core/mock"] diff --git a/sequencer/service/rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml index 5c76ba34..1ced7997 100644 --- a/sequencer/service/rpc/Cargo.toml +++ b/sequencer/service/rpc/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sequencer_rpc" +name = "sequencer_service_rpc" version = "0.1.0" edition = "2024" license = { workspace = true } @@ -8,32 +8,14 @@ license = { workspace = true } workspace = true [dependencies] -nssa.workspace = true common.workspace = true -mempool.workspace = true -sequencer_core = { workspace = true } -bedrock_client.workspace = true +nssa.workspace = true +nssa_core.workspace = true -anyhow.workspace = true +jsonrpsee = { workspace = true, features = ["macros"] } serde_json.workspace = true -log.workspace = true -serde.workspace = true -actix-cors.workspace = true -futures.workspace = true -base58.workspace = true -hex.workspace = true -tempfile.workspace = true -base64.workspace = true -itertools.workspace = true -actix-web.workspace = true -tokio.workspace = true -borsh.workspace = true -bytesize.workspace = true - -[dev-dependencies] -sequencer_core = { workspace = true, features = ["mock"] } +schemars.workspace = true [features] -default = [] -# Includes types to run the sequencer in standalone mode -standalone = ["sequencer_core/mock"] +client = ["jsonrpsee/client"] +server = ["jsonrpsee/server"] diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs index 47e4fa75..0ff68bfe 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/sequencer/service/rpc/src/lib.rs @@ -1,55 +1,74 @@ -use std::sync::Arc; +use std::collections::BTreeMap; use common::{ - rpc_primitives::errors::{RpcError, RpcErrorKind}, + HashType, + block::{Block, BlockId}, transaction::NSSATransaction, }; -use mempool::MemPoolHandle; -pub use net_utils::*; -#[cfg(feature = "standalone")] -use sequencer_core::mock::{MockBlockSettlementClient, MockIndexerClient}; -use sequencer_core::{ - SequencerCore, - block_settlement_client::{BlockSettlementClient, BlockSettlementClientTrait}, - indexer_client::{IndexerClient, IndexerClientTrait}, -}; -use serde::Serialize; -use serde_json::Value; -use tokio::sync::Mutex; +use jsonrpsee::proc_macros::rpc; +#[cfg(feature = "server")] +use jsonrpsee::types::ErrorObjectOwned; +use nssa::{Account, AccountId, ProgramId}; +use nssa_core::{Commitment, MembershipProof, account::Nonce}; -use self::types::err_rpc::RpcErr; +#[cfg(all(not(feature = "server"), not(feature = "client")))] +compile_error!("At least one of `server` or `client` features must be enabled."); -pub mod net_utils; -pub mod process; -pub mod types; +#[cfg_attr(all(feature = "server", not(feature = "client")), rpc(server))] +#[cfg_attr(all(feature = "client", not(feature = "server")), rpc(client))] +#[cfg_attr(all(feature = "server", feature = "client"), rpc(server, client))] +pub trait Rpc { + #[method(name = "sendTransaction")] + async fn send_transaction(&self, tx: NSSATransaction) -> Result; -#[cfg(feature = "standalone")] -pub type JsonHandlerWithMockClients = JsonHandler; + // TODO: expand healthcheck response into some kind of report + #[method(name = "checkHealth")] + async fn check_health(&self) -> Result<(), ErrorObjectOwned>; -// ToDo: Add necessary fields -pub struct JsonHandler< - BC: BlockSettlementClientTrait = BlockSettlementClient, - IC: IndexerClientTrait = IndexerClient, -> { - sequencer_state: Arc>>, - mempool_handle: MemPoolHandle, - max_block_size: usize, -} - -fn respond(val: T) -> Result { - Ok(serde_json::to_value(val)?) -} - -#[must_use] -pub fn rpc_error_responce_inverter(err: RpcError) -> RpcError { - let content = err.error_struct.map(|error| match error { - RpcErrorKind::HandlerError(val) | RpcErrorKind::InternalError(val) => val, - RpcErrorKind::RequestValidationError(vall) => serde_json::to_value(vall).unwrap(), - }); - RpcError { - error_struct: None, - code: err.code, - message: err.message, - data: content, - } + // TODO: These functions should be removed after wallet starts using indexer + // for this type of queries. + // + // ============================================================================================= + + #[method(name = "getBlockData")] + async fn get_block_data(&self, block_id: BlockId) -> Result; + + #[method(name = "getBlockRangeData")] + async fn get_block_range_data( + &self, + start_block_id: BlockId, + end_block_id: BlockId, + ) -> Result, ErrorObjectOwned>; + + #[method(name = "getLastBlockId")] + async fn get_last_block_id(&self) -> Result; + + #[method(name = "getAccountBalance")] + async fn get_account_balance(&self, account_id: AccountId) -> Result; + + #[method(name = "getTransactionByHash")] + async fn get_transaction_by_hash( + &self, + hash: HashType, + ) -> Result; + + #[method(name = "getAccountsNonces")] + async fn get_accounts_nonces( + &self, + account_ids: Vec, + ) -> Result, ErrorObjectOwned>; + + #[method(name = "getProofForCommitment")] + async fn get_proof_for_commitment( + &self, + commitment: Commitment, + ) -> Result; + + #[method(name = "getAccount")] + async fn get_account(&self, account_id: AccountId) -> Result; + + #[method(name = "getProgramIds")] + async fn get_program_ids(&self) -> Result, ErrorObjectOwned>; + + // ============================================================================================= } diff --git a/sequencer/service/rpc/src/net_utils.rs b/sequencer/service/rpc/src/net_utils.rs deleted file mode 100644 index e306ec0e..00000000 --- a/sequencer/service/rpc/src/net_utils.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::{io, net::SocketAddr, sync::Arc}; - -use actix_cors::Cors; -use actix_web::{App, Error as HttpError, HttpResponse, HttpServer, http, middleware, web}; -use common::{ - rpc_primitives::{RpcConfig, message::Message}, - transaction::NSSATransaction, -}; -use futures::{Future, FutureExt as _}; -use log::info; -use mempool::MemPoolHandle; -#[cfg(not(feature = "standalone"))] -use sequencer_core::SequencerCore; -#[cfg(feature = "standalone")] -use sequencer_core::SequencerCoreWithMockClients as SequencerCore; -use tokio::sync::Mutex; - -#[cfg(not(feature = "standalone"))] -use super::JsonHandler; -use crate::process::Process; - -pub const SHUTDOWN_TIMEOUT_SECS: u64 = 10; - -pub const NETWORK: &str = "network"; - -#[cfg(feature = "standalone")] -type JsonHandler = super::JsonHandlerWithMockClients; - -pub(crate) fn rpc_handler( - message: web::Json, - handler: web::Data

, -) -> impl Future> { - let response = async move { - let message = handler.process(message.0).await?; - Ok(HttpResponse::Ok().json(&message)) - }; - response.boxed() -} - -fn get_cors(cors_allowed_origins: &[String]) -> Cors { - let mut cors = Cors::permissive(); - if cors_allowed_origins != ["*".to_owned()] { - for origin in cors_allowed_origins { - cors = cors.allowed_origin(origin); - } - } - cors.allowed_methods(vec!["GET", "POST"]) - .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT]) - .allowed_header(http::header::CONTENT_TYPE) - .max_age(3600) -} - -pub async fn new_http_server( - config: RpcConfig, - seuquencer_core: Arc>, - mempool_handle: MemPoolHandle, -) -> io::Result<(actix_web::dev::Server, SocketAddr)> { - let RpcConfig { - addr, - cors_allowed_origins, - limits_config, - } = config; - info!(target:NETWORK, "Starting HTTP server at {addr}"); - let max_block_size = seuquencer_core - .lock() - .await - .sequencer_config() - .max_block_size - .as_u64() - .try_into() - .expect("`max_block_size` is expected to fit into usize"); - let handler = web::Data::new(JsonHandler { - sequencer_state: Arc::clone(&seuquencer_core), - mempool_handle, - max_block_size, - }); - - // HTTP server - let http_server = HttpServer::new(move || { - let json_limit = limits_config - .json_payload_max_size - .as_u64() - .try_into() - .expect("`json_payload_max_size` is expected to fit into usize"); - App::new() - .wrap(get_cors(&cors_allowed_origins)) - .app_data(handler.clone()) - .app_data(web::JsonConfig::default().limit(json_limit)) - .wrap(middleware::Logger::default()) - .service(web::resource("/").route(web::post().to(rpc_handler::))) - }) - .bind(addr)? - .shutdown_timeout(SHUTDOWN_TIMEOUT_SECS) - .disable_signals(); - - let [final_addr] = http_server - .addrs() - .try_into() - .expect("Exactly one address bound is expected for sequencer HTTP server"); - - info!(target:NETWORK, "HTTP server started at {final_addr}"); - - Ok((http_server.run(), final_addr)) -} diff --git a/sequencer/service/rpc/src/process.rs b/sequencer/service/rpc/src/process.rs deleted file mode 100644 index 17c46f03..00000000 --- a/sequencer/service/rpc/src/process.rs +++ /dev/null @@ -1,786 +0,0 @@ -use std::collections::HashMap; - -use actix_web::Error as HttpError; -use base64::{Engine as _, engine::general_purpose}; -use common::{ - block::{AccountInitialData, HashableBlockData}, - rpc_primitives::{ - errors::RpcError, - message::{Message, Request}, - parser::RpcRequest as _, - requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, - GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetBlockDataRequest, GetBlockDataResponse, GetBlockRangeDataRequest, - GetBlockRangeDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, - GetInitialTestnetAccountsRequest, GetLastBlockRequest, GetLastBlockResponse, - GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest, - GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, HelloRequest, HelloResponse, SendTxRequest, - SendTxResponse, - }, - }, - transaction::{NSSATransaction, TransactionMalformationError}, -}; -use itertools::Itertools as _; -use log::warn; -use nssa::{self, program::Program}; -use sequencer_core::{ - block_settlement_client::BlockSettlementClientTrait, indexer_client::IndexerClientTrait, -}; -use serde_json::Value; - -use super::{JsonHandler, respond, types::err_rpc::RpcErr}; - -pub const HELLO: &str = "hello"; -pub const SEND_TX: &str = "send_tx"; -pub const GET_BLOCK: &str = "get_block"; -pub const GET_BLOCK_RANGE: &str = "get_block_range"; -pub const GET_GENESIS: &str = "get_genesis"; -pub const GET_LAST_BLOCK: &str = "get_last_block"; -pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance"; -pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash"; -pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces"; -pub const GET_ACCOUNT: &str = "get_account"; -pub const GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment"; -pub const GET_PROGRAM_IDS: &str = "get_program_ids"; - -pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; - -pub const TRANSACTION_SUBMITTED: &str = "Transaction submitted"; - -pub const GET_INITIAL_TESTNET_ACCOUNTS: &str = "get_initial_testnet_accounts"; - -pub trait Process: Send + Sync + 'static { - fn process(&self, message: Message) -> impl Future> + Send; -} - -impl< - BC: BlockSettlementClientTrait + Send + Sync + 'static, - IC: IndexerClientTrait + Send + Sync + 'static, -> Process for JsonHandler -{ - async fn process(&self, message: Message) -> Result { - let id = message.id(); - if let Message::Request(request) = message { - let message_inner = self - .process_request_internal(request) - .await - .map_err(|e| e.0); - Ok(Message::response(id, message_inner)) - } else { - Ok(Message::error(RpcError::parse_error( - "JSON RPC Request format was expected".to_owned(), - ))) - } - } -} - -impl JsonHandler { - /// Example of request processing. - fn process_temp_hello(request: Request) -> Result { - let _hello_request = HelloRequest::parse(Some(request.params))?; - - let response = HelloResponse { - greeting: HELLO_FROM_SEQUENCER.to_owned(), - }; - - respond(response) - } - - async fn process_send_tx(&self, request: Request) -> Result { - // Check transaction size against block size limit - // Reserve ~200 bytes for block header overhead - const BLOCK_HEADER_OVERHEAD: usize = 200; - - let send_tx_req = SendTxRequest::parse(Some(request.params))?; - let tx = borsh::from_slice::(&send_tx_req.transaction).unwrap(); - - let tx_hash = tx.hash(); - - let tx_size = send_tx_req.transaction.len(); - - let max_tx_size = self.max_block_size.saturating_sub(BLOCK_HEADER_OVERHEAD); - - if tx_size > max_tx_size { - return Err(TransactionMalformationError::TransactionTooLarge { - size: tx_size, - max: max_tx_size, - } - .into()); - } - - let authenticated_tx = tx - .transaction_stateless_check() - .inspect_err(|err| warn!("Error at pre_check {err:#?}"))?; - - // TODO: Do we need a timeout here? It will be usable if we have too many transactions to - // process - self.mempool_handle - .push(authenticated_tx) - .await - .expect("Mempool is closed, this is a bug"); - - let response = SendTxResponse { - status: TRANSACTION_SUBMITTED.to_owned(), - tx_hash, - }; - - respond(response) - } - - async fn process_get_block_data(&self, request: Request) -> Result { - let get_block_req = GetBlockDataRequest::parse(Some(request.params))?; - - let block = { - let state = self.sequencer_state.lock().await; - - state - .block_store() - .get_block_at_id(get_block_req.block_id)? - }; - - let response = GetBlockDataResponse { - block: borsh::to_vec(&HashableBlockData::from(block)).unwrap(), - }; - - respond(response) - } - - async fn process_get_block_range_data(&self, request: Request) -> Result { - let get_block_req = GetBlockRangeDataRequest::parse(Some(request.params))?; - - let blocks = { - let state = self.sequencer_state.lock().await; - (get_block_req.start_block_id..=get_block_req.end_block_id) - .map(|block_id| state.block_store().get_block_at_id(block_id)) - .map_ok(|block| { - borsh::to_vec(&HashableBlockData::from(block)) - .expect("derived BorshSerialize should never fail") - }) - .collect::, _>>()? - }; - - let response = GetBlockRangeDataResponse { blocks }; - - respond(response) - } - - async fn process_get_genesis(&self, request: Request) -> Result { - let _get_genesis_req = GetGenesisIdRequest::parse(Some(request.params))?; - - let genesis_id = { - let state = self.sequencer_state.lock().await; - - state.block_store().genesis_id() - }; - - let response = GetGenesisIdResponse { genesis_id }; - - respond(response) - } - - async fn process_get_last_block(&self, request: Request) -> Result { - let _get_last_block_req = GetLastBlockRequest::parse(Some(request.params))?; - - let last_block = { - let state = self.sequencer_state.lock().await; - - state.chain_height() - }; - - let response = GetLastBlockResponse { last_block }; - - respond(response) - } - - /// Returns the initial accounts for testnet. - /// `ToDo`: Useful only for testnet and needs to be removed later. - async fn get_initial_testnet_accounts(&self, request: Request) -> Result { - let _get_initial_testnet_accounts_request = - GetInitialTestnetAccountsRequest::parse(Some(request.params))?; - - let initial_accounts: Vec = { - let state = self.sequencer_state.lock().await; - - state.sequencer_config().initial_accounts.clone() - }; - - respond(initial_accounts) - } - - /// Returns the balance of the account at the given `account_id`. - /// The `account_id` must be a valid hex string of the correct length. - async fn process_get_account_balance(&self, request: Request) -> Result { - let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?; - let account_id = get_account_req.account_id; - - let balance = { - let state = self.sequencer_state.lock().await; - let account = state.state().get_account_by_id(account_id); - account.balance - }; - - let response = GetAccountBalanceResponse { balance }; - - respond(response) - } - - /// Returns the nonces of the accounts at the given `account_ids`. - /// Each `account_id` must be a valid hex string of the correct length. - async fn process_get_accounts_nonces(&self, request: Request) -> Result { - let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?; - let account_ids = get_account_nonces_req.account_ids; - - let nonces = { - let state = self.sequencer_state.lock().await; - - account_ids - .into_iter() - .map(|account_id| state.state().get_account_by_id(account_id).nonce.0) - .collect() - }; - - let response = GetAccountsNoncesResponse { nonces }; - - respond(response) - } - - /// Returns account struct for given `account_id`. - /// `AccountId` must be a valid hex string of the correct length. - async fn process_get_account(&self, request: Request) -> Result { - let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; - - let account_id = get_account_nonces_req.account_id; - - let account = { - let state = self.sequencer_state.lock().await; - - state.state().get_account_by_id(account_id) - }; - - let response = GetAccountResponse { account }; - - respond(response) - } - - /// Returns the transaction corresponding to the given hash, if it exists in the blockchain. - /// The hash must be a valid hex string of the correct length. - async fn process_get_transaction_by_hash(&self, request: Request) -> Result { - let get_transaction_req = GetTransactionByHashRequest::parse(Some(request.params))?; - let hash = get_transaction_req.hash; - - let transaction = { - let state = self.sequencer_state.lock().await; - state - .block_store() - .get_transaction_by_hash(hash) - .map(|tx| borsh::to_vec(&tx).unwrap()) - }; - let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx)); - let response = GetTransactionByHashResponse { - transaction: base64_encoded, - }; - respond(response) - } - - /// Returns the commitment proof, corresponding to commitment. - async fn process_get_proof_by_commitment(&self, request: Request) -> Result { - let get_proof_req = GetProofForCommitmentRequest::parse(Some(request.params))?; - - let membership_proof = { - let state = self.sequencer_state.lock().await; - state - .state() - .get_proof_for_commitment(&get_proof_req.commitment) - }; - let response = GetProofForCommitmentResponse { membership_proof }; - respond(response) - } - - fn process_get_program_ids(request: Request) -> Result { - let _get_proof_req = GetProgramIdsRequest::parse(Some(request.params))?; - - let mut program_ids = HashMap::new(); - program_ids.insert( - "authenticated_transfer".to_owned(), - Program::authenticated_transfer_program().id(), - ); - program_ids.insert("token".to_owned(), Program::token().id()); - program_ids.insert("pinata".to_owned(), Program::pinata().id()); - program_ids.insert("amm".to_owned(), Program::amm().id()); - program_ids.insert( - "privacy_preserving_circuit".to_owned(), - nssa::PRIVACY_PRESERVING_CIRCUIT_ID, - ); - let response = GetProgramIdsResponse { program_ids }; - respond(response) - } - - pub async fn process_request_internal(&self, request: Request) -> Result { - match request.method.as_ref() { - HELLO => Self::process_temp_hello(request), - SEND_TX => self.process_send_tx(request).await, - GET_BLOCK => self.process_get_block_data(request).await, - GET_BLOCK_RANGE => self.process_get_block_range_data(request).await, - GET_GENESIS => self.process_get_genesis(request).await, - GET_LAST_BLOCK => self.process_get_last_block(request).await, - GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await, - GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await, - GET_ACCOUNTS_NONCES => self.process_get_accounts_nonces(request).await, - GET_ACCOUNT => self.process_get_account(request).await, - GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, - GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await, - GET_PROGRAM_IDS => Self::process_get_program_ids(request), - _ => Err(RpcErr(RpcError::method_not_found(request.method))), - } - } -} - -#[cfg(test)] -mod tests { - use std::{str::FromStr as _, sync::Arc, time::Duration}; - - use base58::ToBase58 as _; - use base64::{Engine as _, engine::general_purpose}; - use bedrock_client::BackoffConfig; - use common::{ - block::AccountInitialData, config::BasicAuth, test_utils::sequencer_sign_key_for_testing, - transaction::NSSATransaction, - }; - use nssa::AccountId; - use sequencer_core::{ - config::{BedrockConfig, SequencerConfig}, - mock::{MockBlockSettlementClient, MockIndexerClient, SequencerCoreWithMockClients}, - }; - use serde_json::Value; - use tempfile::tempdir; - use tokio::sync::Mutex; - - use crate::rpc_handler; - - type JsonHandlerWithMockClients = - crate::JsonHandler; - - fn sequencer_config_for_tests() -> SequencerConfig { - let tempdir = tempdir().unwrap(); - let home = tempdir.path().to_path_buf(); - let acc1_id: Vec = vec![ - 148, 179, 206, 253, 199, 51, 82, 86, 232, 2, 152, 122, 80, 243, 54, 207, 237, 112, 83, - 153, 44, 59, 204, 49, 128, 84, 160, 227, 216, 149, 97, 102, - ]; - - let acc2_id: Vec = vec![ - 30, 145, 107, 3, 207, 73, 192, 230, 160, 63, 238, 207, 18, 69, 54, 216, 103, 244, 92, - 94, 124, 248, 42, 16, 141, 19, 119, 18, 14, 226, 140, 204, - ]; - - let initial_acc1 = AccountInitialData { - account_id: AccountId::from_str(&acc1_id.to_base58()).unwrap(), - balance: 10000, - }; - - let initial_acc2 = AccountInitialData { - account_id: AccountId::from_str(&acc2_id.to_base58()).unwrap(), - balance: 20000, - }; - - let initial_accounts = vec![initial_acc1, initial_acc2]; - - SequencerConfig { - home, - override_rust_log: Some("info".to_owned()), - genesis_id: 1, - is_genesis_random: false, - max_num_tx_in_block: 10, - max_block_size: bytesize::ByteSize::mib(1), - mempool_max_size: 1000, - block_create_timeout: Duration::from_secs(1), - port: 8080, - initial_accounts, - initial_commitments: vec![], - signing_key: *sequencer_sign_key_for_testing().value(), - retry_pending_blocks_timeout: Duration::from_secs(60 * 4), - bedrock_config: BedrockConfig { - backoff: BackoffConfig { - start_delay: Duration::from_millis(100), - max_retries: 5, - }, - channel_id: [42; 32].into(), - node_url: "http://localhost:8080".parse().unwrap(), - auth: Some(BasicAuth { - username: "user".to_owned(), - password: None, - }), - }, - indexer_rpc_url: "ws://localhost:8779".parse().unwrap(), - } - } - - async fn components_for_tests() -> ( - JsonHandlerWithMockClients, - Vec, - NSSATransaction, - ) { - let config = sequencer_config_for_tests(); - - let (mut sequencer_core, mempool_handle) = - SequencerCoreWithMockClients::start_from_config(config).await; - let initial_accounts = sequencer_core.sequencer_config().initial_accounts.clone(); - - let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); - let balance_to_move = 10; - let tx = common::test_utils::create_transaction_native_token_transfer( - AccountId::from_str( - &[ - 148, 179, 206, 253, 199, 51, 82, 86, 232, 2, 152, 122, 80, 243, 54, 207, 237, - 112, 83, 153, 44, 59, 204, 49, 128, 84, 160, 227, 216, 149, 97, 102, - ] - .to_base58(), - ) - .unwrap(), - 0, - AccountId::from_str(&[2; 32].to_base58()).unwrap(), - balance_to_move, - &signing_key, - ); - - mempool_handle - .push(tx.clone()) - .await - .expect("Mempool is closed, this is a bug"); - - sequencer_core - .produce_new_block_with_mempool_transactions() - .unwrap(); - - let max_block_size = - usize::try_from(sequencer_core.sequencer_config().max_block_size.as_u64()) - .expect("`max_block_size` is expected to fit in usize"); - let sequencer_core = Arc::new(Mutex::new(sequencer_core)); - - ( - JsonHandlerWithMockClients { - sequencer_state: sequencer_core, - mempool_handle, - max_block_size, - }, - initial_accounts, - tx, - ) - } - - async fn call_rpc_handler_with_json( - handler: JsonHandlerWithMockClients, - request_json: Value, - ) -> Value { - use actix_web::{App, test, web}; - - let app = test::init_service(App::new().app_data(web::Data::new(handler)).route( - "/", - web::post().to(rpc_handler::), - )) - .await; - - let req = test::TestRequest::post() - .uri("/") - .set_json(request_json) - .to_request(); - - let resp = test::call_service(&app, req).await; - let body = test::read_body(resp).await; - - serde_json::from_slice(&body).unwrap() - } - - #[actix_web::test] - async fn get_account_balance_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_account_balance", - "params": { "account_id": "11".repeat(16) }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "balance": 0 - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_account_balance_for_invalid_base58() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_account_balance", - "params": { "account_id": "not_a_valid_base58" }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "cause": { - "info": { - "error_message": "Failed parsing args: invalid base58: InvalidBase58Character('_', 3)" - }, - "name": "PARSE_ERROR" - }, - "code": -32700, - "data": "Failed parsing args: invalid base58: InvalidBase58Character('_', 3)", - "message": "Parse error", - "name": "REQUEST_VALIDATION_ERROR" - }, - }); - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_account_balance_for_invalid_length() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_account_balance", - "params": { "account_id": "cafecafe" }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "cause": { - "info": { - "error_message": "Failed parsing args: invalid length: expected 32 bytes, got 6" - }, - "name": "PARSE_ERROR" - }, - "code": -32700, - "data": "Failed parsing args: invalid length: expected 32 bytes, got 6", - "message": "Parse error", - "name": "REQUEST_VALIDATION_ERROR" - }, - }); - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_account_balance_for_existing_account() { - let (json_handler, initial_accounts, _) = components_for_tests().await; - - let acc1_id = initial_accounts[0].account_id; - - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_account_balance", - "params": { "account_id": acc1_id }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "balance": 10000 - 10 - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_accounts_nonces_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_accounts_nonces", - "params": { "account_ids": ["11".repeat(16)] }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "nonces": [ 0 ] - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_accounts_nonces_for_existent_account() { - let (json_handler, initial_accounts, _) = components_for_tests().await; - - let acc1_id = initial_accounts[0].account_id; - let acc2_id = initial_accounts[1].account_id; - - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_accounts_nonces", - "params": { "account_ids": [acc1_id, acc2_id] }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "nonces": [ 1, 0 ] - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_account_data_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_account", - "params": { "account_id": "11".repeat(16) }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "account": { - "balance": 0, - "nonce": 0, - "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], - "data": [], - } - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_transaction_by_hash_for_non_existent_hash() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_transaction_by_hash", - "params": { "hash": "cafe".repeat(16) }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "transaction": null - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_transaction_by_hash_for_invalid_hex() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_transaction_by_hash", - "params": { "hash": "not_a_valid_hex" }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "cause": { - "info": { - "error_message": "Failed parsing args: Odd number of digits" - }, - "name": "PARSE_ERROR" - }, - "code": -32700, - "data": "Failed parsing args: Odd number of digits", - "message": "Parse error", - "name": "REQUEST_VALIDATION_ERROR" - }, - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_transaction_by_hash_for_invalid_length() { - let (json_handler, _, _) = components_for_tests().await; - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_transaction_by_hash", - "params": { "hash": "cafecafe" }, - "id": 1 - }); - let expected_response = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "cause": { - "info": { - "error_message": "Failed parsing args: Invalid string length" - }, - "name": "PARSE_ERROR" - }, - "code": -32700, - "data": "Failed parsing args: Invalid string length", - "message": "Parse error", - "name": "REQUEST_VALIDATION_ERROR" - } - }); - - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } - - #[actix_web::test] - async fn get_transaction_by_hash_for_existing_transaction() { - let (json_handler, _, tx) = components_for_tests().await; - let tx_hash_hex = hex::encode(tx.hash()); - let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap()); - - let request = serde_json::json!({ - "jsonrpc": "2.0", - "method": "get_transaction_by_hash", - "params": { "hash": tx_hash_hex}, - "id": 1 - }); - - let expected_response = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "result": { - "transaction": expected_base64_encoded, - } - }); - let response = call_rpc_handler_with_json(json_handler, request).await; - - assert_eq!(response, expected_response); - } -} diff --git a/sequencer/service/rpc/src/types/err_rpc.rs b/sequencer/service/rpc/src/types/err_rpc.rs deleted file mode 100644 index 4cb75606..00000000 --- a/sequencer/service/rpc/src/types/err_rpc.rs +++ /dev/null @@ -1,49 +0,0 @@ -use common::{ - rpc_primitives::errors::{RpcError, RpcParseError}, - transaction::TransactionMalformationError, -}; - -macro_rules! standard_rpc_err_kind { - ($type_name:path) => { - impl RpcErrKind for $type_name { - fn into_rpc_err(self) -> RpcError { - self.into() - } - } - }; -} - -pub struct RpcErr(pub RpcError); - -pub type RpcErrInternal = anyhow::Error; - -pub trait RpcErrKind: 'static { - fn into_rpc_err(self) -> RpcError; -} - -impl From for RpcErr { - fn from(e: T) -> Self { - Self(e.into_rpc_err()) - } -} - -standard_rpc_err_kind!(RpcError); -standard_rpc_err_kind!(RpcParseError); - -impl RpcErrKind for serde_json::Error { - fn into_rpc_err(self) -> RpcError { - RpcError::serialization_error(&self.to_string()) - } -} - -impl RpcErrKind for RpcErrInternal { - fn into_rpc_err(self) -> RpcError { - RpcError::new_internal_error(None, &format!("{self:#?}")) - } -} - -impl RpcErrKind for TransactionMalformationError { - fn into_rpc_err(self) -> RpcError { - RpcError::invalid_params(Some(serde_json::to_value(self).unwrap())) - } -} diff --git a/sequencer/service/rpc/src/types/mod.rs b/sequencer/service/rpc/src/types/mod.rs deleted file mode 100644 index 0b78fea1..00000000 --- a/sequencer/service/rpc/src/types/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod err_rpc; diff --git a/sequencer/service/src/lib.rs b/sequencer/service/src/lib.rs index a17ecbf9..547f58d2 100644 --- a/sequencer/service/src/lib.rs +++ b/sequencer/service/src/lib.rs @@ -1,59 +1,75 @@ -use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; -use actix_web::dev::ServerHandle; -use anyhow::{Context as _, Result}; -use clap::Parser; -use common::rpc_primitives::RpcConfig; -use futures::{FutureExt as _, never::Never}; +use anyhow::{Context as _, Result, anyhow}; +use bytesize::ByteSize; +use common::transaction::NSSATransaction; +use futures::never::Never; +use jsonrpsee::server::ServerHandle; #[cfg(not(feature = "standalone"))] use log::warn; use log::{error, info}; +use mempool::MemPoolHandle; #[cfg(feature = "standalone")] use sequencer_core::SequencerCoreWithMockClients as SequencerCore; -use sequencer_core::config::SequencerConfig; +pub use sequencer_core::config::*; #[cfg(not(feature = "standalone"))] use sequencer_core::{SequencerCore, block_settlement_client::BlockSettlementClientTrait as _}; -use sequencer_rpc::new_http_server; +use sequencer_service_rpc::RpcServer as _; use tokio::{sync::Mutex, task::JoinHandle}; -pub const RUST_LOG: &str = "RUST_LOG"; +pub mod service; -#[derive(Parser, Debug)] -#[clap(version)] -struct Args { - /// Path to configs. - home_dir: PathBuf, -} +const REQUEST_BODY_MAX_SIZE: ByteSize = ByteSize::mib(10); /// Handle to manage the sequencer and its tasks. /// -/// Implements `Drop` to ensure all tasks are aborted and the HTTP server is stopped when dropped. +/// Implements `Drop` to ensure all tasks are aborted and the RPC server is stopped when dropped. pub struct SequencerHandle { addr: SocketAddr, - http_server_handle: ServerHandle, + /// Option because of `Drop` which forbids to simply move out of `self` in `stopped()`. + server_handle: Option, main_loop_handle: JoinHandle>, retry_pending_blocks_loop_handle: JoinHandle>, listen_for_bedrock_blocks_loop_handle: JoinHandle>, } impl SequencerHandle { - /// Runs the sequencer indefinitely, monitoring its tasks. - /// - /// If no error occurs, this function will never return. + fn new( + addr: SocketAddr, + server_handle: ServerHandle, + main_loop_handle: JoinHandle>, + retry_pending_blocks_loop_handle: JoinHandle>, + listen_for_bedrock_blocks_loop_handle: JoinHandle>, + ) -> Self { + Self { + addr, + server_handle: Some(server_handle), + main_loop_handle, + retry_pending_blocks_loop_handle, + listen_for_bedrock_blocks_loop_handle, + } + } + + /// Wait for all Sequencer tasks to stop. #[expect( clippy::integer_division_remainder_used, reason = "Generated by select! macro, can't be easily rewritten to avoid this lint" )] - pub async fn run_forever(&mut self) -> Result { + pub async fn stopped(mut self) -> Result { let Self { addr: _, - http_server_handle: _, + server_handle, main_loop_handle, retry_pending_blocks_loop_handle, listen_for_bedrock_blocks_loop_handle, - } = self; + } = &mut self; + + let server_handle = server_handle.take().expect("Server handle is set"); tokio::select! { + _ = server_handle.stopped() => { + Err(anyhow!("RPC Server stopped")) + } res = main_loop_handle => { res .context("Main loop task panicked")? @@ -89,7 +105,7 @@ impl Drop for SequencerHandle { fn drop(&mut self) { let Self { addr: _, - http_server_handle, + server_handle, main_loop_handle, retry_pending_blocks_loop_handle, listen_for_bedrock_blocks_loop_handle, @@ -99,31 +115,35 @@ impl Drop for SequencerHandle { retry_pending_blocks_loop_handle.abort(); listen_for_bedrock_blocks_loop_handle.abort(); - // Can't wait here as Drop can't be async, but anyway stop signal should be sent - http_server_handle.stop(true).now_or_never(); + let Some(handle) = server_handle else { + return; + }; + + if let Err(err) = handle.stop() { + error!("An error occurred while stopping Sequencer RPC server: {err}"); + } } } -pub async fn startup_sequencer(app_config: SequencerConfig) -> Result { - let block_timeout = app_config.block_create_timeout; - let retry_pending_blocks_timeout = app_config.retry_pending_blocks_timeout; - let port = app_config.port; +pub async fn run(config: SequencerConfig, port: u16) -> Result { + let block_timeout = config.block_create_timeout; + let retry_pending_blocks_timeout = config.retry_pending_blocks_timeout; + let max_block_size = config.max_block_size; - let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(app_config).await; + let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(config).await; info!("Sequencer core set up"); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); - let (http_server, addr) = new_http_server( - RpcConfig::with_port(port), + let (server_handle, addr) = run_server( Arc::clone(&seq_core_wrapped), mempool_handle, + port, + max_block_size.as_u64(), ) .await?; - info!("HTTP server started"); - let http_server_handle = http_server.handle(); - tokio::spawn(http_server); + info!("RPC server started"); #[cfg(not(feature = "standalone"))] { @@ -146,13 +166,42 @@ pub async fn startup_sequencer(app_config: SequencerConfig) -> Result>, + mempool_handle: MemPoolHandle, + port: u16, + max_block_size: u64, +) -> Result<(ServerHandle, SocketAddr)> { + let server = jsonrpsee::server::ServerBuilder::with_config( + jsonrpsee::server::ServerConfigBuilder::new() + .max_request_body_size( + u32::try_from(REQUEST_BODY_MAX_SIZE.as_u64()) + .expect("REQUEST_BODY_MAX_SIZE should be less than u32::MAX"), + ) + .build(), + ) + .build(SocketAddr::from(([0, 0, 0, 0], port))) + .await + .context("Failed to build RPC server")?; + + let addr = server + .local_addr() + .context("Failed to get local address of RPC server")?; + + info!("Starting Sequencer Service RPC server on {addr}"); + + let service = service::SequencerService::new(sequencer, mempool_handle, max_block_size); + let handle = server.start(service.into_rpc()); + Ok((handle, addr)) } async fn main_loop(seq_core: Arc>, block_timeout: Duration) -> Result { @@ -210,7 +259,7 @@ async fn retry_pending_blocks(seq_core: &Arc>) -> Result<() .create_inscribe_tx(block) .context("Failed to create inscribe tx for pending block")?; - debug!(">>>> Create inscribe: {:?}", now.elapsed()); + debug!("Create inscribe: {:?}", now.elapsed()); let now = Instant::now(); if let Err(e) = block_settlement_client @@ -222,7 +271,7 @@ async fn retry_pending_blocks(seq_core: &Arc>) -> Result<() block.header.block_id ); } - debug!(">>>> Post: {:?}", now.elapsed()); + debug!("Post: {:?}", now.elapsed()); } Ok(()) } @@ -287,33 +336,3 @@ async fn retry_pending_blocks_loop( ) -> Result { std::future::pending::>().await } - -pub async fn main_runner() -> Result<()> { - env_logger::init(); - - let args = Args::parse(); - let Args { home_dir } = args; - - let app_config = SequencerConfig::from_path(&home_dir.join("sequencer_config.json"))?; - - if let Some(rust_log) = &app_config.override_rust_log { - info!("RUST_LOG env var set to {rust_log:?}"); - - // SAFETY: there is no other threads running at this point - unsafe { - std::env::set_var(RUST_LOG, rust_log); - } - } - - // ToDo: Add restart on failures - let mut sequencer_handle = startup_sequencer(app_config).await?; - - info!("Sequencer running. Monitoring concurrent tasks..."); - - let Err(err) = sequencer_handle.run_forever().await; - error!("Sequencer failed: {err:#}"); - - info!("Shutting down sequencer..."); - - Ok(()) -} diff --git a/sequencer/service/src/main.rs b/sequencer/service/src/main.rs index d0c51073..326ded70 100644 --- a/sequencer/service/src/main.rs +++ b/sequencer/service/src/main.rs @@ -1,16 +1,60 @@ +use std::path::PathBuf; + use anyhow::Result; -use sequencer_service::main_runner; +use clap::Parser; +use log::{error, info}; +use tokio_util::sync::CancellationToken; -pub const NUM_THREADS: usize = 4; - -// TODO: Why it requires config as a directory and not as a file? -fn main() -> Result<()> { - actix::System::with_tokio_rt(|| { - tokio::runtime::Builder::new_multi_thread() - .worker_threads(NUM_THREADS) - .enable_all() - .build() - .unwrap() - }) - .block_on(main_runner()) +#[derive(Debug, Parser)] +#[clap(version)] +struct Args { + #[clap(name = "config")] + config_path: PathBuf, + #[clap(short, long, default_value = "3040")] + port: u16, +} + +#[tokio::main] +#[expect( + clippy::integer_division_remainder_used, + reason = "Generated by select! macro, can't be easily rewritten to avoid this lint" +)] +async fn main() -> Result<()> { + env_logger::init(); + + let Args { config_path, port } = Args::parse(); + + let cancellation_token = listen_for_shutdown_signal(); + + let config = sequencer_service::SequencerConfig::from_path(&config_path)?; + let sequencer_handle = sequencer_service::run(config, port).await?; + + tokio::select! { + () = cancellation_token.cancelled() => { + info!("Shutting down sequencer..."); + } + Err(err) = sequencer_handle.stopped() => { + error!("Sequencer stopped unexpectedly: {err}"); + } + } + + info!("Sequencer shutdown complete"); + + Ok(()) +} + +fn listen_for_shutdown_signal() -> CancellationToken { + let cancellation_token = CancellationToken::new(); + let cancellation_token_clone = cancellation_token.clone(); + + tokio::spawn(async move { + if let Err(err) = tokio::signal::ctrl_c().await { + error!("Failed to listen for Ctrl-C signal: {err}"); + return; + } + info!("Received Ctrl-C signal"); + cancellation_token_clone.cancel(); + }); + + cancellation_token } diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs new file mode 100644 index 00000000..d1b21f69 --- /dev/null +++ b/sequencer/service/src/service.rs @@ -0,0 +1,202 @@ +use std::{collections::BTreeMap, sync::Arc}; + +use common::{ + HashType, + block::{Block, BlockId}, + transaction::NSSATransaction, +}; +use jsonrpsee::{ + core::async_trait, + types::{ErrorCode, ErrorObjectOwned}, +}; +use log::warn; +use mempool::MemPoolHandle; +use nssa::{self, program::Program}; +use nssa_core::{ + Commitment, MembershipProof, + account::{Account, AccountId, Nonce}, + program::ProgramId, +}; +use sequencer_core::{ + DbError, SequencerCore, block_settlement_client::BlockSettlementClientTrait, + indexer_client::IndexerClientTrait, +}; +use tokio::sync::Mutex; + +pub struct SequencerService { + sequencer: Arc>>, + mempool_handle: MemPoolHandle, + max_block_size: u64, +} + +impl SequencerService { + pub fn new( + sequencer: Arc>>, + mempool_handle: MemPoolHandle, + max_block_size: u64, + ) -> Self { + Self { + sequencer, + mempool_handle, + max_block_size, + } + } +} + +#[async_trait] +impl + sequencer_service_rpc::RpcServer for SequencerService +{ + async fn send_transaction(&self, tx: NSSATransaction) -> Result { + // Reserve ~200 bytes for block header overhead + const BLOCK_HEADER_OVERHEAD: u64 = 200; + + let tx_hash = tx.hash(); + + let tx_size = u64::try_from( + borsh::to_vec(&tx) + .expect("NSSATransaction BorshSerialize should never fail") + .len(), + ) + .expect("Transaction size should fit in u64"); + + let max_tx_size = self.max_block_size.saturating_sub(BLOCK_HEADER_OVERHEAD); + + if tx_size > max_tx_size { + return Err(ErrorObjectOwned::owned( + ErrorCode::InvalidParams.code(), + format!("Transaction too large: size {tx_size}, max {max_tx_size}"), + None::<()>, + )); + } + + let authenticated_tx = tx + .transaction_stateless_check() + .inspect_err(|err| warn!("Error at pre_check {err:#?}")) + .map_err(|err| { + ErrorObjectOwned::owned( + ErrorCode::InvalidParams.code(), + format!("{err:?}"), + None::<()>, + ) + })?; + + self.mempool_handle + .push(authenticated_tx) + .await + .expect("Mempool is closed, this is a bug"); + + Ok(tx_hash) + } + + async fn check_health(&self) -> Result<(), ErrorObjectOwned> { + Ok(()) + } + + async fn get_block_data(&self, block_id: BlockId) -> Result { + let sequencer = self.sequencer.lock().await; + sequencer + .block_store() + .get_block_at_id(block_id) + .map_err(|err| db_error_to_rpc_error(&err)) + } + + async fn get_block_range_data( + &self, + start_block_id: BlockId, + end_block_id: BlockId, + ) -> Result, ErrorObjectOwned> { + let sequencer = self.sequencer.lock().await; + (start_block_id..=end_block_id) + .map(|block_id| sequencer.block_store().get_block_at_id(block_id)) + .collect::, _>>() + .map_err(|err| db_error_to_rpc_error(&err)) + } + + async fn get_last_block_id(&self) -> Result { + let sequencer = self.sequencer.lock().await; + Ok(sequencer.chain_height()) + } + + async fn get_account_balance(&self, account_id: AccountId) -> Result { + let sequencer = self.sequencer.lock().await; + let account = sequencer.state().get_account_by_id(account_id); + Ok(account.balance) + } + + async fn get_transaction_by_hash( + &self, + hash: HashType, + ) -> Result { + let sequencer = self.sequencer.lock().await; + sequencer + .block_store() + .get_transaction_by_hash(hash) + .ok_or_else(|| { + ErrorObjectOwned::owned(NOT_FOUND_ERROR_CODE, "Transaction not found", None::<()>) + }) + } + + async fn get_accounts_nonces( + &self, + account_ids: Vec, + ) -> Result, ErrorObjectOwned> { + let sequencer = self.sequencer.lock().await; + let nonces = account_ids + .into_iter() + .map(|account_id| sequencer.state().get_account_by_id(account_id).nonce) + .collect(); + Ok(nonces) + } + + async fn get_proof_for_commitment( + &self, + commitment: Commitment, + ) -> Result { + let sequencer = self.sequencer.lock().await; + sequencer + .state() + .get_proof_for_commitment(&commitment) + .ok_or_else(|| { + ErrorObjectOwned::owned( + NOT_FOUND_ERROR_CODE, + "Proof for commitment not found", + None::<()>, + ) + }) + } + + async fn get_account(&self, account_id: AccountId) -> Result { + let sequencer = self.sequencer.lock().await; + Ok(sequencer.state().get_account_by_id(account_id)) + } + + async fn get_program_ids(&self) -> Result, ErrorObjectOwned> { + let mut program_ids = BTreeMap::new(); + program_ids.insert( + "authenticated_transfer".to_owned(), + Program::authenticated_transfer_program().id(), + ); + program_ids.insert("token".to_owned(), Program::token().id()); + program_ids.insert("pinata".to_owned(), Program::pinata().id()); + program_ids.insert("amm".to_owned(), Program::amm().id()); + program_ids.insert( + "privacy_preserving_circuit".to_owned(), + nssa::PRIVACY_PRESERVING_CIRCUIT_ID, + ); + Ok(program_ids) + } +} + +const NOT_FOUND_ERROR_CODE: i32 = -31999; + +fn db_error_to_rpc_error(err: &DbError) -> ErrorObjectOwned { + match err { + DbError::NotFound { entity } => ErrorObjectOwned::owned( + NOT_FOUND_ERROR_CODE, + format!("{entity} not found"), + None::<()>, + ), + _ => ErrorObjectOwned::owned(ErrorCode::InternalError.code(), err.to_string(), None::<()>), + } +} diff --git a/storage/src/error.rs b/storage/src/error.rs index 3056e09b..3e0f88ba 100644 --- a/storage/src/error.rs +++ b/storage/src/error.rs @@ -14,6 +14,8 @@ pub enum DbError { }, #[error("Logic Error: {additional_info}")] DbInteractionError { additional_info: String }, + #[error("{entity} not found")] + NotFound { entity: String }, } impl DbError { @@ -39,4 +41,9 @@ impl DbError { additional_info: message, } } + + #[must_use] + pub const fn not_found(entity: String) -> Self { + Self::NotFound { entity } + } } diff --git a/storage/src/indexer.rs b/storage/src/indexer.rs index 534a1c0b..c9b3b358 100644 --- a/storage/src/indexer.rs +++ b/storage/src/indexer.rs @@ -180,9 +180,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "First block not found".to_owned(), - )) + Err(DbError::not_found("First block".to_owned())) } } @@ -209,9 +207,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Last block not found".to_owned(), - )) + Err(DbError::not_found("Last block".to_owned())) } } @@ -286,9 +282,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Last breakpoint id not found".to_owned(), - )) + Err(DbError::not_found("Last breakpoint id".to_owned())) } } @@ -537,9 +531,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Err(DbError::not_found(format!("Block with id {block_id}"))) } } @@ -618,7 +610,7 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None)) } - pub fn get_breakpoint(&self, br_id: u64) -> DbResult { + fn get_breakpoint(&self, br_id: u64) -> DbResult { let cf_br = self.breakpoint_column(); let res = self .db @@ -641,6 +633,8 @@ impl RocksDBIO { ) })?) } else { + // Note: this is not a `DbError::NotFound` case, because we expect that all searched + // breakpoints will be present in db as this is an internal method. Err(DbError::db_interaction_error( "Breakpoint on this id not found".to_owned(), )) @@ -686,9 +680,7 @@ impl RocksDBIO { Ok(breakpoint) } else { - Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Err(DbError::not_found(format!("Block with id {block_id}"))) } } @@ -740,9 +732,7 @@ impl RocksDBIO { DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned())) })?) } else { - Err(DbError::db_interaction_error( - "Block on this hash not found".to_owned(), - )) + Err(DbError::not_found("Block with given hash".to_owned())) } } @@ -766,9 +756,7 @@ impl RocksDBIO { DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned())) })?) } else { - Err(DbError::db_interaction_error( - "Block for this tx hash not found".to_owned(), - )) + Err(DbError::not_found("Block for given tx hash".to_owned())) } } diff --git a/storage/src/sequencer.rs b/storage/src/sequencer.rs index 8d072a52..3d0190d6 100644 --- a/storage/src/sequencer.rs +++ b/storage/src/sequencer.rs @@ -142,9 +142,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "First block not found".to_owned(), - )) + Err(DbError::not_found("First block".to_owned())) } } @@ -171,9 +169,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Last block not found".to_owned(), - )) + Err(DbError::not_found("Last block".to_owned())) } } @@ -399,9 +395,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Latest block meta not found".to_owned(), - )) + Err(DbError::not_found("Latest block meta".to_owned())) } } @@ -465,9 +459,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Err(DbError::not_found(format!("Block with id {block_id}"))) } } @@ -494,9 +486,7 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Err(DbError::not_found("NSSA state".to_owned())) } } @@ -512,9 +502,7 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))? .is_none() { - return Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), - )); + return Err(DbError::not_found(format!("Block with id {block_id}"))); } self.db diff --git a/wallet/configs/debug/wallet_config.json b/wallet/configs/debug/wallet_config.json index 1835c88a..d279c0cb 100644 --- a/wallet/configs/debug/wallet_config.json +++ b/wallet/configs/debug/wallet_config.json @@ -9,79 +9,13 @@ { "Public": { "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", - "pub_sign_key": [ - 127, - 39, - 48, - 152, - 242, - 91, - 113, - 230, - 192, - 5, - 169, - 81, - 159, - 38, - 120, - 218, - 141, - 28, - 127, - 1, - 246, - 162, - 119, - 120, - 226, - 217, - 148, - 138, - 189, - 249, - 1, - 251 - ] + "pub_sign_key": "7f273098f25b71e6c005a9519f2678da8d1c7f01f6a27778e2d9948abdf901fb" } }, { "Public": { "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", - "pub_sign_key": [ - 244, - 52, - 248, - 116, - 23, - 32, - 1, - 69, - 134, - 174, - 67, - 53, - 109, - 42, - 236, - 98, - 87, - 218, - 8, - 98, - 34, - 246, - 4, - 221, - 183, - 93, - 105, - 115, - 59, - 134, - 252, - 76 - ] + "pub_sign_key": "f434f8741720014586ae43356d2aec6257da086222f604ddb75d69733b86fc4c" } }, { diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 79729fc4..d873b357 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -51,6 +51,22 @@ pub enum AccDecodeData { Decode(nssa_core::SharedSecretKey, AccountId), } +#[derive(Debug, thiserror::Error)] +pub enum ExecutionFailureKind { + #[error("Failed to get data from sequencer")] + SequencerError(#[source] anyhow::Error), + #[error("Inputs amounts does not match outputs")] + AmountMismatchError, + #[error("Accounts key not found")] + KeyNotFoundError, + #[error("Sequencer client error: {0:?}")] + SequencerClientError(#[from] SequencerClientError), + #[error("Can not pay for operation")] + InsufficientFundsError, + #[error("Account {0} data is invalid")] + AccountDataError(AccountId), +} + #[expect(clippy::partial_pub_fields, reason = "TODO: make all fields private")] pub struct WalletCore { config_path: PathBuf, From b254ebb185f000f5751e8de426866de7f6cc1ee0 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Fri, 13 Mar 2026 22:38:23 +0300 Subject: [PATCH 03/10] feat: refactor sequencer RPC client-side --- Cargo.lock | 7 +- examples/program_deployment/Cargo.toml | 2 + .../src/bin/run_hello_world.rs | 4 +- .../bin/run_hello_world_through_tail_call.rs | 4 +- .../bin/run_hello_world_with_authorization.rs | 4 +- ...uthorization_through_tail_call_with_pda.rs | 4 +- .../bin/run_hello_world_with_move_function.rs | 6 +- explorer_service/src/api.rs | 11 +- .../src/pages/transaction_page.rs | 4 +- indexer/core/src/block_store.rs | 27 +++-- indexer/service/rpc/src/lib.rs | 12 ++- indexer/service/src/lib.rs | 6 +- indexer/service/src/mock_service.rs | 35 +++--- indexer/service/src/service.rs | 18 ++-- integration_tests/Cargo.toml | 1 + integration_tests/src/config.rs | 2 - integration_tests/src/lib.rs | 47 ++++---- integration_tests/tests/account.rs | 4 +- integration_tests/tests/amm.rs | 61 +++-------- .../tests/auth_transfer/private.rs | 7 +- .../tests/auth_transfer/public.rs | 27 +++-- integration_tests/tests/block_size_limit.rs | 42 +++++--- integration_tests/tests/indexer.rs | 50 +++++---- integration_tests/tests/keys_restoration.rs | 5 +- integration_tests/tests/pinata.rs | 34 +++--- integration_tests/tests/program_deployment.rs | 13 +-- integration_tests/tests/token.rs | 43 +++----- integration_tests/tests/tps.rs | 13 ++- .../src/key_management/key_tree/mod.rs | 85 ++------------- sequencer/core/src/block_store.rs | 26 +++-- sequencer/core/src/lib.rs | 7 +- sequencer/service/rpc/Cargo.toml | 1 - sequencer/service/rpc/src/lib.rs | 33 ++++-- sequencer/service/src/lib.rs | 17 ++- sequencer/service/src/service.rs | 45 ++++---- storage/src/error.rs | 7 -- storage/src/indexer.rs | 100 +++++++++++------- storage/src/sequencer.rs | 32 ++++-- wallet-ffi/Cargo.toml | 1 + wallet-ffi/src/lib.rs | 2 +- wallet-ffi/src/pinata.rs | 12 +-- wallet-ffi/src/sync.rs | 8 +- wallet-ffi/src/transfer.rs | 32 +++--- wallet/Cargo.toml | 2 + wallet/src/cli/account.rs | 7 +- wallet/src/cli/chain.rs | 16 ++- wallet/src/cli/mod.rs | 27 +++-- .../src/cli/programs/native_token_transfer.rs | 44 ++++---- wallet/src/cli/programs/pinata.rs | 10 +- wallet/src/cli/programs/token.rs | 80 ++++++-------- wallet/src/lib.rs | 74 ++++++------- wallet/src/pinata_interactions.rs | 18 ++-- wallet/src/poller.rs | 39 +++---- wallet/src/privacy_preserving_tx.rs | 3 +- wallet/src/program_facades/amm.rs | 37 +++++-- .../native_token_transfer/deshielded.rs | 6 +- .../native_token_transfer/mod.rs | 3 +- .../native_token_transfer/private.rs | 10 +- .../native_token_transfer/public.rs | 20 +++- .../native_token_transfer/shielded.rs | 8 +- wallet/src/program_facades/pinata.rs | 17 +-- wallet/src/program_facades/token.rs | 69 +++++++----- wallet/src/transaction_utils.rs | 48 +++++---- 63 files changed, 717 insertions(+), 722 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1695180d..fdd8395c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3571,6 +3571,7 @@ dependencies = [ "nssa_core", "sequencer_core", "sequencer_service", + "sequencer_service_rpc", "serde_json", "tempfile", "testcontainers", @@ -5868,8 +5869,10 @@ name = "program_deployment" version = "0.1.0" dependencies = [ "clap", + "common", "nssa", "nssa_core", + "sequencer_service_rpc", "tokio", "wallet", ] @@ -7197,7 +7200,6 @@ dependencies = [ "jsonrpsee", "nssa", "nssa_core", - "schemars 1.2.1", "serde_json", ] @@ -8667,9 +8669,11 @@ dependencies = [ "nssa_core", "optfield", "rand 0.8.5", + "sequencer_service_rpc", "serde", "serde_json", "sha2", + "thiserror 2.0.18", "token_core", "tokio", "url", @@ -8683,6 +8687,7 @@ dependencies = [ "common", "nssa", "nssa_core", + "sequencer_service_rpc", "tempfile", "tokio", "wallet", diff --git a/examples/program_deployment/Cargo.toml b/examples/program_deployment/Cargo.toml index 96964a36..c41d9247 100644 --- a/examples/program_deployment/Cargo.toml +++ b/examples/program_deployment/Cargo.toml @@ -8,8 +8,10 @@ license = { workspace = true } workspace = true [dependencies] +common.workspace = true nssa.workspace = true nssa_core.workspace = true +sequencer_service_rpc = { workspace = true, features = ["client"] } wallet.workspace = true tokio = { workspace = true, features = ["macros"] } diff --git a/examples/program_deployment/src/bin/run_hello_world.rs b/examples/program_deployment/src/bin/run_hello_world.rs index 3c0c9034..3d89b1a4 100644 --- a/examples/program_deployment/src/bin/run_hello_world.rs +++ b/examples/program_deployment/src/bin/run_hello_world.rs @@ -1,8 +1,10 @@ +use common::transaction::NSSATransaction; use nssa::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; +use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; // Before running this example, compile the `hello_world.rs` guest program with: @@ -58,7 +60,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs index 56d28084..c3c75b5f 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs @@ -1,8 +1,10 @@ +use common::transaction::NSSATransaction; use nssa::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; +use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; // Before running this example, compile the `simple_tail_call.rs` guest program with: @@ -54,7 +56,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs index f38443ac..39e1380f 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs @@ -1,9 +1,11 @@ +use common::transaction::NSSATransaction; use nssa::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; use nssa_core::account::Nonce; +use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; // Before running this example, compile the `hello_world_with_authorization.rs` guest program with: @@ -78,7 +80,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs index 4371b000..e6a8ca99 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs @@ -3,12 +3,14 @@ reason = "This is an example program, it's fine to print to stdout" )] +use common::transaction::NSSATransaction; use nssa::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; use nssa_core::program::PdaSeed; +use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; // Before running this example, compile the `simple_tail_call.rs` guest program with: @@ -56,7 +58,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index 0d4af502..a1c2517e 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -1,5 +1,7 @@ use clap::{Parser, Subcommand}; +use common::transaction::NSSATransaction; use nssa::{PublicTransaction, program::Program, public_transaction}; +use sequencer_service_rpc::RpcClient as _; use wallet::{PrivacyPreservingAccount, WalletCore}; // Before running this example, compile the `hello_world_with_move_function.rs` guest program with: @@ -87,7 +89,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); } @@ -126,7 +128,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await .unwrap(); } diff --git a/explorer_service/src/api.rs b/explorer_service/src/api.rs index b37145af..8c2a0e36 100644 --- a/explorer_service/src/api.rs +++ b/explorer_service/src/api.rs @@ -41,12 +41,12 @@ pub async fn search(query: String) -> Result { // Try as hash if let Ok(hash) = HashType::from_str(&query) { // Try as block hash - if let Ok(block) = client.get_block_by_hash(hash).await { + if let Ok(Some(block)) = client.get_block_by_hash(hash).await { blocks.push(block); } // Try as transaction hash - if let Ok(tx) = client.get_transaction(hash).await { + if let Ok(Some(tx)) = client.get_transaction(hash).await { transactions.push(tx); } } @@ -60,7 +60,7 @@ pub async fn search(query: String) -> Result { // Try as block ID if let Ok(block_id) = query.parse::() - && let Ok(block) = client.get_block_by_id(block_id).await + && let Ok(Some(block)) = client.get_block_by_id(block_id).await { blocks.push(block); } @@ -81,6 +81,7 @@ pub async fn get_block_by_id(block_id: BlockId) -> Result .get_block_by_id(block_id) .await .map_err(|e| ServerFnError::ServerError(format!("RPC error: {e}"))) + .and_then(|opt| opt.ok_or_else(|| ServerFnError::ServerError("Block not found".to_owned()))) } /// Get latest block ID @@ -103,6 +104,7 @@ pub async fn get_block_by_hash(block_hash: HashType) -> Result Result impl IntoView { } = witness_set; let program_id_str = program_id.to_string(); - let proof_len = proof.0.len(); + let proof_len = proof.map_or(0, |p| p.0.len()); let signatures_count = signatures_and_public_keys.len(); view! { @@ -183,7 +183,7 @@ pub fn TransactionPage() -> impl IntoView { proof, } = witness_set; - let proof_len = proof.0.len(); + let proof_len = proof.map_or(0, |p| p.0.len()); view! {

"Privacy-Preserving Transaction Details"

diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index db2f855b..384217ff 100644 --- a/indexer/core/src/block_store.rs +++ b/indexer/core/src/block_store.rs @@ -46,7 +46,7 @@ impl IndexerStore { Ok(self.dbio.get_meta_last_block_in_db()?) } - pub fn get_block_at_id(&self, id: u64) -> Result { + pub fn get_block_at_id(&self, id: u64) -> Result> { Ok(self.dbio.get_block(id)?) } @@ -54,20 +54,25 @@ impl IndexerStore { Ok(self.dbio.get_block_batch(before, limit)?) } - pub fn get_transaction_by_hash(&self, tx_hash: [u8; 32]) -> Result { - let block = self.get_block_at_id(self.dbio.get_block_id_by_tx_hash(tx_hash)?)?; - let transaction = block + pub fn get_transaction_by_hash(&self, tx_hash: [u8; 32]) -> Result> { + let Some(block_id) = self.dbio.get_block_id_by_tx_hash(tx_hash)? else { + return Ok(None); + }; + let Some(block) = self.get_block_at_id(block_id)? else { + return Ok(None); + }; + Ok(block .body .transactions - .iter() - .find(|enc_tx| enc_tx.hash().0 == tx_hash) - .ok_or_else(|| anyhow::anyhow!("Transaction not found in DB"))?; - - Ok(transaction.clone()) + .into_iter() + .find(|enc_tx| enc_tx.hash().0 == tx_hash)) } - pub fn get_block_by_hash(&self, hash: [u8; 32]) -> Result { - self.get_block_at_id(self.dbio.get_block_id_by_hash(hash)?) + pub fn get_block_by_hash(&self, hash: [u8; 32]) -> Result> { + let Some(id) = self.dbio.get_block_id_by_hash(hash)? else { + return Ok(None); + }; + self.get_block_at_id(id) } pub fn get_transactions_by_account( diff --git a/indexer/service/rpc/src/lib.rs b/indexer/service/rpc/src/lib.rs index be0e45ca..217c60d4 100644 --- a/indexer/service/rpc/src/lib.rs +++ b/indexer/service/rpc/src/lib.rs @@ -30,16 +30,22 @@ pub trait Rpc { async fn get_last_finalized_block_id(&self) -> Result; #[method(name = "getBlockById")] - async fn get_block_by_id(&self, block_id: BlockId) -> Result; + async fn get_block_by_id(&self, block_id: BlockId) -> Result, ErrorObjectOwned>; #[method(name = "getBlockByHash")] - async fn get_block_by_hash(&self, block_hash: HashType) -> Result; + async fn get_block_by_hash( + &self, + block_hash: HashType, + ) -> Result, ErrorObjectOwned>; #[method(name = "getAccount")] async fn get_account(&self, account_id: AccountId) -> Result; #[method(name = "getTransaction")] - async fn get_transaction(&self, tx_hash: HashType) -> Result; + async fn get_transaction( + &self, + tx_hash: HashType, + ) -> Result, ErrorObjectOwned>; #[method(name = "getBlocks")] async fn get_blocks( diff --git a/indexer/service/src/lib.rs b/indexer/service/src/lib.rs index 48e4f876..47f9289e 100644 --- a/indexer/service/src/lib.rs +++ b/indexer/service/src/lib.rs @@ -3,7 +3,7 @@ use std::net::SocketAddr; use anyhow::{Context as _, Result}; pub use indexer_core::config::*; use indexer_service_rpc::RpcServer as _; -use jsonrpsee::server::Server; +use jsonrpsee::server::{Server, ServerHandle}; use log::{error, info}; pub mod service; @@ -14,10 +14,10 @@ pub mod mock_service; pub struct IndexerHandle { addr: SocketAddr, /// Option because of `Drop` which forbids to simply move out of `self` in `stopped()`. - server_handle: Option, + server_handle: Option, } impl IndexerHandle { - const fn new(addr: SocketAddr, server_handle: jsonrpsee::server::ServerHandle) -> Self { + const fn new(addr: SocketAddr, server_handle: ServerHandle) -> Self { Self { addr, server_handle: Some(server_handle), diff --git a/indexer/service/src/mock_service.rs b/indexer/service/src/mock_service.rs index b52123bc..eb6f11f7 100644 --- a/indexer/service/src/mock_service.rs +++ b/indexer/service/src/mock_service.rs @@ -201,26 +201,23 @@ impl indexer_service_rpc::RpcServer for MockIndexerService { }) } - async fn get_block_by_id(&self, block_id: BlockId) -> Result { - self.blocks + async fn get_block_by_id(&self, block_id: BlockId) -> Result, ErrorObjectOwned> { + Ok(self + .blocks .iter() .find(|b| b.header.block_id == block_id) - .cloned() - .ok_or_else(|| { - ErrorObjectOwned::owned( - -32001, - format!("Block with ID {block_id} not found"), - None::<()>, - ) - }) + .cloned()) } - async fn get_block_by_hash(&self, block_hash: HashType) -> Result { - self.blocks + async fn get_block_by_hash( + &self, + block_hash: HashType, + ) -> Result, ErrorObjectOwned> { + Ok(self + .blocks .iter() .find(|b| b.header.hash == block_hash) - .cloned() - .ok_or_else(|| ErrorObjectOwned::owned(-32001, "Block with hash not found", None::<()>)) + .cloned()) } async fn get_account(&self, account_id: AccountId) -> Result { @@ -230,11 +227,11 @@ impl indexer_service_rpc::RpcServer for MockIndexerService { .ok_or_else(|| ErrorObjectOwned::owned(-32001, "Account not found", None::<()>)) } - async fn get_transaction(&self, tx_hash: HashType) -> Result { - self.transactions - .get(&tx_hash) - .map(|(tx, _)| tx.clone()) - .ok_or_else(|| ErrorObjectOwned::owned(-32001, "Transaction not found", None::<()>)) + async fn get_transaction( + &self, + tx_hash: HashType, + ) -> Result, ErrorObjectOwned> { + Ok(self.transactions.get(&tx_hash).map(|(tx, _)| tx.clone())) } async fn get_blocks( diff --git a/indexer/service/src/service.rs b/indexer/service/src/service.rs index 049d4a0c..e2f8a321 100644 --- a/indexer/service/src/service.rs +++ b/indexer/service/src/service.rs @@ -52,22 +52,25 @@ impl indexer_service_rpc::RpcServer for IndexerService { self.indexer.store.get_last_block_id().map_err(db_error) } - async fn get_block_by_id(&self, block_id: BlockId) -> Result { + async fn get_block_by_id(&self, block_id: BlockId) -> Result, ErrorObjectOwned> { Ok(self .indexer .store .get_block_at_id(block_id) .map_err(db_error)? - .into()) + .map(Into::into)) } - async fn get_block_by_hash(&self, block_hash: HashType) -> Result { + async fn get_block_by_hash( + &self, + block_hash: HashType, + ) -> Result, ErrorObjectOwned> { Ok(self .indexer .store .get_block_by_hash(block_hash.0) .map_err(db_error)? - .into()) + .map(Into::into)) } async fn get_account(&self, account_id: AccountId) -> Result { @@ -80,13 +83,16 @@ impl indexer_service_rpc::RpcServer for IndexerService { .into()) } - async fn get_transaction(&self, tx_hash: HashType) -> Result { + async fn get_transaction( + &self, + tx_hash: HashType, + ) -> Result, ErrorObjectOwned> { Ok(self .indexer .store .get_transaction_by_hash(tx_hash.0) .map_err(db_error)? - .into()) + .map(Into::into)) } async fn get_blocks( diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index a68609a3..137c9f54 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -19,6 +19,7 @@ indexer_service.workspace = true serde_json.workspace = true token_core.workspace = true indexer_service_rpc.workspace = true +sequencer_service_rpc = { workspace = true, features = ["client"] } wallet-ffi.workspace = true url.workspace = true diff --git a/integration_tests/src/config.rs b/integration_tests/src/config.rs index 5bcf59b9..dc24c8f0 100644 --- a/integration_tests/src/config.rs +++ b/integration_tests/src/config.rs @@ -204,7 +204,6 @@ pub fn sequencer_config( Ok(SequencerConfig { home, - override_rust_log: None, genesis_id: 1, is_genesis_random: true, max_num_tx_in_block, @@ -212,7 +211,6 @@ pub fn sequencer_config( mempool_max_size, block_create_timeout, retry_pending_blocks_timeout: Duration::from_secs(120), - port: 0, initial_accounts: initial_data.sequencer_initial_accounts(), initial_commitments: initial_data.sequencer_initial_commitments(), signing_key: [37; 32], diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index d7324f8a..016bde21 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -3,8 +3,7 @@ use std::{net::SocketAddr, path::PathBuf, sync::LazyLock}; use anyhow::{Context as _, Result, bail}; -use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64}; -use common::{HashType, sequencer_client::SequencerClient, transaction::NSSATransaction}; +use common::{HashType, transaction::NSSATransaction}; use futures::FutureExt as _; use indexer_service::IndexerHandle; use log::{debug, error, warn}; @@ -12,6 +11,7 @@ use nssa::{AccountId, PrivacyPreservingTransaction}; use nssa_core::Commitment; use sequencer_core::indexer_client::{IndexerClient, IndexerClientTrait as _}; use sequencer_service::SequencerHandle; +use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; use tempfile::TempDir; use testcontainers::compose::DockerCompose; use wallet::{WalletCore, config::WalletConfigOverrides}; @@ -38,7 +38,8 @@ pub struct TestContext { indexer_client: IndexerClient, wallet: WalletCore, wallet_password: String, - sequencer_handle: SequencerHandle, + /// Optional to move out value in Drop + sequencer_handle: Option, indexer_handle: IndexerHandle, bedrock_compose: DockerCompose, _temp_indexer_dir: TempDir, @@ -90,8 +91,9 @@ impl TestContext { .context("Failed to convert sequencer addr to URL")?; let indexer_url = config::addr_to_url(config::UrlProtocol::Ws, indexer_handle.addr()) .context("Failed to convert indexer addr to URL")?; - let sequencer_client = - SequencerClient::new(sequencer_url).context("Failed to create sequencer client")?; + let sequencer_client = SequencerClientBuilder::default() + .build(sequencer_url) + .context("Failed to create sequencer client")?; let indexer_client = IndexerClient::new(&indexer_url) .await .context("Failed to create indexer client")?; @@ -102,7 +104,7 @@ impl TestContext { wallet, wallet_password, bedrock_compose, - sequencer_handle, + sequencer_handle: Some(sequencer_handle), indexer_handle, _temp_indexer_dir: temp_indexer_dir, _temp_sequencer_dir: temp_sequencer_dir, @@ -229,7 +231,7 @@ impl TestContext { ) .context("Failed to create Sequencer config")?; - let sequencer_handle = sequencer_service::startup_sequencer(config).await?; + let sequencer_handle = sequencer_service::run(config, 0).await?; Ok((sequencer_handle, temp_sequencer_dir)) } @@ -333,14 +335,16 @@ impl Drop for TestContext { wallet_password: _, } = self; - if sequencer_handle.is_finished() { - let Err(err) = self - .sequencer_handle - .run_forever() + let sequencer_handle = sequencer_handle + .take() + .expect("Sequencer handle should be present in TestContext drop"); + if sequencer_handle.is_stopped() { + let Err(err) = sequencer_handle + .stopped() .now_or_never() - .expect("Future is finished and should be ready"); + .expect("Sequencer handle should be stopped"); error!( - "Sequencer handle has unexpectedly finished before TestContext drop with error: {err:#}" + "Sequencer handle has unexpectedly stopped before TestContext drop with error: {err:#}" ); } @@ -459,15 +463,8 @@ pub async fn fetch_privacy_preserving_tx( seq_client: &SequencerClient, tx_hash: HashType, ) -> PrivacyPreservingTransaction { - let transaction_encoded = seq_client - .get_transaction_by_hash(tx_hash) - .await - .unwrap() - .transaction - .unwrap(); + let tx = seq_client.get_transaction(tx_hash).await.unwrap().unwrap(); - let tx_bytes = BASE64.decode(transaction_encoded).unwrap(); - let tx = borsh::from_slice(&tx_bytes).unwrap(); match tx { NSSATransaction::PrivacyPreserving(privacy_preserving_transaction) => { privacy_preserving_transaction @@ -480,8 +477,8 @@ pub async fn verify_commitment_is_in_state( commitment: Commitment, seq_client: &SequencerClient, ) -> bool { - matches!( - seq_client.get_proof_for_commitment(commitment).await, - Ok(Some(_)) - ) + seq_client + .get_proof_for_commitment(commitment) + .await + .is_ok() } diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index 3f1d0993..60c1aeaa 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -7,6 +7,7 @@ use anyhow::Result; use integration_tests::TestContext; use log::info; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, @@ -21,8 +22,7 @@ async fn get_existing_account() -> Result<()> { let account = ctx .sequencer_client() .get_account(ctx.existing_public_accounts()[0]) - .await? - .account; + .await?; assert_eq!( account.program_owner, diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index bdb2da72..42aa5f3f 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -9,6 +9,7 @@ use std::time::Duration; use anyhow::Result; use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_public_account_id}; use log::info; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -194,20 +195,14 @@ async fn amm_public() -> Result<()> { let user_holding_a_acc = ctx .sequencer_client() .get_account(recipient_account_id_1) - .await? - .account; + .await?; let user_holding_b_acc = ctx .sequencer_client() .get_account(recipient_account_id_2) - .await? - .account; + .await?; - let user_holding_lp_acc = ctx - .sequencer_client() - .get_account(user_holding_lp) - .await? - .account; + let user_holding_lp_acc = ctx.sequencer_client().get_account(user_holding_lp).await?; assert_eq!( u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()), @@ -243,20 +238,14 @@ async fn amm_public() -> Result<()> { let user_holding_a_acc = ctx .sequencer_client() .get_account(recipient_account_id_1) - .await? - .account; + .await?; let user_holding_b_acc = ctx .sequencer_client() .get_account(recipient_account_id_2) - .await? - .account; + .await?; - let user_holding_lp_acc = ctx - .sequencer_client() - .get_account(user_holding_lp) - .await? - .account; + let user_holding_lp_acc = ctx.sequencer_client().get_account(user_holding_lp).await?; assert_eq!( u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()), @@ -292,20 +281,14 @@ async fn amm_public() -> Result<()> { let user_holding_a_acc = ctx .sequencer_client() .get_account(recipient_account_id_1) - .await? - .account; + .await?; let user_holding_b_acc = ctx .sequencer_client() .get_account(recipient_account_id_2) - .await? - .account; + .await?; - let user_holding_lp_acc = ctx - .sequencer_client() - .get_account(user_holding_lp) - .await? - .account; + let user_holding_lp_acc = ctx.sequencer_client().get_account(user_holding_lp).await?; assert_eq!( u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()), @@ -342,20 +325,14 @@ async fn amm_public() -> Result<()> { let user_holding_a_acc = ctx .sequencer_client() .get_account(recipient_account_id_1) - .await? - .account; + .await?; let user_holding_b_acc = ctx .sequencer_client() .get_account(recipient_account_id_2) - .await? - .account; + .await?; - let user_holding_lp_acc = ctx - .sequencer_client() - .get_account(user_holding_lp) - .await? - .account; + let user_holding_lp_acc = ctx.sequencer_client().get_account(user_holding_lp).await?; assert_eq!( u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()), @@ -392,20 +369,14 @@ async fn amm_public() -> Result<()> { let user_holding_a_acc = ctx .sequencer_client() .get_account(recipient_account_id_1) - .await? - .account; + .await?; let user_holding_b_acc = ctx .sequencer_client() .get_account(recipient_account_id_2) - .await? - .account; + .await?; - let user_holding_lp_acc = ctx - .sequencer_client() - .get_account(user_holding_lp) - .await? - .account; + let user_holding_lp_acc = ctx.sequencer_client().get_account(user_holding_lp).await?; assert_eq!( u128::from_le_bytes(user_holding_a_acc.data[33..].try_into().unwrap()), diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 93e925d9..59b4719a 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -8,6 +8,7 @@ use integration_tests::{ use log::info; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -135,7 +136,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { let acc_2_balance = ctx.sequencer_client().get_account_balance(to).await?; assert_eq!(from_acc.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_2_balance, 20100); info!("Successfully deshielded transfer to public account"); @@ -245,7 +246,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { let acc_from_balance = ctx.sequencer_client().get_account_balance(from).await?; - assert_eq!(acc_from_balance.balance, 9900); + assert_eq!(acc_from_balance, 9900); assert_eq!(acc_to.balance, 20100); info!("Successfully shielded transfer to owned private account"); @@ -290,7 +291,7 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { .await ); - assert_eq!(acc_1_balance.balance, 9900); + assert_eq!(acc_1_balance, 9900); info!("Successfully shielded transfer to foreign account"); diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index ce73d62f..7f8c3836 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -4,6 +4,7 @@ use anyhow::Result; use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_public_account_id}; use log::info; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -41,8 +42,8 @@ async fn successful_transfer_to_existing_account() -> Result<()> { info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); Ok(()) } @@ -97,8 +98,8 @@ pub async fn successful_transfer_to_new_account() -> Result<()> { info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 100); + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 100); Ok(()) } @@ -134,8 +135,8 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> { info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 10000); - assert_eq!(acc_2_balance.balance, 20000); + assert_eq!(acc_1_balance, 10000); + assert_eq!(acc_2_balance, 20000); Ok(()) } @@ -171,8 +172,8 @@ async fn two_consecutive_successful_transfers() -> Result<()> { info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); info!("First TX Success!"); @@ -203,8 +204,8 @@ async fn two_consecutive_successful_transfers() -> Result<()> { info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 9800); - assert_eq!(acc_2_balance.balance, 20200); + assert_eq!(acc_1_balance, 9800); + assert_eq!(acc_2_balance, 20200); info!("Second TX Success!"); @@ -230,11 +231,7 @@ async fn initialize_public_account() -> Result<()> { wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; info!("Checking correct execution"); - let account = ctx - .sequencer_client() - .get_account(account_id) - .await? - .account; + let account = ctx.sequencer_client().get_account(account_id).await?; assert_eq!( account.program_owner, diff --git a/integration_tests/tests/block_size_limit.rs b/integration_tests/tests/block_size_limit.rs index 41c9fc76..72f773c9 100644 --- a/integration_tests/tests/block_size_limit.rs +++ b/integration_tests/tests/block_size_limit.rs @@ -8,11 +8,12 @@ use std::time::Duration; use anyhow::Result; use bytesize::ByteSize; -use common::{block::HashableBlockData, transaction::NSSATransaction}; +use common::transaction::NSSATransaction; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, config::SequencerPartialConfig, }; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use tokio::test; #[test] @@ -36,7 +37,10 @@ async fn reject_oversized_transaction() -> Result<()> { let tx = nssa::ProgramDeploymentTransaction::new(message); // Try to submit the transaction and expect an error - let result = ctx.sequencer_client().send_tx_program(tx).await; + let result = ctx + .sequencer_client() + .send_transaction(NSSATransaction::ProgramDeployment(tx)) + .await; assert!( result.is_err(), @@ -74,7 +78,10 @@ async fn accept_transaction_within_limit() -> Result<()> { let tx = nssa::ProgramDeploymentTransaction::new(message); // This should succeed - let result = ctx.sequencer_client().send_tx_program(tx).await; + let result = ctx + .sequencer_client() + .send_transaction(NSSATransaction::ProgramDeployment(tx)) + .await; assert!( result.is_ok(), @@ -112,33 +119,38 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { let burner_id = Program::new(burner_bytecode.clone())?.id(); let chain_caller_id = Program::new(chain_caller_bytecode.clone())?.id(); - let initial_block_height = ctx.sequencer_client().get_last_block().await?.last_block; + let initial_block_height = ctx.sequencer_client().get_last_block_id().await?; // Submit both program deployments ctx.sequencer_client() - .send_tx_program(nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(burner_bytecode), + .send_transaction(NSSATransaction::ProgramDeployment( + nssa::ProgramDeploymentTransaction::new( + nssa::program_deployment_transaction::Message::new(burner_bytecode), + ), )) .await?; ctx.sequencer_client() - .send_tx_program(nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(chain_caller_bytecode), + .send_transaction(NSSATransaction::ProgramDeployment( + nssa::ProgramDeploymentTransaction::new( + nssa::program_deployment_transaction::Message::new(chain_caller_bytecode), + ), )) .await?; // Wait for first block tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let block1_response = ctx + let block1 = ctx .sequencer_client() .get_block(initial_block_height + 1) - .await?; - let block1: HashableBlockData = borsh::from_slice(&block1_response.block)?; + .await? + .unwrap(); // Check which program is in block 1 - let get_program_ids = |block: &HashableBlockData| -> Vec { + let get_program_ids = |block: &common::block::Block| -> Vec { block + .body .transactions .iter() .filter_map(|tx| { @@ -168,11 +180,11 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { // Wait for second block tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let block2_response = ctx + let block2 = ctx .sequencer_client() .get_block(initial_block_height + 2) - .await?; - let block2: HashableBlockData = borsh::from_slice(&block2_response.block)?; + .await? + .unwrap(); let block2_program_ids = get_program_ids(&block2); // The other program should be in block 2 diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index 0b947135..cb8cf0e9 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -22,12 +22,8 @@ async fn indexer_test_run() -> Result<()> { // RUN OBSERVATION tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await; - let last_block_seq = ctx - .sequencer_client() - .get_last_block() - .await - .unwrap() - .last_block; + let last_block_seq = + sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()).await?; info!("Last block on seq now is {last_block_seq}"); @@ -100,20 +96,22 @@ async fn indexer_state_consistency() -> Result<()> { tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; info!("Checking correct balance move"); - let acc_1_balance = ctx - .sequencer_client() - .get_account_balance(ctx.existing_public_accounts()[0]) - .await?; - let acc_2_balance = ctx - .sequencer_client() - .get_account_balance(ctx.existing_public_accounts()[1]) - .await?; + let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; info!("Balance of sender: {acc_1_balance:#?}"); info!("Balance of receiver: {acc_2_balance:#?}"); - assert_eq!(acc_1_balance.balance, 9900); - assert_eq!(acc_2_balance.balance, 20100); + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); // WAIT info!("Waiting for indexer to parse blocks"); @@ -131,16 +129,16 @@ async fn indexer_state_consistency() -> Result<()> { .unwrap(); info!("Checking correct state transition"); - let acc1_seq_state = ctx - .sequencer_client() - .get_account(ctx.existing_public_accounts()[0]) - .await? - .account; - let acc2_seq_state = ctx - .sequencer_client() - .get_account(ctx.existing_public_accounts()[1]) - .await? - .account; + let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc2_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; assert_eq!(acc1_ind_state, acc1_seq_state.into()); assert_eq!(acc2_ind_state, acc2_seq_state.into()); diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index 0d20f8b4..cdbe2e6b 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -14,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::{AccountId, program::Program}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -305,8 +306,8 @@ async fn restore_keys_from_seed() -> Result<()> { .get_account_balance(to_account_id4) .await?; - assert_eq!(acc3.balance, 91); // 102 - 11 - assert_eq!(acc4.balance, 114); // 103 + 11 + assert_eq!(acc3, 91); // 102 - 11 + assert_eq!(acc4, 114); // 103 + 11 info!("Successfully restored keys and verified transactions"); diff --git a/integration_tests/tests/pinata.rs b/integration_tests/tests/pinata.rs index 38cfeac3..3285c216 100644 --- a/integration_tests/tests/pinata.rs +++ b/integration_tests/tests/pinata.rs @@ -13,6 +13,7 @@ use integration_tests::{ format_public_account_id, verify_commitment_is_in_state, }; use log::info; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ Command, SubcommandReturnValue, @@ -46,8 +47,7 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()> let pinata_balance_pre = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; let claim_result = wallet::cli::execute_subcommand( ctx.wallet_mut(), @@ -70,8 +70,7 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()> let pinata_balance_post = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; assert_eq!(pinata_balance_post, pinata_balance_pre); @@ -102,8 +101,7 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<() let pinata_balance_pre = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; let claim_result = wallet::cli::execute_subcommand( ctx.wallet_mut(), @@ -126,8 +124,7 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<() let pinata_balance_post = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; assert_eq!(pinata_balance_post, pinata_balance_pre); @@ -146,8 +143,7 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> { let pinata_balance_pre = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; @@ -158,14 +154,12 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> { let pinata_balance_post = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; let winner_balance_post = ctx .sequencer_client() .get_account_balance(ctx.existing_public_accounts()[0]) - .await? - .balance; + .await?; assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); assert_eq!(winner_balance_post, 10000 + pinata_prize); @@ -187,8 +181,7 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> { let pinata_balance_pre = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } = result else { @@ -211,8 +204,7 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> { let pinata_balance_post = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); @@ -268,8 +260,7 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { let pinata_balance_pre = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; @@ -285,8 +276,7 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { let pinata_balance_post = ctx .sequencer_client() .get_account_balance(PINATA_BASE58.parse().unwrap()) - .await? - .balance; + .await?; assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); diff --git a/integration_tests/tests/program_deployment.rs b/integration_tests/tests/program_deployment.rs index 1feb7290..bb46ba87 100644 --- a/integration_tests/tests/program_deployment.rs +++ b/integration_tests/tests/program_deployment.rs @@ -6,11 +6,13 @@ use std::{path::PathBuf, time::Duration}; use anyhow::Result; +use common::transaction::NSSATransaction; use integration_tests::{ NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, }; use log::info; use nssa::{AccountId, program::Program}; +use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::Command; @@ -47,18 +49,17 @@ async fn deploy_and_execute_program() -> Result<()> { )?; let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); let transaction = nssa::PublicTransaction::new(message, witness_set); - let _response = ctx.sequencer_client().send_tx_public(transaction).await?; + let _response = ctx + .sequencer_client() + .send_transaction(NSSATransaction::Public(transaction)) + .await?; info!("Waiting for next block creation"); // Waiting for long time as it may take some time for such a big transaction to be included in a // block tokio::time::sleep(Duration::from_secs(2 * TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let post_state_account = ctx - .sequencer_client() - .get_account(account_id) - .await? - .account; + let post_state_account = ctx.sequencer_client().get_account(account_id).await?; assert_eq!(post_state_account.program_owner, data_changer.id()); assert_eq!(post_state_account.balance, 0); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 5efd69ef..b638b6c9 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -14,6 +14,7 @@ use integration_tests::{ use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; use nssa::program::Program; +use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; use wallet::cli::{ @@ -92,8 +93,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -110,8 +110,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); @@ -143,8 +142,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( @@ -159,8 +157,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; assert_eq!(recipient_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -188,8 +185,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -205,8 +201,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -236,8 +231,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -253,8 +247,7 @@ async fn create_and_transfer_public_token() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -341,8 +334,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!(definition_acc.program_owner, Program::token().id()); @@ -405,8 +397,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { let definition_acc = ctx .sequencer_client() .get_account(definition_account_id) - .await? - .account; + .await?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?; assert_eq!( @@ -506,8 +497,7 @@ async fn create_token_with_private_definition() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; assert_eq!(supply_acc.program_owner, Program::token().id()); let token_holding = TokenHolding::try_from(&supply_acc.data)?; @@ -586,8 +576,7 @@ async fn create_token_with_private_definition() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id_public) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( @@ -882,8 +871,7 @@ async fn shielded_token_transfer() -> Result<()> { let supply_acc = ctx .sequencer_client() .get_account(supply_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&supply_acc.data)?; assert_eq!( token_holding, @@ -1026,8 +1014,7 @@ async fn deshielded_token_transfer() -> Result<()> { let recipient_acc = ctx .sequencer_client() .get_account(recipient_account_id) - .await? - .account; + .await?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?; assert_eq!( token_holding, diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index 1dee3a85..bd46849e 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -13,6 +13,7 @@ use std::time::{Duration, Instant}; use anyhow::Result; use bytesize::ByteSize; +use common::transaction::NSSATransaction; use integration_tests::{ TestContext, config::{InitialData, SequencerPartialConfig}, @@ -30,6 +31,7 @@ use nssa_core::{ account::{AccountWithMetadata, Nonce, data::Data}, encryption::ViewingPublicKey, }; +use sequencer_service_rpc::RpcClient as _; use tokio::test; pub(crate) struct TpsTestManager { @@ -153,10 +155,9 @@ pub async fn tps_test() -> Result<()> { for (i, tx) in txs.into_iter().enumerate() { let tx_hash = ctx .sequencer_client() - .send_tx_public(tx) + .send_transaction(NSSATransaction::Public(tx)) .await - .unwrap() - .tx_hash; + .unwrap(); info!("Sent tx {i}"); tx_hashes.push(tx_hash); } @@ -170,15 +171,13 @@ pub async fn tps_test() -> Result<()> { let tx_obj = ctx .sequencer_client() - .get_transaction_by_hash(*tx_hash) + .get_transaction(*tx_hash) .await .inspect_err(|err| { log::warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}"); }); - if let Ok(tx_obj) = tx_obj - && tx_obj.transaction.is_some() - { + if tx_obj.is_ok_and(|opt| opt.is_some()) { info!("Found tx {i} with hash {tx_hash}"); break; } diff --git a/key_protocol/src/key_management/key_tree/mod.rs b/key_protocol/src/key_management/key_tree/mod.rs index a94e8291..08a576e5 100644 --- a/key_protocol/src/key_management/key_tree/mod.rs +++ b/key_protocol/src/key_management/key_tree/mod.rs @@ -1,7 +1,7 @@ -use std::{collections::BTreeMap, sync::Arc}; +use std::collections::BTreeMap; use anyhow::Result; -use common::sequencer_client::SequencerClient; +use nssa::{Account, AccountId}; use serde::{Deserialize, Serialize}; use crate::key_management::{ @@ -197,40 +197,6 @@ impl KeyTree { } impl KeyTree { - /// Cleanup of all non-initialized accounts in a private tree. - /// - /// For given `depth` checks children to a tree such that their `ChainIndex::depth(&self) < - /// depth`. - /// - /// If account is default, removes them. - /// - /// Chain must be parsed for accounts beforehand. - /// - /// Fast, leaves gaps between accounts. - pub fn cleanup_tree_remove_uninit_for_depth(&mut self, depth: u32) { - let mut id_stack = vec![ChainIndex::root()]; - - while let Some(curr_id) = id_stack.pop() { - if let Some(node) = self.key_map.get(&curr_id) - && node.value.1 == nssa::Account::default() - && curr_id != ChainIndex::root() - { - let addr = node.account_id(); - self.remove(addr); - } - - let mut next_id = curr_id.nth_child(0); - - while (next_id.depth()) < depth { - id_stack.push(next_id.clone()); - next_id = match next_id.next_in_line() { - Some(id) => id, - None => break, - }; - } - } - } - /// Cleanup of non-initialized accounts in a private tree. /// /// If account is default, removes them, stops at first non-default account. @@ -259,56 +225,17 @@ impl KeyTree { } impl KeyTree { - /// Cleanup of all non-initialized accounts in a public tree. - /// - /// For given `depth` checks children to a tree such that their `ChainIndex::depth(&self) < - /// depth`. - /// - /// If account is default, removes them. - /// - /// Fast, leaves gaps between accounts. - pub async fn cleanup_tree_remove_ininit_for_depth( - &mut self, - depth: u32, - client: Arc, - ) -> Result<()> { - let mut id_stack = vec![ChainIndex::root()]; - - while let Some(curr_id) = id_stack.pop() { - if let Some(node) = self.key_map.get(&curr_id) { - let address = node.account_id(); - let node_acc = client.get_account(address).await?.account; - - if node_acc == nssa::Account::default() && curr_id != ChainIndex::root() { - self.remove(address); - } - } - - let mut next_id = curr_id.nth_child(0); - - while (next_id.depth()) < depth { - id_stack.push(next_id.clone()); - next_id = match next_id.next_in_line() { - Some(id) => id, - None => break, - }; - } - } - - Ok(()) - } - /// Cleanup of non-initialized accounts in a public tree. /// /// If account is default, removes them, stops at first non-default account. /// - /// Walks through tree in lairs of same depth using `ChainIndex::chain_ids_at_depth()`. + /// Walks through tree in layers of same depth using `ChainIndex::chain_ids_at_depth()`. /// /// Slow, maintains tree consistency. - pub async fn cleanup_tree_remove_uninit_layered( + pub async fn cleanup_tree_remove_uninit_layered>>( &mut self, depth: u32, - client: Arc, + get_account: impl Fn(AccountId) -> F, ) -> Result<()> { let depth = usize::try_from(depth).expect("Depth is expected to fit in usize"); 'outer: for i in (1..depth).rev() { @@ -316,7 +243,7 @@ impl KeyTree { for id in ChainIndex::chain_ids_at_depth(i) { if let Some(node) = self.key_map.get(&id) { let address = node.account_id(); - let node_acc = client.get_account(address).await?.account; + let node_acc = get_account(address).await?; if node_acc == nssa::Account::default() { let addr = node.account_id(); diff --git a/sequencer/core/src/block_store.rs b/sequencer/core/src/block_store.rs index 51355f5f..7a226d45 100644 --- a/sequencer/core/src/block_store.rs +++ b/sequencer/core/src/block_store.rs @@ -42,7 +42,7 @@ impl SequencerStore { }) } - pub fn get_block_at_id(&self, id: u64) -> Result { + pub fn get_block_at_id(&self, id: u64) -> Result, DbError> { self.dbio.get_block(id) } @@ -56,16 +56,20 @@ impl SequencerStore { /// Returns the transaction corresponding to the given hash, if it exists in the blockchain. pub fn get_transaction_by_hash(&self, hash: HashType) -> Option { - let block_id = self.tx_hash_to_block_map.get(&hash); - let block = block_id.map(|&id| self.get_block_at_id(id)); - if let Some(Ok(block)) = block { - for transaction in block.body.transactions { - if transaction.hash() == hash { - return Some(transaction); - } + let block_id = *self.tx_hash_to_block_map.get(&hash)?; + let block = self + .get_block_at_id(block_id) + .ok() + .flatten() + .expect("Block should be present since the hash is in the map"); + for transaction in block.body.transactions { + if transaction.hash() == hash { + return Some(transaction); } } - None + panic!( + "Transaction hash was in the map but transaction was not found in the block. This should never happen." + ); } pub fn latest_block_meta(&self) -> Result { @@ -244,7 +248,7 @@ mod tests { node_store.update(&block, [1; 32], &dummy_state).unwrap(); // Verify initial status is Pending - let retrieved_block = node_store.get_block_at_id(block_id).unwrap(); + let retrieved_block = node_store.get_block_at_id(block_id).unwrap().unwrap(); assert!(matches!( retrieved_block.bedrock_status, common::block::BedrockStatus::Pending @@ -254,7 +258,7 @@ mod tests { node_store.mark_block_as_finalized(block_id).unwrap(); // Verify status is now Finalized - let finalized_block = node_store.get_block_at_id(block_id).unwrap(); + let finalized_block = node_store.get_block_at_id(block_id).unwrap().unwrap(); assert!(matches!( finalized_block.bedrock_status, common::block::BedrockStatus::Finalized diff --git a/sequencer/core/src/lib.rs b/sequencer/core/src/lib.rs index 7f58faf4..f3e94614 100644 --- a/sequencer/core/src/lib.rs +++ b/sequencer/core/src/lib.rs @@ -389,7 +389,6 @@ mod tests { SequencerConfig { home, - override_rust_log: Some("info".to_owned()), genesis_id: 1, is_genesis_random: false, max_num_tx_in_block: 10, @@ -476,7 +475,6 @@ mod tests { assert_eq!(sequencer.chain_height, config.genesis_id); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); - assert_eq!(sequencer.sequencer_config.port, 8080); let acc1_account_id = config.initial_accounts[0].account_id; let acc2_account_id = config.initial_accounts[1].account_id; @@ -694,6 +692,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); // Only one should be included in the block @@ -721,6 +720,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!(block.body.transactions, vec![tx.clone()]); @@ -732,6 +732,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert!(block.body.transactions.is_empty()); } @@ -766,6 +767,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!(block.body.transactions, vec![tx.clone()]); } @@ -884,6 +886,7 @@ mod tests { let new_block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!( diff --git a/sequencer/service/rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml index 1ced7997..7fa173d1 100644 --- a/sequencer/service/rpc/Cargo.toml +++ b/sequencer/service/rpc/Cargo.toml @@ -14,7 +14,6 @@ nssa_core.workspace = true jsonrpsee = { workspace = true, features = ["macros"] } serde_json.workspace = true -schemars.workspace = true [features] client = ["jsonrpsee/client"] diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs index 0ff68bfe..a4bb8f06 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/sequencer/service/rpc/src/lib.rs @@ -8,12 +8,29 @@ use common::{ use jsonrpsee::proc_macros::rpc; #[cfg(feature = "server")] use jsonrpsee::types::ErrorObjectOwned; +#[cfg(feature = "client")] +pub use jsonrpsee::{core::ClientError, http_client::HttpClientBuilder as SequencerClientBuilder}; use nssa::{Account, AccountId, ProgramId}; use nssa_core::{Commitment, MembershipProof, account::Nonce}; #[cfg(all(not(feature = "server"), not(feature = "client")))] compile_error!("At least one of `server` or `client` features must be enabled."); +/// Type alias for RPC client. Only available when `client` feature is enabled. +/// +/// It's cheap to clone this client, so it can be cloned and shared across the application. +/// +/// # Example +/// +/// ```ignore +/// use sequencer_service_rpc::{SequencerClientBuilder, RpcClient as _}; +/// +/// let client = SequencerClientBuilder::default().build(url)?; +/// let tx_hash = client.send_transaction(tx).await?; +/// ``` +#[cfg(feature = "client")] +pub type SequencerClient = jsonrpsee::http_client::HttpClient; + #[cfg_attr(all(feature = "server", not(feature = "client")), rpc(server))] #[cfg_attr(all(feature = "client", not(feature = "server")), rpc(client))] #[cfg_attr(all(feature = "server", feature = "client"), rpc(server, client))] @@ -30,11 +47,11 @@ pub trait Rpc { // // ============================================================================================= - #[method(name = "getBlockData")] - async fn get_block_data(&self, block_id: BlockId) -> Result; + #[method(name = "getBlock")] + async fn get_block(&self, block_id: BlockId) -> Result, ErrorObjectOwned>; - #[method(name = "getBlockRangeData")] - async fn get_block_range_data( + #[method(name = "getBlockRange")] + async fn get_block_range( &self, start_block_id: BlockId, end_block_id: BlockId, @@ -46,11 +63,11 @@ pub trait Rpc { #[method(name = "getAccountBalance")] async fn get_account_balance(&self, account_id: AccountId) -> Result; - #[method(name = "getTransactionByHash")] - async fn get_transaction_by_hash( + #[method(name = "getTransaction")] + async fn get_transaction( &self, - hash: HashType, - ) -> Result; + tx_hash: HashType, + ) -> Result, ErrorObjectOwned>; #[method(name = "getAccountsNonces")] async fn get_accounts_nonces( diff --git a/sequencer/service/src/lib.rs b/sequencer/service/src/lib.rs index 547f58d2..8ab997d9 100644 --- a/sequencer/service/src/lib.rs +++ b/sequencer/service/src/lib.rs @@ -89,10 +89,19 @@ impl SequencerHandle { } #[must_use] - pub fn is_finished(&self) -> bool { - self.main_loop_handle.is_finished() - || self.retry_pending_blocks_loop_handle.is_finished() - || self.listen_for_bedrock_blocks_loop_handle.is_finished() + pub fn is_stopped(&self) -> bool { + let Self { + addr: _, + server_handle, + main_loop_handle, + retry_pending_blocks_loop_handle, + listen_for_bedrock_blocks_loop_handle, + } = self; + + server_handle.as_ref().is_none_or(ServerHandle::is_stopped) + || main_loop_handle.is_finished() + || retry_pending_blocks_loop_handle.is_finished() + || listen_for_bedrock_blocks_loop_handle.is_finished() } #[must_use] diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs index d1b21f69..c8f17189 100644 --- a/sequencer/service/src/service.rs +++ b/sequencer/service/src/service.rs @@ -93,24 +93,37 @@ impl Result { + async fn get_block(&self, block_id: BlockId) -> Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; sequencer .block_store() .get_block_at_id(block_id) - .map_err(|err| db_error_to_rpc_error(&err)) + .map_err(|err| internal_error(&err)) } - async fn get_block_range_data( + async fn get_block_range( &self, start_block_id: BlockId, end_block_id: BlockId, ) -> Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; (start_block_id..=end_block_id) - .map(|block_id| sequencer.block_store().get_block_at_id(block_id)) + .map(|block_id| { + sequencer + .block_store() + .get_block_at_id(block_id) + .map_err(|err| internal_error(&err)) + .and_then(|opt| { + opt.ok_or_else(|| { + ErrorObjectOwned::owned( + NOT_FOUND_ERROR_CODE, + format!("Block with id {block_id} not found"), + None::<()>, + ) + }) + }) + }) .collect::, _>>() - .map_err(|err| db_error_to_rpc_error(&err)) } async fn get_last_block_id(&self) -> Result { @@ -124,17 +137,12 @@ impl Result { + ) -> Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; - sequencer - .block_store() - .get_transaction_by_hash(hash) - .ok_or_else(|| { - ErrorObjectOwned::owned(NOT_FOUND_ERROR_CODE, "Transaction not found", None::<()>) - }) + Ok(sequencer.block_store().get_transaction_by_hash(hash)) } async fn get_accounts_nonces( @@ -190,13 +198,6 @@ impl ErrorObjectOwned { - match err { - DbError::NotFound { entity } => ErrorObjectOwned::owned( - NOT_FOUND_ERROR_CODE, - format!("{entity} not found"), - None::<()>, - ), - _ => ErrorObjectOwned::owned(ErrorCode::InternalError.code(), err.to_string(), None::<()>), - } +fn internal_error(err: &DbError) -> ErrorObjectOwned { + ErrorObjectOwned::owned(ErrorCode::InternalError.code(), err.to_string(), None::<()>) } diff --git a/storage/src/error.rs b/storage/src/error.rs index 3e0f88ba..3056e09b 100644 --- a/storage/src/error.rs +++ b/storage/src/error.rs @@ -14,8 +14,6 @@ pub enum DbError { }, #[error("Logic Error: {additional_info}")] DbInteractionError { additional_info: String }, - #[error("{entity} not found")] - NotFound { entity: String }, } impl DbError { @@ -41,9 +39,4 @@ impl DbError { additional_info: message, } } - - #[must_use] - pub const fn not_found(entity: String) -> Self { - Self::NotFound { entity } - } } diff --git a/storage/src/indexer.rs b/storage/src/indexer.rs index c9b3b358..91c3d8d1 100644 --- a/storage/src/indexer.rs +++ b/storage/src/indexer.rs @@ -180,7 +180,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("First block".to_owned())) + Err(DbError::db_interaction_error( + "First block not found".to_owned(), + )) } } @@ -207,7 +209,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("Last block".to_owned())) + Err(DbError::db_interaction_error( + "Last block not found".to_owned(), + )) } } @@ -282,7 +286,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("Last breakpoint id".to_owned())) + Err(DbError::db_interaction_error( + "Last breakpoint id not found".to_owned(), + )) } } @@ -508,7 +514,7 @@ impl RocksDBIO { Ok(()) } - pub fn get_block(&self, block_id: u64) -> DbResult { + pub fn get_block(&self, block_id: u64) -> DbResult> { let cf_block = self.block_column(); let res = self .db @@ -524,14 +530,14 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(borsh::from_slice::(&data).map_err(|serr| { + Ok(Some(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message( serr, Some("Failed to deserialize block data".to_owned()), ) - })?) + })?)) } else { - Err(DbError::not_found(format!("Block with id {block_id}"))) + Ok(None) } } @@ -659,7 +665,9 @@ impl RocksDBIO { }; for id in start..=block_id { - let block = self.get_block(id)?; + let block = self.get_block(id)?.ok_or_else(|| { + DbError::db_interaction_error(format!("Block with id {id} not found")) + })?; for transaction in block.body.transactions { transaction @@ -680,7 +688,9 @@ impl RocksDBIO { Ok(breakpoint) } else { - Err(DbError::not_found(format!("Block with id {block_id}"))) + Err(DbError::db_interaction_error(format!( + "Block with id {block_id} not found" + ))) } } @@ -712,7 +722,7 @@ impl RocksDBIO { // Mappings - pub fn get_block_id_by_hash(&self, hash: [u8; 32]) -> DbResult { + pub fn get_block_id_by_hash(&self, hash: [u8; 32]) -> DbResult> { let cf_hti = self.hash_to_id_column(); let res = self .db @@ -728,15 +738,15 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(borsh::from_slice::(&data).map_err(|serr| { + Ok(Some(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned())) - })?) + })?)) } else { - Err(DbError::not_found("Block with given hash".to_owned())) + Ok(None) } } - pub fn get_block_id_by_tx_hash(&self, tx_hash: [u8; 32]) -> DbResult { + pub fn get_block_id_by_tx_hash(&self, tx_hash: [u8; 32]) -> DbResult> { let cf_tti = self.tx_hash_to_id_column(); let res = self .db @@ -752,11 +762,11 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(borsh::from_slice::(&data).map_err(|serr| { + Ok(Some(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned())) - })?) + })?)) } else { - Err(DbError::not_found("Block for given tx hash".to_owned())) + Ok(None) } } @@ -909,8 +919,14 @@ impl RocksDBIO { let mut tx_batch = vec![]; for tx_hash in self.get_acc_transaction_hashes(acc_id, offset, limit)? { - let block_id = self.get_block_id_by_tx_hash(tx_hash)?; - let block = self.get_block(block_id)?; + let block_id = self.get_block_id_by_tx_hash(tx_hash)?.ok_or_else(|| { + DbError::db_interaction_error(format!( + "Block id not found for tx hash {tx_hash:#?}" + )) + })?; + let block = self.get_block(block_id)?.ok_or_else(|| { + DbError::db_interaction_error(format!("Block with id {block_id} not found")) + })?; let transaction = block .body @@ -1007,7 +1023,7 @@ mod tests { let first_id = dbio.get_meta_first_block_in_db().unwrap(); let is_first_set = dbio.get_meta_is_first_block_set().unwrap(); let last_br_id = dbio.get_meta_last_breakpoint_id().unwrap(); - let last_block = dbio.get_block(1).unwrap(); + let last_block = dbio.get_block(1).unwrap().unwrap(); let breakpoint = dbio.get_breakpoint(0).unwrap(); let final_state = dbio.final_state().unwrap(); @@ -1044,7 +1060,7 @@ mod tests { let first_id = dbio.get_meta_first_block_in_db().unwrap(); let is_first_set = dbio.get_meta_is_first_block_set().unwrap(); let last_br_id = dbio.get_meta_last_breakpoint_id().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let breakpoint = dbio.get_breakpoint(0).unwrap(); let final_state = dbio.final_state().unwrap(); @@ -1075,7 +1091,7 @@ mod tests { for i in 1..BREAKPOINT_INTERVAL { let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, u128::from(i - 1), true); @@ -1091,7 +1107,7 @@ mod tests { let first_id = dbio.get_meta_first_block_in_db().unwrap(); let is_first_set = dbio.get_meta_is_first_block_set().unwrap(); let last_br_id = dbio.get_meta_last_breakpoint_id().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_breakpoint = dbio.get_breakpoint(0).unwrap(); let breakpoint = dbio.get_breakpoint(1).unwrap(); let final_state = dbio.final_state().unwrap(); @@ -1130,7 +1146,7 @@ mod tests { RocksDBIO::open_or_create(temdir_path, &genesis_block(), &initial_state()).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 0, true); @@ -1141,7 +1157,7 @@ mod tests { dbio.put_block(&block, [1; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 1, true); @@ -1152,7 +1168,7 @@ mod tests { dbio.put_block(&block, [2; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 2, true); @@ -1163,7 +1179,7 @@ mod tests { dbio.put_block(&block, [3; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 3, true); @@ -1173,10 +1189,16 @@ mod tests { let block = common::test_utils::produce_dummy_block(5, Some(prev_hash), vec![transfer_tx]); dbio.put_block(&block, [4; 32]).unwrap(); - let control_block_id1 = dbio.get_block_id_by_hash(control_hash1.0).unwrap(); - let control_block_id2 = dbio.get_block_id_by_hash(control_hash2.0).unwrap(); - let control_block_id3 = dbio.get_block_id_by_tx_hash(control_tx_hash1.0).unwrap(); - let control_block_id4 = dbio.get_block_id_by_tx_hash(control_tx_hash2.0).unwrap(); + let control_block_id1 = dbio.get_block_id_by_hash(control_hash1.0).unwrap().unwrap(); + let control_block_id2 = dbio.get_block_id_by_hash(control_hash2.0).unwrap().unwrap(); + let control_block_id3 = dbio + .get_block_id_by_tx_hash(control_tx_hash1.0) + .unwrap() + .unwrap(); + let control_block_id4 = dbio + .get_block_id_by_tx_hash(control_tx_hash2.0) + .unwrap() + .unwrap(); assert_eq!(control_block_id1, 2); assert_eq!(control_block_id2, 3); @@ -1195,7 +1217,7 @@ mod tests { RocksDBIO::open_or_create(temdir_path, &genesis_block(), &initial_state()).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 0, true); @@ -1205,7 +1227,7 @@ mod tests { dbio.put_block(&block, [1; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 1, true); @@ -1215,7 +1237,7 @@ mod tests { dbio.put_block(&block, [2; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 2, true); @@ -1225,7 +1247,7 @@ mod tests { dbio.put_block(&block, [3; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 3, true); @@ -1273,7 +1295,7 @@ mod tests { RocksDBIO::open_or_create(temdir_path, &genesis_block(), &initial_state()).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 0, true); @@ -1285,7 +1307,7 @@ mod tests { dbio.put_block(&block, [1; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 1, true); @@ -1297,7 +1319,7 @@ mod tests { dbio.put_block(&block, [2; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 2, true); @@ -1309,7 +1331,7 @@ mod tests { dbio.put_block(&block, [3; 32]).unwrap(); let last_id = dbio.get_meta_last_block_in_db().unwrap(); - let last_block = dbio.get_block(last_id).unwrap(); + let last_block = dbio.get_block(last_id).unwrap().unwrap(); let prev_hash = last_block.header.hash; let transfer_tx = transfer(1, 3, true); diff --git a/storage/src/sequencer.rs b/storage/src/sequencer.rs index 3d0190d6..143b96ce 100644 --- a/storage/src/sequencer.rs +++ b/storage/src/sequencer.rs @@ -142,7 +142,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("First block".to_owned())) + Err(DbError::db_interaction_error( + "First block not found".to_owned(), + )) } } @@ -169,7 +171,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("Last block".to_owned())) + Err(DbError::db_interaction_error( + "Last block not found".to_owned(), + )) } } @@ -395,7 +399,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("Latest block meta".to_owned())) + Err(DbError::db_interaction_error( + "Latest block meta not found".to_owned(), + )) } } @@ -436,7 +442,7 @@ impl RocksDBIO { Ok(()) } - pub fn get_block(&self, block_id: u64) -> DbResult { + pub fn get_block(&self, block_id: u64) -> DbResult> { let cf_block = self.block_column(); let res = self .db @@ -452,14 +458,14 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok(borsh::from_slice::(&data).map_err(|serr| { + Ok(Some(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message( serr, Some("Failed to deserialize block data".to_owned()), ) - })?) + })?)) } else { - Err(DbError::not_found(format!("Block with id {block_id}"))) + Ok(None) } } @@ -486,7 +492,9 @@ impl RocksDBIO { ) })?) } else { - Err(DbError::not_found("NSSA state".to_owned())) + Err(DbError::db_interaction_error( + "NSSA state not found".to_owned(), + )) } } @@ -502,7 +510,9 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))? .is_none() { - return Err(DbError::not_found(format!("Block with id {block_id}"))); + return Err(DbError::db_interaction_error(format!( + "Block with id {block_id} not found" + ))); } self.db @@ -513,7 +523,9 @@ impl RocksDBIO { } pub fn mark_block_as_finalized(&self, block_id: u64) -> DbResult<()> { - let mut block = self.get_block(block_id)?; + let mut block = self.get_block(block_id)?.ok_or_else(|| { + DbError::db_interaction_error(format!("Block with id {block_id} not found")) + })?; block.bedrock_status = BedrockStatus::Finalized; let cf_block = self.block_column(); diff --git a/wallet-ffi/Cargo.toml b/wallet-ffi/Cargo.toml index 93096e12..07169639 100644 --- a/wallet-ffi/Cargo.toml +++ b/wallet-ffi/Cargo.toml @@ -15,6 +15,7 @@ wallet.workspace = true nssa.workspace = true common.workspace = true nssa_core.workspace = true +sequencer_service_rpc = { workspace = true, features = ["client"] } tokio.workspace = true [build-dependencies] diff --git a/wallet-ffi/src/lib.rs b/wallet-ffi/src/lib.rs index c36b05e0..d84bf5a3 100644 --- a/wallet-ffi/src/lib.rs +++ b/wallet-ffi/src/lib.rs @@ -28,7 +28,7 @@ use std::sync::OnceLock; -use common::error::ExecutionFailureKind; +use ::wallet::ExecutionFailureKind; // Re-export public types for cbindgen pub use error::WalletFfiError as FfiError; use tokio::runtime::Handle; diff --git a/wallet-ffi/src/pinata.rs b/wallet-ffi/src/pinata.rs index 7c8e21d0..7ec2fc48 100644 --- a/wallet-ffi/src/pinata.rs +++ b/wallet-ffi/src/pinata.rs @@ -75,8 +75,8 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( let pinata = Pinata(&wallet); match block_on(pinata.claim(pinata_id, winner_id, solution)) { - Ok(response) => { - let tx_hash = CString::new(response.tx_hash.to_string()) + Ok(tx_hash) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -182,8 +182,8 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ pinata .claim_private_owned_account_already_initialized(pinata_id, winner_id, solution, proof), ) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash.to_string()) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -268,8 +268,8 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( let pinata = Pinata(&wallet); match block_on(pinata.claim_private_owned_account(pinata_id, winner_id, solution)) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash.to_string()) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); diff --git a/wallet-ffi/src/sync.rs b/wallet-ffi/src/sync.rs index c321feb0..41031d06 100644 --- a/wallet-ffi/src/sync.rs +++ b/wallet-ffi/src/sync.rs @@ -1,5 +1,7 @@ //! Block synchronization functions. +use sequencer_service_rpc::RpcClient as _; + use crate::{ block_on, error::{print_error, WalletFfiError}, @@ -134,10 +136,10 @@ pub unsafe extern "C" fn wallet_ffi_get_current_block_height( } }; - match block_on(wallet.sequencer_client.get_last_block()) { - Ok(response) => { + match block_on(wallet.sequencer_client.get_last_block_id()) { + Ok(last_block_id) => { unsafe { - *out_block_height = response.last_block; + *out_block_height = last_block_id; } WalletFfiError::Success } diff --git a/wallet-ffi/src/transfer.rs b/wallet-ffi/src/transfer.rs index da1892dd..5b1e27d2 100644 --- a/wallet-ffi/src/transfer.rs +++ b/wallet-ffi/src/transfer.rs @@ -73,8 +73,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_public_transfer(from_id, to_id, amount)) { - Ok(response) => { - let tx_hash = CString::new(response.tx_hash.to_string()) + Ok(tx_hash) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -163,8 +163,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( match block_on( transfer.send_shielded_transfer_to_outer_account(from_id, to_npk, to_vpk, amount), ) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -244,8 +244,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_deshielded_transfer(from_id, to_id, amount)) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -333,8 +333,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( match block_on(transfer.send_private_transfer_to_outer_account(from_id, to_npk, to_vpk, amount)) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -417,8 +417,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_shielded_transfer(from_id, to_id, amount)) { - Ok((response, _shared_key)) => { - let tx_hash = CString::new(response.tx_hash) + Ok((tx_hash, _shared_key)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -501,8 +501,8 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_private_transfer_to_owned_account(from_id, to_id, amount)) { - Ok((response, _shared_keys)) => { - let tx_hash = CString::new(response.tx_hash) + Ok((tx_hash, _shared_keys)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -573,8 +573,8 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.register_account(account_id)) { - Ok(response) => { - let tx_hash = CString::new(response.tx_hash.to_string()) + Ok(tx_hash) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); @@ -645,8 +645,8 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.register_account_private(account_id)) { - Ok((res, _secret)) => { - let tx_hash = CString::new(res.tx_hash) + Ok((tx_hash, _secret)) => { + let tx_hash = CString::new(tx_hash.to_string()) .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 63e14bb6..e4eedd2e 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -12,10 +12,12 @@ nssa_core.workspace = true nssa.workspace = true common.workspace = true key_protocol.workspace = true +sequencer_service_rpc = { workspace = true, features = ["client"] } token_core.workspace = true amm_core.workspace = true anyhow.workspace = true +thiserror.workspace = true serde_json.workspace = true env_logger.workspace = true log.workspace = true diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index c7d76f24..7e90b1bd 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -3,6 +3,7 @@ use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::key_tree::chain_index::ChainIndex; use nssa::{Account, PublicKey, program::Program}; +use sequencer_service_rpc::RpcClient; use token_core::{TokenDefinition, TokenHolding}; use crate::{ @@ -244,11 +245,7 @@ impl WalletSubcommand for AccountSubcommand { } Self::New(new_subcommand) => new_subcommand.handle_subcommand(wallet_core).await, Self::SyncPrivate => { - let curr_last_block = wallet_core - .sequencer_client - .get_last_block() - .await? - .last_block; + let curr_last_block = wallet_core.sequencer_client.get_last_block_id().await?; if wallet_core .storage diff --git a/wallet/src/cli/chain.rs b/wallet/src/cli/chain.rs index 4beadbbc..dfb22eba 100644 --- a/wallet/src/cli/chain.rs +++ b/wallet/src/cli/chain.rs @@ -1,6 +1,7 @@ use anyhow::Result; use clap::Subcommand; use common::HashType; +use sequencer_service_rpc::RpcClient as _; use crate::{ WalletCore, @@ -32,22 +33,19 @@ impl WalletSubcommand for ChainSubcommand { ) -> Result { match self { Self::CurrentBlockId => { - let latest_block_res = wallet_core.sequencer_client.get_last_block().await?; + let latest_block_id = wallet_core.sequencer_client.get_last_block_id().await?; - println!("Last block id is {}", latest_block_res.last_block); + println!("Last block id is {latest_block_id}"); } Self::Block { id } => { - let block_res = wallet_core.sequencer_client.get_block(id).await?; + let block = wallet_core.sequencer_client.get_block(id).await?; - println!("Last block id is {:#?}", block_res.block); + println!("Last block id is {block:#?}"); } Self::Transaction { hash } => { - let tx_res = wallet_core - .sequencer_client - .get_transaction_by_hash(hash) - .await?; + let tx = wallet_core.sequencer_client.get_transaction(hash).await?; - println!("Last block id is {:#?}", tx_res.transaction); + println!("Transaction is {tx:#?}"); } } Ok(SubcommandReturnValue::Empty) diff --git a/wallet/src/cli/mod.rs b/wallet/src/cli/mod.rs index 58d77d6a..221f5539 100644 --- a/wallet/src/cli/mod.rs +++ b/wallet/src/cli/mod.rs @@ -1,9 +1,11 @@ -use std::{io::Write as _, path::PathBuf, sync::Arc}; +use std::{io::Write as _, path::PathBuf}; use anyhow::{Context as _, Result}; use clap::{Parser, Subcommand}; -use common::HashType; +use common::{HashType, transaction::NSSATransaction}; +use futures::TryFutureExt; use nssa::{ProgramDeploymentTransaction, program::Program}; +use sequencer_service_rpc::RpcClient as _; use crate::{ WalletCore, @@ -175,7 +177,7 @@ pub async fn execute_subcommand( let transaction = ProgramDeploymentTransaction::new(message); let _response = wallet_core .sequencer_client - .send_tx_program(transaction) + .send_transaction(NSSATransaction::ProgramDeployment(transaction)) .await .context("Transaction submission error")?; @@ -188,11 +190,7 @@ pub async fn execute_subcommand( pub async fn execute_continuous_run(wallet_core: &mut WalletCore) -> Result<()> { loop { - let latest_block_num = wallet_core - .sequencer_client - .get_last_block() - .await? - .last_block; + let latest_block_num = wallet_core.sequencer_client.get_last_block_id().await?; wallet_core.sync_to_block(latest_block_num).await?; tokio::time::sleep(wallet_core.config().seq_poll_timeout).await; @@ -230,16 +228,17 @@ pub async fn execute_keys_restoration(wallet_core: &mut WalletCore, depth: u32) .storage .user_data .public_key_tree - .cleanup_tree_remove_uninit_layered(depth, Arc::clone(&wallet_core.sequencer_client)) + .cleanup_tree_remove_uninit_layered(depth, |account_id| { + wallet_core + .sequencer_client + .get_account(account_id) + .map_err(Into::into) + }) .await?; println!("Public tree cleaned up"); - let last_block = wallet_core - .sequencer_client - .get_last_block() - .await? - .last_block; + let last_block = wallet_core.sequencer_client.get_last_block_id().await?; println!("Last block is {last_block}"); diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/wallet/src/cli/programs/native_token_transfer.rs index 314f78ba..910c6914 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/wallet/src/cli/programs/native_token_transfer.rs @@ -58,14 +58,13 @@ impl WalletSubcommand for AuthTransferSubcommand { AccountPrivacyKind::Public => { let account_id = account_id.parse()?; - let res = NativeTokenTransfer(wallet_core) + let tx_hash = NativeTokenTransfer(wallet_core) .register_account(account_id) .await?; - println!("Results of tx send are {res:#?}"); + println!("Results of tx send are {tx_hash:#?}"); - let transfer_tx = - wallet_core.poll_native_token_transfer(res.tx_hash).await?; + let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; println!("Transaction data is {transfer_tx:?}"); @@ -74,13 +73,12 @@ impl WalletSubcommand for AuthTransferSubcommand { AccountPrivacyKind::Private => { let account_id = account_id.parse()?; - let (res, secret) = NativeTokenTransfer(wallet_core) + let (tx_hash, secret) = NativeTokenTransfer(wallet_core) .register_account_private(account_id) .await?; - println!("Results of tx send are {res:#?}"); + println!("Results of tx send are {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -311,13 +309,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let from: AccountId = from.parse().unwrap(); let to: AccountId = to.parse().unwrap(); - let (res, [secret_from, secret_to]) = NativeTokenTransfer(wallet_core) + let (tx_hash, [secret_from, secret_to]) = NativeTokenTransfer(wallet_core) .send_private_transfer_to_owned_account(from, to, amount) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -351,13 +348,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let to_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec()); - let (res, [secret_from, _]) = NativeTokenTransfer(wallet_core) + let (tx_hash, [secret_from, _]) = NativeTokenTransfer(wallet_core) .send_private_transfer_to_outer_account(from, to_npk, to_vpk, amount) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -387,13 +383,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let from: AccountId = from.parse().unwrap(); let to: AccountId = to.parse().unwrap(); - let (res, secret) = NativeTokenTransfer(wallet_core) + let (tx_hash, secret) = NativeTokenTransfer(wallet_core) .send_shielded_transfer(from, to, amount) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -428,13 +423,11 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec()); - let (res, _) = NativeTokenTransfer(wallet_core) + let (tx_hash, _) = NativeTokenTransfer(wallet_core) .send_shielded_transfer_to_outer_account(from, to_npk, to_vpk, amount) .await?; - println!("Results of tx send are {res:#?}"); - - let tx_hash = res.tx_hash; + println!("Transaction hash is {tx_hash:#?}"); wallet_core.store_persistent_data().await?; @@ -460,13 +453,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let from: AccountId = from.parse().unwrap(); let to: AccountId = to.parse().unwrap(); - let (res, secret) = NativeTokenTransfer(wallet_core) + let (tx_hash, secret) = NativeTokenTransfer(wallet_core) .send_deshielded_transfer(from, to, amount) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -486,13 +478,13 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let from: AccountId = from.parse().unwrap(); let to: AccountId = to.parse().unwrap(); - let res = NativeTokenTransfer(wallet_core) + let tx_hash = NativeTokenTransfer(wallet_core) .send_public_transfer(from, to, amount) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?; + let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; println!("Transaction data is {transfer_tx:?}"); diff --git a/wallet/src/cli/programs/pinata.rs b/wallet/src/cli/programs/pinata.rs index 948da9c2..9dba482c 100644 --- a/wallet/src/cli/programs/pinata.rs +++ b/wallet/src/cli/programs/pinata.rs @@ -112,13 +112,12 @@ impl WalletSubcommand for PinataProgramSubcommandPublic { .await .context("failed to compute solution")?; - let res = Pinata(wallet_core) + let tx_hash = Pinata(wallet_core) .claim(pinata_account_id, winner_account_id, solution) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; println!("Transaction data is {transfer_tx:?}"); @@ -148,13 +147,12 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { .await .context("failed to compute solution")?; - let (res, secret_winner) = Pinata(wallet_core) + let (tx_hash, secret_winner) = Pinata(wallet_core) .claim_private_owned_account(pinata_account_id, winner_account_id, solution) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; println!("Transaction data is {transfer_tx:?}"); diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index 65a283dd..cd5ec4b2 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -713,7 +713,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let sender_account_id: AccountId = sender_account_id.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); - let (res, [secret_sender, secret_recipient]) = Token(wallet_core) + let (tx_hash, [secret_sender, secret_recipient]) = Token(wallet_core) .send_transfer_transaction_private_owned_account( sender_account_id, recipient_account_id, @@ -721,9 +721,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -761,7 +760,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { recipient_vpk.to_vec(), ); - let (res, [secret_sender, _]) = Token(wallet_core) + let (tx_hash, [secret_sender, _]) = Token(wallet_core) .send_transfer_transaction_private_foreign_account( sender_account_id, recipient_npk, @@ -770,9 +769,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -796,7 +794,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, [secret_definition, secret_holder]) = Token(wallet_core) + let (tx_hash, [secret_definition, secret_holder]) = Token(wallet_core) .send_burn_transaction_private_owned_account( definition_account_id, holder_account_id, @@ -804,9 +802,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -833,7 +830,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, [secret_definition, secret_holder]) = Token(wallet_core) + let (tx_hash, [secret_definition, secret_holder]) = Token(wallet_core) .send_mint_transaction_private_owned_account( definition_account_id, holder_account_id, @@ -841,9 +838,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -882,7 +878,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { holder_vpk.to_vec(), ); - let (res, [secret_definition, _]) = Token(wallet_core) + let (tx_hash, [secret_definition, _]) = Token(wallet_core) .send_mint_transaction_private_foreign_account( definition_account_id, holder_npk, @@ -891,9 +887,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -927,7 +922,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let sender_account_id: AccountId = sender_account_id.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); - let (res, secret_sender) = Token(wallet_core) + let (tx_hash, secret_sender) = Token(wallet_core) .send_transfer_transaction_deshielded( sender_account_id, recipient_account_id, @@ -935,9 +930,8 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -961,7 +955,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, secret_definition) = Token(wallet_core) + let (tx_hash, secret_definition) = Token(wallet_core) .send_burn_transaction_deshielded_owned_account( definition_account_id, holder_account_id, @@ -969,9 +963,8 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -995,7 +988,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, secret_definition) = Token(wallet_core) + let (tx_hash, secret_definition) = Token(wallet_core) .send_mint_transaction_deshielded( definition_account_id, holder_account_id, @@ -1003,9 +996,8 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1050,7 +1042,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { recipient_vpk.to_vec(), ); - let (res, _) = Token(wallet_core) + let (tx_hash, _) = Token(wallet_core) .send_transfer_transaction_shielded_foreign_account( sender_account_id, recipient_npk, @@ -1059,9 +1051,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1080,7 +1071,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let sender_account_id: AccountId = sender_account_id.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); - let (res, secret_recipient) = Token(wallet_core) + let (tx_hash, secret_recipient) = Token(wallet_core) .send_transfer_transaction_shielded_owned_account( sender_account_id, recipient_account_id, @@ -1088,9 +1079,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1114,7 +1104,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, secret_holder) = Token(wallet_core) + let (tx_hash, secret_holder) = Token(wallet_core) .send_burn_transaction_shielded( definition_account_id, holder_account_id, @@ -1122,9 +1112,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1148,7 +1137,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let holder_account_id: AccountId = holder_account_id.parse().unwrap(); - let (res, secret_holder) = Token(wallet_core) + let (tx_hash, secret_holder) = Token(wallet_core) .send_mint_transaction_shielded_owned_account( definition_account_id, holder_account_id, @@ -1156,9 +1145,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1194,7 +1182,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { holder_vpk.to_vec(), ); - let (res, _) = Token(wallet_core) + let (tx_hash, _) = Token(wallet_core) .send_mint_transaction_shielded_foreign_account( definition_account_id, holder_npk, @@ -1203,9 +1191,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1235,7 +1222,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); - let (res, [secret_definition, secret_supply]) = Token(wallet_core) + let (tx_hash, [secret_definition, secret_supply]) = Token(wallet_core) .send_new_definition_private_owned_definiton_and_supply( definition_account_id, supply_account_id, @@ -1244,9 +1231,8 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1274,7 +1260,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); - let (res, secret_definition) = Token(wallet_core) + let (tx_hash, secret_definition) = Token(wallet_core) .send_new_definition_private_owned_definiton( definition_account_id, supply_account_id, @@ -1283,9 +1269,8 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { @@ -1310,7 +1295,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let definition_account_id: AccountId = definition_account_id.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap(); - let (res, secret_supply) = Token(wallet_core) + let (tx_hash, secret_supply) = Token(wallet_core) .send_new_definition_private_owned_supply( definition_account_id, supply_account_id, @@ -1319,9 +1304,8 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Results of tx send are {res:#?}"); + println!("Transaction hash is {tx_hash:#?}"); - let tx_hash = res.tx_hash; let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index d873b357..e2bb6a8a 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -8,15 +8,11 @@ reason = "Most of the shadows come from args parsing which is ok" )] -use std::{path::PathBuf, sync::Arc}; +use std::path::PathBuf; use anyhow::{Context as _, Result}; -use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64}; use chain_storage::WalletChainStore; -use common::{ - HashType, error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse, - sequencer_client::SequencerClient, transaction::NSSATransaction, -}; +use common::{HashType, transaction::NSSATransaction}; use config::WalletConfig; use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode as _}; use log::info; @@ -28,6 +24,7 @@ use nssa::{ }; use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData}; pub use privacy_preserving_tx::PrivacyPreservingAccount; +use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; use tokio::io::AsyncWriteExt as _; use crate::{ @@ -59,8 +56,8 @@ pub enum ExecutionFailureKind { AmountMismatchError, #[error("Accounts key not found")] KeyNotFoundError, - #[error("Sequencer client error: {0:?}")] - SequencerClientError(#[from] SequencerClientError), + #[error("Sequencer client error")] + SequencerClientError(#[from] sequencer_service_rpc::ClientError), #[error("Can not pay for operation")] InsufficientFundsError, #[error("Account {0} data is invalid")] @@ -74,7 +71,7 @@ pub struct WalletCore { storage: WalletChainStore, storage_path: PathBuf, poller: TxPoller, - pub sequencer_client: Arc, + pub sequencer_client: SequencerClient, pub last_synced_block: u64, } @@ -145,11 +142,26 @@ impl WalletCore { config.apply_overrides(config_overrides); } - let sequencer_client = Arc::new(SequencerClient::new_with_auth( - config.sequencer_addr.clone(), - config.basic_auth.clone(), - )?); - let tx_poller = TxPoller::new(&config, Arc::clone(&sequencer_client)); + let sequencer_client = { + let mut builder = SequencerClientBuilder::default(); + if let Some(basic_auth) = &config.basic_auth { + builder = builder.set_headers( + [( + "Authorization".parse().expect("Header name is valid"), + format!("Basic {}", basic_auth) + .parse() + .context("Invalid basic auth format")?, + )] + .into_iter() + .collect(), + ); + } + builder + .build(config.sequencer_addr.clone()) + .context("Failed to create sequencer client")? + }; + + let tx_poller = TxPoller::new(&config, sequencer_client.clone()); let storage = storage_ctor(config)?; @@ -238,26 +250,17 @@ impl WalletCore { /// Get account balance. pub async fn get_account_balance(&self, acc: AccountId) -> Result { - Ok(self - .sequencer_client - .get_account_balance(acc) - .await? - .balance) + Ok(self.sequencer_client.get_account_balance(acc).await?) } /// Get accounts nonces. pub async fn get_accounts_nonces(&self, accs: Vec) -> Result> { - Ok(self - .sequencer_client - .get_accounts_nonces(accs) - .await? - .nonces) + Ok(self.sequencer_client.get_accounts_nonces(accs).await?) } /// Get account. pub async fn get_account_public(&self, account_id: AccountId) -> Result { - let response = self.sequencer_client.get_account(account_id).await?; - Ok(response.account) + Ok(self.sequencer_client.get_account(account_id).await?) } #[must_use] @@ -286,11 +289,7 @@ impl WalletCore { /// Poll transactions. pub async fn poll_native_token_transfer(&self, hash: HashType) -> Result { - let transaction_encoded = self.poller.poll_tx(hash).await?; - let tx_base64_decode = BASE64.decode(transaction_encoded)?; - let pub_tx = borsh::from_slice::(&tx_base64_decode).unwrap(); - - Ok(pub_tx) + self.poller.poll_tx(hash).await } pub async fn check_private_account_initialized( @@ -301,6 +300,7 @@ impl WalletCore { self.sequencer_client .get_proof_for_commitment(acc_comm) .await + .map(Some) .map_err(anyhow::Error::from) } else { Ok(None) @@ -351,7 +351,7 @@ impl WalletCore { accounts: Vec, instruction_data: InstructionData, program: &ProgramWithDependencies, - ) -> Result<(SendTxResponse, Vec), ExecutionFailureKind> { + ) -> Result<(HashType, Vec), ExecutionFailureKind> { self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| { Ok(()) }) @@ -364,7 +364,7 @@ impl WalletCore { instruction_data: InstructionData, program: &ProgramWithDependencies, tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>, - ) -> Result<(SendTxResponse, Vec), ExecutionFailureKind> { + ) -> Result<(HashType, Vec), ExecutionFailureKind> { let acc_manager = privacy_preserving_tx::AccountManager::new(self, accounts).await?; let pre_states = acc_manager.pre_states(); @@ -416,7 +416,9 @@ impl WalletCore { .collect(); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client + .send_transaction(NSSATransaction::PrivacyPreserving(tx)) + .await?, shared_secrets, )) } @@ -443,11 +445,11 @@ impl WalletCore { let bar = indicatif::ProgressBar::new(num_of_blocks); while let Some(block) = blocks.try_next().await? { - for tx in block.transactions { + for tx in block.body.transactions { self.sync_private_accounts_with_tx(tx); } - self.last_synced_block = block.block_id; + self.last_synced_block = block.header.block_id; self.store_persistent_data().await?; bar.inc(1); } diff --git a/wallet/src/pinata_interactions.rs b/wallet/src/pinata_interactions.rs index abcfcf6a..22595a89 100644 --- a/wallet/src/pinata_interactions.rs +++ b/wallet/src/pinata_interactions.rs @@ -1,10 +1,12 @@ -use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; +use sequencer_service_rpc::RpcClient as _; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{AccountId, privacy_preserving_transaction::circuit}; use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata}; use crate::{ - WalletCore, helperfunctions::produce_random_nonces, transaction_utils::AccountPreparedData, + ExecutionFailureKind, WalletCore, helperfunctions::produce_random_nonces, + transaction_utils::AccountPreparedData, }; impl WalletCore { @@ -13,7 +15,7 @@ impl WalletCore { pinata_account_id: AccountId, winner_account_id: AccountId, solution: u128, - ) -> Result { + ) -> Result { let account_ids = vec![pinata_account_id, winner_account_id]; let program_id = nssa::program::Program::pinata().id(); let message = @@ -23,7 +25,7 @@ impl WalletCore { let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.sequencer_client.send_tx_public(tx).await?) + Ok(self.sequencer_client.send_transaction(NSSATransaction::Public(tx)).await?) } pub async fn claim_pinata_private_owned_account_already_initialized( @@ -32,7 +34,7 @@ impl WalletCore { winner_account_id: AccountId, solution: u128, winner_proof: MembershipProof, - ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { nsk: winner_nsk, npk: winner_npk, @@ -89,7 +91,7 @@ impl WalletCore { ); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_winner], )) } @@ -99,7 +101,7 @@ impl WalletCore { pinata_account_id: AccountId, winner_account_id: AccountId, solution: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { nsk: _, npk: winner_npk, @@ -156,7 +158,7 @@ impl WalletCore { ); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_winner], )) } diff --git a/wallet/src/poller.rs b/wallet/src/poller.rs index 113f42ee..7dbd59c1 100644 --- a/wallet/src/poller.rs +++ b/wallet/src/poller.rs @@ -1,8 +1,9 @@ -use std::{sync::Arc, time::Duration}; +use std::time::Duration; use anyhow::Result; -use common::{HashType, block::HashableBlockData, sequencer_client::SequencerClient}; +use common::{HashType, block::Block, transaction::NSSATransaction}; use log::{info, warn}; +use sequencer_service_rpc::{RpcClient as _, SequencerClient}; use crate::config::WalletConfig; @@ -13,12 +14,12 @@ pub struct TxPoller { polling_max_error_attempts: u64, polling_delay: Duration, block_poll_max_amount: u64, - client: Arc, + client: SequencerClient, } impl TxPoller { #[must_use] - pub const fn new(config: &WalletConfig, client: Arc) -> Self { + pub const fn new(config: &WalletConfig, client: SequencerClient) -> Self { Self { polling_delay: config.seq_poll_timeout, polling_max_blocks_to_query: config.seq_tx_poll_max_blocks, @@ -29,7 +30,7 @@ impl TxPoller { } // TODO: this polling is not based on blocks, but on timeouts, need to fix this. - pub async fn poll_tx(&self, tx_hash: HashType) -> Result { + pub async fn poll_tx(&self, tx_hash: HashType) -> Result { let max_blocks_to_query = self.polling_max_blocks_to_query; info!("Starting poll for transaction {tx_hash}"); @@ -38,29 +39,22 @@ impl TxPoller { let mut try_error_counter = 0_u64; - let tx_obj = loop { - let tx_obj = self - .client - .get_transaction_by_hash(tx_hash) - .await - .inspect_err(|err| { + loop { + match self.client.get_transaction(tx_hash).await { + Ok(Some(tx)) => return Ok(tx), + Ok(None) => {} + Err(err) => { warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}"); - }); - - if let Ok(tx_obj) = tx_obj { - break tx_obj; + } } + try_error_counter = try_error_counter .checked_add(1) .expect("We check error counter in this loop"); if try_error_counter > self.polling_max_error_attempts { - anyhow::bail!("Number of retries exceeded"); + break; } - }; - - if let Some(tx) = tx_obj.transaction { - return Ok(tx); } tokio::time::sleep(self.polling_delay).await; @@ -72,16 +66,15 @@ impl TxPoller { pub fn poll_block_range( &self, range: std::ops::RangeInclusive, - ) -> impl futures::Stream> { + ) -> impl futures::Stream> { async_stream::stream! { let mut chunk_start = *range.start(); loop { let chunk_end = std::cmp::min(chunk_start.saturating_add(self.block_poll_max_amount).saturating_sub(1), *range.end()); - let blocks = self.client.get_block_range(chunk_start..=chunk_end).await?.blocks; + let blocks = self.client.get_block_range(chunk_start, chunk_end).await?; for block in blocks { - let block = borsh::from_slice::(&block)?; yield Ok(block); } diff --git a/wallet/src/privacy_preserving_tx.rs b/wallet/src/privacy_preserving_tx.rs index 0aaffa9a..04056111 100644 --- a/wallet/src/privacy_preserving_tx.rs +++ b/wallet/src/privacy_preserving_tx.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use common::error::ExecutionFailureKind; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{AccountId, PrivateKey}; use nssa_core::{ @@ -8,7 +7,7 @@ use nssa_core::{ encryption::{EphemeralPublicKey, ViewingPublicKey}, }; -use crate::WalletCore; +use crate::{ExecutionFailureKind, WalletCore}; #[derive(Clone)] pub enum PrivacyPreservingAccount { diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 19a51f29..c430f29d 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -1,9 +1,10 @@ use amm_core::{compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda}; -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; use nssa::{AccountId, program::Program}; +use sequencer_service_rpc::RpcClient as _; use token_core::TokenHolding; -use crate::WalletCore; +use crate::{ExecutionFailureKind, WalletCore}; pub struct Amm<'wallet>(pub &'wallet WalletCore); impl Amm<'_> { @@ -14,7 +15,7 @@ impl Amm<'_> { user_holding_lp: AccountId, balance_a: u128, balance_b: u128, - ) -> Result { + ) -> Result { let program = Program::amm(); let amm_program_id = Program::amm().id(); let instruction = amm_core::Instruction::NewDefinition { @@ -95,7 +96,11 @@ impl Amm<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_swap( @@ -105,7 +110,7 @@ impl Amm<'_> { swap_amount_in: u128, min_amount_out: u128, token_definition_id_in: AccountId, - ) -> Result { + ) -> Result { let instruction = amm_core::Instruction::Swap { swap_amount_in, min_amount_out, @@ -203,7 +208,11 @@ impl Amm<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_add_liquidity( @@ -214,7 +223,7 @@ impl Amm<'_> { min_amount_liquidity: u128, max_amount_to_add_token_a: u128, max_amount_to_add_token_b: u128, - ) -> Result { + ) -> Result { let instruction = amm_core::Instruction::AddLiquidity { min_amount_liquidity, max_amount_to_add_token_a, @@ -295,7 +304,11 @@ impl Amm<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_remove_liquidity( @@ -306,7 +319,7 @@ impl Amm<'_> { remove_liquidity_amount: u128, min_amount_to_remove_token_a: u128, min_amount_to_remove_token_b: u128, - ) -> Result { + ) -> Result { let instruction = amm_core::Instruction::RemoveLiquidity { remove_liquidity_amount, min_amount_to_remove_token_a, @@ -378,6 +391,10 @@ impl Amm<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } } diff --git a/wallet/src/program_facades/native_token_transfer/deshielded.rs b/wallet/src/program_facades/native_token_transfer/deshielded.rs index 7b774595..d51f15ce 100644 --- a/wallet/src/program_facades/native_token_transfer/deshielded.rs +++ b/wallet/src/program_facades/native_token_transfer/deshielded.rs @@ -1,8 +1,8 @@ -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::HashType; use nssa::AccountId; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::PrivacyPreservingAccount; +use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; impl NativeTokenTransfer<'_> { pub async fn send_deshielded_transfer( @@ -10,7 +10,7 @@ impl NativeTokenTransfer<'_> { from: AccountId, to: AccountId, balance_to_move: u128, - ) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, nssa_core::SharedSecretKey), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 diff --git a/wallet/src/program_facades/native_token_transfer/mod.rs b/wallet/src/program_facades/native_token_transfer/mod.rs index 1db864f6..72be949a 100644 --- a/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/wallet/src/program_facades/native_token_transfer/mod.rs @@ -1,8 +1,7 @@ -use common::error::ExecutionFailureKind; use nssa::{Account, program::Program}; use nssa_core::program::InstructionData; -use crate::WalletCore; +use crate::{ExecutionFailureKind, WalletCore}; pub mod deshielded; pub mod private; diff --git a/wallet/src/program_facades/native_token_transfer/private.rs b/wallet/src/program_facades/native_token_transfer/private.rs index eb37ec94..c3a2125b 100644 --- a/wallet/src/program_facades/native_token_transfer/private.rs +++ b/wallet/src/program_facades/native_token_transfer/private.rs @@ -1,17 +1,17 @@ use std::vec; -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::HashType; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::PrivacyPreservingAccount; +use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; impl NativeTokenTransfer<'_> { pub async fn register_account_private( &self, from: AccountId, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction: u128 = 0; self.0 @@ -34,7 +34,7 @@ impl NativeTokenTransfer<'_> { to_npk: NullifierPublicKey, to_vpk: ViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 @@ -64,7 +64,7 @@ impl NativeTokenTransfer<'_> { from: AccountId, to: AccountId, balance_to_move: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 diff --git a/wallet/src/program_facades/native_token_transfer/public.rs b/wallet/src/program_facades/native_token_transfer/public.rs index eefaa1fe..a54a215f 100644 --- a/wallet/src/program_facades/native_token_transfer/public.rs +++ b/wallet/src/program_facades/native_token_transfer/public.rs @@ -1,11 +1,13 @@ -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; use nssa::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; +use sequencer_service_rpc::RpcClient as _; use super::NativeTokenTransfer; +use crate::ExecutionFailureKind; impl NativeTokenTransfer<'_> { pub async fn send_public_transfer( @@ -13,7 +15,7 @@ impl NativeTokenTransfer<'_> { from: AccountId, to: AccountId, balance_to_move: u128, - ) -> Result { + ) -> Result { let balance = self .0 .get_account_balance(from) @@ -50,7 +52,11 @@ impl NativeTokenTransfer<'_> { let tx = PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } else { Err(ExecutionFailureKind::InsufficientFundsError) } @@ -59,7 +65,7 @@ impl NativeTokenTransfer<'_> { pub async fn register_account( &self, from: AccountId, - ) -> Result { + ) -> Result { let nonces = self .0 .get_accounts_nonces(vec![from]) @@ -90,6 +96,10 @@ impl NativeTokenTransfer<'_> { let tx = PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } } diff --git a/wallet/src/program_facades/native_token_transfer/shielded.rs b/wallet/src/program_facades/native_token_transfer/shielded.rs index 22897502..625e1a8b 100644 --- a/wallet/src/program_facades/native_token_transfer/shielded.rs +++ b/wallet/src/program_facades/native_token_transfer/shielded.rs @@ -1,9 +1,9 @@ -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::HashType; use nssa::AccountId; use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; -use crate::PrivacyPreservingAccount; +use crate::{ExecutionFailureKind, PrivacyPreservingAccount}; impl NativeTokenTransfer<'_> { pub async fn send_shielded_transfer( @@ -11,7 +11,7 @@ impl NativeTokenTransfer<'_> { from: AccountId, to: AccountId, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 @@ -40,7 +40,7 @@ impl NativeTokenTransfer<'_> { to_npk: NullifierPublicKey, to_vpk: ViewingPublicKey, balance_to_move: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 diff --git a/wallet/src/program_facades/pinata.rs b/wallet/src/program_facades/pinata.rs index c68fa658..97118ecd 100644 --- a/wallet/src/program_facades/pinata.rs +++ b/wallet/src/program_facades/pinata.rs @@ -1,8 +1,9 @@ -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; use nssa::AccountId; use nssa_core::{MembershipProof, SharedSecretKey}; +use sequencer_service_rpc::RpcClient as _; -use crate::{PrivacyPreservingAccount, WalletCore}; +use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore}; pub struct Pinata<'wallet>(pub &'wallet WalletCore); @@ -12,7 +13,7 @@ impl Pinata<'_> { pinata_account_id: AccountId, winner_account_id: AccountId, solution: u128, - ) -> Result { + ) -> Result { let account_ids = vec![pinata_account_id, winner_account_id]; let program_id = nssa::program::Program::pinata().id(); let message = @@ -22,7 +23,11 @@ impl Pinata<'_> { let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } /// Claim a pinata reward using a privacy-preserving transaction for an already-initialized @@ -36,7 +41,7 @@ impl Pinata<'_> { winner_account_id: AccountId, solution: u128, _winner_proof: MembershipProof, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { self.claim_private_owned_account(pinata_account_id, winner_account_id, solution) .await } @@ -46,7 +51,7 @@ impl Pinata<'_> { pinata_account_id: AccountId, winner_account_id: AccountId, solution: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { self.0 .send_privacy_preserving_tx( vec![ diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index bdacae37..ca36e723 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -1,9 +1,10 @@ -use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; use nssa::{AccountId, program::Program}; use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; +use sequencer_service_rpc::RpcClient as _; use token_core::Instruction; -use crate::{PrivacyPreservingAccount, WalletCore}; +use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore}; pub struct Token<'wallet>(pub &'wallet WalletCore); @@ -14,7 +15,7 @@ impl Token<'_> { supply_account_id: AccountId, name: String, total_supply: u128, - ) -> Result { + ) -> Result { let account_ids = vec![definition_account_id, supply_account_id]; let program_id = nssa::program::Program::token().id(); let instruction = Instruction::NewFungibleDefinition { name, total_supply }; @@ -30,7 +31,11 @@ impl Token<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_new_definition_private_owned_supply( @@ -39,7 +44,7 @@ impl Token<'_> { supply_account_id: AccountId, name: String, total_supply: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -69,7 +74,7 @@ impl Token<'_> { supply_account_id: AccountId, name: String, total_supply: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -99,7 +104,7 @@ impl Token<'_> { supply_account_id: AccountId, name: String, total_supply: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -127,7 +132,7 @@ impl Token<'_> { sender_account_id: AccountId, recipient_account_id: AccountId, amount: u128, - ) -> Result { + ) -> Result { let account_ids = vec![sender_account_id, recipient_account_id]; let program_id = nssa::program::Program::token().id(); let instruction = Instruction::Transfer { @@ -162,7 +167,11 @@ impl Token<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_transfer_transaction_private_owned_account( @@ -170,7 +179,7 @@ impl Token<'_> { sender_account_id: AccountId, recipient_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -201,7 +210,7 @@ impl Token<'_> { recipient_npk: NullifierPublicKey, recipient_vpk: ViewingPublicKey, amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -234,7 +243,7 @@ impl Token<'_> { sender_account_id: AccountId, recipient_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -265,7 +274,7 @@ impl Token<'_> { sender_account_id: AccountId, recipient_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -297,7 +306,7 @@ impl Token<'_> { recipient_npk: NullifierPublicKey, recipient_vpk: ViewingPublicKey, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -331,7 +340,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result { + ) -> Result { let account_ids = vec![definition_account_id, holder_account_id]; let instruction = Instruction::Burn { amount_to_burn: amount, @@ -364,7 +373,11 @@ impl Token<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_burn_transaction_private_owned_account( @@ -372,7 +385,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::Burn { amount_to_burn: amount, }; @@ -402,7 +415,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Burn { amount_to_burn: amount, }; @@ -433,7 +446,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Burn { amount_to_burn: amount, }; @@ -464,7 +477,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result { + ) -> Result { let account_ids = vec![definition_account_id, holder_account_id]; let instruction = Instruction::Mint { amount_to_mint: amount, @@ -499,7 +512,11 @@ impl Token<'_> { let tx = nssa::PublicTransaction::new(message, witness_set); - Ok(self.0.sequencer_client.send_tx_public(tx).await?) + Ok(self + .0 + .sequencer_client + .send_transaction(NSSATransaction::Public(tx)) + .await?) } pub async fn send_mint_transaction_private_owned_account( @@ -507,7 +524,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::Mint { amount_to_mint: amount, }; @@ -538,7 +555,7 @@ impl Token<'_> { holder_npk: NullifierPublicKey, holder_vpk: ViewingPublicKey, amount: u128, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let instruction = Instruction::Mint { amount_to_mint: amount, }; @@ -571,7 +588,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Mint { amount_to_mint: amount, }; @@ -602,7 +619,7 @@ impl Token<'_> { definition_account_id: AccountId, holder_account_id: AccountId, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Mint { amount_to_mint: amount, }; @@ -634,7 +651,7 @@ impl Token<'_> { holder_npk: NullifierPublicKey, holder_vpk: ViewingPublicKey, amount: u128, - ) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { let instruction = Instruction::Mint { amount_to_mint: amount, }; diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 2adc3033..ab64ab28 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -1,4 +1,5 @@ -use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; +use common::{HashType, transaction::NSSATransaction}; +use sequencer_service_rpc::RpcClient as _; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{ Account, AccountId, PrivacyPreservingTransaction, @@ -10,7 +11,7 @@ use nssa_core::{ account::AccountWithMetadata, encryption::ViewingPublicKey, program::InstructionData, }; -use crate::{WalletCore, helperfunctions::produce_random_nonces}; +use crate::{ExecutionFailureKind, WalletCore, helperfunctions::produce_random_nonces}; pub(crate) struct AccountPreparedData { pub nsk: Option, @@ -51,11 +52,12 @@ impl WalletCore { } if needs_proof { - proof = self - .sequencer_client - .get_proof_for_commitment(sender_commitment) - .await - .unwrap(); + proof = Some( + self.sequencer_client + .get_proof_for_commitment(sender_commitment) + .await + .unwrap(), + ); } Ok(AccountPreparedData { @@ -75,7 +77,7 @@ impl WalletCore { tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, to_proof: MembershipProof, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let AccountPreparedData { nsk: from_nsk, npk: from_npk, @@ -140,7 +142,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_from, shared_secret_to], )) } @@ -152,7 +154,7 @@ impl WalletCore { instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let AccountPreparedData { nsk: from_nsk, npk: from_npk, @@ -214,7 +216,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_from, shared_secret_to], )) } @@ -227,7 +229,7 @@ impl WalletCore { instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, - ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { let AccountPreparedData { nsk: from_nsk, npk: from_npk, @@ -285,7 +287,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_from, shared_secret_to], )) } @@ -297,7 +299,7 @@ impl WalletCore { instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, - ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { nsk: from_nsk, npk: from_npk, @@ -345,7 +347,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret], )) } @@ -358,7 +360,7 @@ impl WalletCore { tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, to_proof: MembershipProof, - ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 1]), ExecutionFailureKind> { let Ok(from_acc) = self.get_account_public(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -412,7 +414,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret], )) } @@ -424,7 +426,7 @@ impl WalletCore { instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, - ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 1]), ExecutionFailureKind> { let Ok(from_acc) = self.get_account_public(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -478,7 +480,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret], )) } @@ -491,7 +493,7 @@ impl WalletCore { instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, - ) -> Result { + ) -> Result { let Ok(from_acc) = self.get_account_public(from).await else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -538,13 +540,13 @@ impl WalletCore { let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]); let tx = PrivacyPreservingTransaction::new(message, witness_set); - Ok(self.sequencer_client.send_tx_private(tx).await?) + Ok(self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?) } pub async fn register_account_under_authenticated_transfers_programs_private( &self, from: AccountId, - ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { + ) -> Result<(HashType, [SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { nsk: _, npk: from_npk, @@ -585,7 +587,7 @@ impl WalletCore { let tx = PrivacyPreservingTransaction::new(message, witness_set); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client.send_transaction(NSSATransaction::PrivacyPreserving(tx)).await?, [shared_secret_from], )) } From 9d87e3b04651ea1ae24aa21c4d58aa137fd2b37c Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Fri, 13 Mar 2026 22:56:14 +0300 Subject: [PATCH 04/10] fix: fix lints --- indexer/service/protocol/src/convert.rs | 2 +- integration_tests/src/lib.rs | 2 +- sequencer/core/src/lib.rs | 3 +- sequencer/service/src/lib.rs | 4 +-- sequencer/service/src/service.rs | 30 +++++++++---------- wallet/src/cli/account.rs | 2 +- wallet/src/cli/mod.rs | 2 +- wallet/src/lib.rs | 12 ++------ .../native_token_transfer/mod.rs | 5 ---- 9 files changed, 24 insertions(+), 38 deletions(-) diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index dd01e28a..6114620f 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -402,7 +402,7 @@ impl TryFrom for nssa::privacy_preserving_transaction::witness_set:: signatures_and_public_keys, proof .map(Into::into) - .ok_or_else(|| nssa::error::NssaError::InvalidInput("Missing proof".to_string()))?, + .ok_or_else(|| nssa::error::NssaError::InvalidInput("Missing proof".to_owned()))?, )) } } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 016bde21..e6d31cf6 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -38,7 +38,7 @@ pub struct TestContext { indexer_client: IndexerClient, wallet: WalletCore, wallet_password: String, - /// Optional to move out value in Drop + /// Optional to move out value in Drop. sequencer_handle: Option, indexer_handle: IndexerHandle, bedrock_compose: DockerCompose, diff --git a/sequencer/core/src/lib.rs b/sequencer/core/src/lib.rs index f3e94614..cef66033 100644 --- a/sequencer/core/src/lib.rs +++ b/sequencer/core/src/lib.rs @@ -15,6 +15,7 @@ use logos_blockchain_key_management_system_service::keys::{ED25519_SECRET_KEY_SI use mempool::{MemPool, MemPoolHandle}; #[cfg(feature = "mock")] pub use mock::SequencerCoreWithMockClients; +pub use storage::error::DbError; use crate::{ block_settlement_client::{BlockSettlementClient, BlockSettlementClientTrait, MsgId}, @@ -27,8 +28,6 @@ pub mod block_store; pub mod config; pub mod indexer_client; -pub use storage::error::DbError; - #[cfg(feature = "mock")] pub mod mock; diff --git a/sequencer/service/src/lib.rs b/sequencer/service/src/lib.rs index 8ab997d9..bc9a4ef5 100644 --- a/sequencer/service/src/lib.rs +++ b/sequencer/service/src/lib.rs @@ -34,7 +34,7 @@ pub struct SequencerHandle { } impl SequencerHandle { - fn new( + const fn new( addr: SocketAddr, server_handle: ServerHandle, main_loop_handle: JoinHandle>, @@ -67,7 +67,7 @@ impl SequencerHandle { let server_handle = server_handle.take().expect("Server handle is set"); tokio::select! { - _ = server_handle.stopped() => { + () = server_handle.stopped() => { Err(anyhow!("RPC Server stopped")) } res = main_loop_handle => { diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs index c8f17189..ab5459a7 100644 --- a/sequencer/service/src/service.rs +++ b/sequencer/service/src/service.rs @@ -23,6 +23,8 @@ use sequencer_core::{ }; use tokio::sync::Mutex; +const NOT_FOUND_ERROR_CODE: i32 = -31999; + pub struct SequencerService { sequencer: Arc>>, mempool_handle: MemPoolHandle, @@ -30,7 +32,7 @@ pub struct SequencerService SequencerService { - pub fn new( + pub const fn new( sequencer: Arc>>, mempool_handle: MemPoolHandle, max_block_size: u64, @@ -109,19 +111,17 @@ impl, - ) - }) - }) + .map_err(|err| internal_error(&err))?; + block.ok_or_else(|| { + ErrorObjectOwned::owned( + NOT_FOUND_ERROR_CODE, + format!("Block with id {block_id} not found"), + None::<()>, + ) + }) }) .collect::, _>>() } @@ -139,10 +139,10 @@ impl Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; - Ok(sequencer.block_store().get_transaction_by_hash(hash)) + Ok(sequencer.block_store().get_transaction_by_hash(tx_hash)) } async fn get_accounts_nonces( @@ -196,8 +196,6 @@ impl ErrorObjectOwned { ErrorObjectOwned::owned(ErrorCode::InternalError.code(), err.to_string(), None::<()>) } diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 7e90b1bd..2a8ed2c7 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -3,7 +3,7 @@ use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::key_tree::chain_index::ChainIndex; use nssa::{Account, PublicKey, program::Program}; -use sequencer_service_rpc::RpcClient; +use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use crate::{ diff --git a/wallet/src/cli/mod.rs b/wallet/src/cli/mod.rs index 221f5539..85e792cc 100644 --- a/wallet/src/cli/mod.rs +++ b/wallet/src/cli/mod.rs @@ -3,7 +3,7 @@ use std::{io::Write as _, path::PathBuf}; use anyhow::{Context as _, Result}; use clap::{Parser, Subcommand}; use common::{HashType, transaction::NSSATransaction}; -use futures::TryFutureExt; +use futures::TryFutureExt as _; use nssa::{ProgramDeploymentTransaction, program::Program}; use sequencer_service_rpc::RpcClient as _; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index e2bb6a8a..5ebbaf82 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -146,13 +146,12 @@ impl WalletCore { let mut builder = SequencerClientBuilder::default(); if let Some(basic_auth) = &config.basic_auth { builder = builder.set_headers( - [( + std::iter::once(( "Authorization".parse().expect("Header name is valid"), - format!("Basic {}", basic_auth) + format!("Basic {basic_auth}") .parse() .context("Invalid basic auth format")?, - )] - .into_iter() + )) .collect(), ); } @@ -341,11 +340,6 @@ impl WalletCore { Ok(()) } - // TODO: handle large Err-variant properly - #[expect( - clippy::result_large_err, - reason = "ExecutionFailureKind is large, tracked by TODO" - )] pub async fn send_privacy_preserving_tx( &self, accounts: Vec, diff --git a/wallet/src/program_facades/native_token_transfer/mod.rs b/wallet/src/program_facades/native_token_transfer/mod.rs index 72be949a..c771c735 100644 --- a/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/wallet/src/program_facades/native_token_transfer/mod.rs @@ -14,11 +14,6 @@ pub mod shielded; )] pub struct NativeTokenTransfer<'wallet>(pub &'wallet WalletCore); -// TODO: handle large Err-variant properly -#[expect( - clippy::result_large_err, - reason = "ExecutionFailureKind is large, tracked by TODO" -)] fn auth_transfer_preparation( balance_to_move: u128, ) -> ( From b631ef02c6937f4e3fc56ed15be7791fa7c76e55 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Sat, 14 Mar 2026 03:20:37 +0300 Subject: [PATCH 05/10] fix: final fixes & polishing --- Cargo.lock | 12 - Justfile | 2 +- common/Cargo.toml | 6 - integration_tests/Cargo.toml | 2 - integration_tests/src/lib.rs | 4 +- key_protocol/Cargo.toml | 4 +- .../src/key_management/secret_holders.rs | 4 +- key_protocol/src/key_protocol_core/mod.rs | 4 +- sequencer/service/Dockerfile | 4 +- sequencer/service/docker-compose.yml | 6 +- sequencer/service/rpc/Cargo.toml | 1 - sequencer/service/rpc/src/lib.rs | 2 +- sequencer/service/src/service.rs | 13 +- wallet-ffi/Cargo.toml | 1 - wallet/Cargo.toml | 2 - wallet/src/chain_storage.rs | 119 +--- .../src/cli/programs/native_token_transfer.rs | 16 +- wallet/src/cli/programs/pinata.rs | 4 +- wallet/src/cli/programs/token.rs | 32 +- wallet/src/config.rs | 518 ++---------------- wallet/src/lib.rs | 3 +- 21 files changed, 120 insertions(+), 639 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdd8395c..58b9c1cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,22 +1498,16 @@ name = "common" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.1", "borsh", - "bytesize", "hex", "log", "logos-blockchain-common-http-client", "nssa", "nssa_core", - "reqwest", "serde", - "serde_json", "serde_with", "sha2", "thiserror 2.0.18", - "tokio-retry", - "url", ] [[package]] @@ -3556,8 +3550,6 @@ name = "integration_tests" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.1", - "borsh", "bytesize", "common", "env_logger", @@ -7200,7 +7192,6 @@ dependencies = [ "jsonrpsee", "nssa", "nssa_core", - "serde_json", ] [[package]] @@ -8652,8 +8643,6 @@ dependencies = [ "anyhow", "async-stream", "base58", - "base64 0.22.1", - "borsh", "clap", "common", "env_logger", @@ -8684,7 +8673,6 @@ name = "wallet-ffi" version = "0.1.0" dependencies = [ "cbindgen", - "common", "nssa", "nssa_core", "sequencer_service_rpc", diff --git a/Justfile b/Justfile index e6eab8d9..ac003a15 100644 --- a/Justfile +++ b/Justfile @@ -33,7 +33,7 @@ run-bedrock: [working-directory: 'sequencer/service'] run-sequencer: @echo "🧠 Running sequencer" - RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_service configs/debug + RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_service configs/debug/sequencer_config.json # Run Indexer [working-directory: 'indexer/service'] diff --git a/common/Cargo.toml b/common/Cargo.toml index 8aafed40..002e0cfc 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -13,16 +13,10 @@ nssa_core.workspace = true anyhow.workspace = true thiserror.workspace = true -serde_json.workspace = true serde.workspace = true serde_with.workspace = true -reqwest.workspace = true sha2.workspace = true log.workspace = true hex.workspace = true borsh.workspace = true -bytesize.workspace = true -base64.workspace = true -url.workspace = true logos-blockchain-common-http-client.workspace = true -tokio-retry.workspace = true diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 137c9f54..c88ec1fd 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -27,11 +27,9 @@ url.workspace = true anyhow.workspace = true env_logger.workspace = true log.workspace = true -base64.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } hex.workspace = true tempfile.workspace = true -borsh.workspace = true bytesize.workspace = true futures.workspace = true testcontainers = { version = "0.27.0", features = ["docker-compose"] } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index e6d31cf6..2128a482 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -480,5 +480,7 @@ pub async fn verify_commitment_is_in_state( seq_client .get_proof_for_commitment(commitment) .await - .is_ok() + .ok() + .flatten() + .is_some() } diff --git a/key_protocol/Cargo.toml b/key_protocol/Cargo.toml index 7a16b627..5ce7e97c 100644 --- a/key_protocol/Cargo.toml +++ b/key_protocol/Cargo.toml @@ -19,10 +19,12 @@ serde.workspace = true k256.workspace = true sha2.workspace = true rand.workspace = true -base58.workspace = true hex.workspace = true aes-gcm.workspace = true bip39.workspace = true hmac-sha512.workspace = true thiserror.workspace = true itertools.workspace = true + +[dev-dependencies] +base58.workspace = true diff --git a/key_protocol/src/key_management/secret_holders.rs b/key_protocol/src/key_management/secret_holders.rs index 9643abe0..45e640da 100644 --- a/key_protocol/src/key_management/secret_holders.rs +++ b/key_protocol/src/key_management/secret_holders.rs @@ -10,16 +10,16 @@ use sha2::{Digest as _, digest::FixedOutput as _}; const NSSA_ENTROPY_BYTES: [u8; 32] = [0; 32]; -#[derive(Debug)] /// Seed holder. Non-clonable to ensure that different holders use different seeds. /// Produces `TopSecretKeyHolder` objects. +#[derive(Debug)] pub struct SeedHolder { // ToDo: Needs to be vec as serde derives is not implemented for [u8; 64] pub(crate) seed: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] /// Secret spending key object. Can produce `PrivateKeyHolder` objects. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct SecretSpendingKey(pub(crate) [u8; 32]); pub type ViewingSecretKey = Scalar; diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index 65c592e3..cb21748c 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -66,13 +66,13 @@ impl NSSAUserData { ) -> Result { if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) { anyhow::bail!( - "Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys" + "Key transaction pairing check not satisfied, there are public account_ids, which is not derived from keys" ); } if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) { anyhow::bail!( - "Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys" + "Key transaction pairing check not satisfied, there are private account_ids, which is not derived from keys" ); } diff --git a/sequencer/service/Dockerfile b/sequencer/service/Dockerfile index 73db0336..414d4889 100644 --- a/sequencer/service/Dockerfile +++ b/sequencer/service/Dockerfile @@ -97,7 +97,7 @@ COPY --from=builder --chown=sequencer_user:sequencer_user /usr/local/bin/r0vm /u COPY --from=builder --chown=sequencer_user:sequencer_user /root/.logos-blockchain-circuits /home/sequencer_user/.logos-blockchain-circuits # Copy entrypoint script -COPY sequencer_service/docker-entrypoint.sh /docker-entrypoint.sh +COPY sequencer/service/docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh # Expose default port @@ -125,4 +125,4 @@ USER root ENTRYPOINT ["/docker-entrypoint.sh"] WORKDIR /sequencer_service -CMD ["sequencer_service", "/etc/sequencer_service"] +CMD ["sequencer_service", "/etc/sequencer_service/sequencer_config.json"] diff --git a/sequencer/service/docker-compose.yml b/sequencer/service/docker-compose.yml index ebc024d6..81520e7b 100644 --- a/sequencer/service/docker-compose.yml +++ b/sequencer/service/docker-compose.yml @@ -2,13 +2,13 @@ services: sequencer_service: image: lssa/sequencer_service build: - context: .. + context: ../.. dockerfile: sequencer/service/Dockerfile container_name: sequencer_service ports: - "3040:3040" volumes: - # Mount configuration folder - - ./configs/docker:/etc/sequencer_service + # Mount configuration file + - ./configs/docker/sequencer_config.json:/etc/sequencer_service/sequencer_config.json # Mount data folder - ./data:/var/lib/sequencer_service diff --git a/sequencer/service/rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml index 7fa173d1..193b948f 100644 --- a/sequencer/service/rpc/Cargo.toml +++ b/sequencer/service/rpc/Cargo.toml @@ -13,7 +13,6 @@ nssa.workspace = true nssa_core.workspace = true jsonrpsee = { workspace = true, features = ["macros"] } -serde_json.workspace = true [features] client = ["jsonrpsee/client"] diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs index a4bb8f06..620d93fb 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/sequencer/service/rpc/src/lib.rs @@ -79,7 +79,7 @@ pub trait Rpc { async fn get_proof_for_commitment( &self, commitment: Commitment, - ) -> Result; + ) -> Result, ErrorObjectOwned>; #[method(name = "getAccount")] async fn get_account(&self, account_id: AccountId) -> Result; diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs index ab5459a7..e31cae1e 100644 --- a/sequencer/service/src/service.rs +++ b/sequencer/service/src/service.rs @@ -160,18 +160,9 @@ impl Result { + ) -> Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; - sequencer - .state() - .get_proof_for_commitment(&commitment) - .ok_or_else(|| { - ErrorObjectOwned::owned( - NOT_FOUND_ERROR_CODE, - "Proof for commitment not found", - None::<()>, - ) - }) + Ok(sequencer.state().get_proof_for_commitment(&commitment)) } async fn get_account(&self, account_id: AccountId) -> Result { diff --git a/wallet-ffi/Cargo.toml b/wallet-ffi/Cargo.toml index 07169639..0af20a54 100644 --- a/wallet-ffi/Cargo.toml +++ b/wallet-ffi/Cargo.toml @@ -13,7 +13,6 @@ crate-type = ["rlib", "cdylib", "staticlib"] [dependencies] wallet.workspace = true nssa.workspace = true -common.workspace = true nssa_core.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } tokio.workspace = true diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index e4eedd2e..2e628790 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -27,8 +27,6 @@ humantime.workspace = true tokio = { workspace = true, features = ["macros"] } clap.workspace = true base58.workspace = true -base64.workspace = true -borsh.workspace = true hex.workspace = true rand.workspace = true itertools.workspace = true diff --git a/wallet/src/chain_storage.rs b/wallet/src/chain_storage.rs index 49d31371..8a2cd09b 100644 --- a/wallet/src/chain_storage.rs +++ b/wallet/src/chain_storage.rs @@ -161,105 +161,44 @@ impl WalletChainStore { #[cfg(test)] mod tests { + use std::str::FromStr as _; + use key_protocol::key_management::key_tree::{ keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode as _, }; + use nssa::PrivateKey; use super::*; use crate::config::{ - InitialAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic, + InitialAccountData, InitialAccountDataPublic, PersistentAccountDataPrivate, + PersistentAccountDataPublic, }; fn create_initial_accounts() -> Vec { - let initial_acc1 = serde_json::from_str( - r#"{ - "Public": { - "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", - "pub_sign_key": [ - 127, - 39, - 48, - 152, - 242, - 91, - 113, - 230, - 192, - 5, - 169, - 81, - 159, - 38, - 120, - 218, - 141, - 28, - 127, - 1, - 246, - 162, - 119, - 120, - 226, - 217, - 148, - 138, - 189, - 249, - 1, - 251 - ] - } - }"#, - ) - .unwrap(); - - let initial_acc2 = serde_json::from_str( - r#"{ - "Public": { - "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", - "pub_sign_key": [ - 244, - 52, - 248, - 116, - 23, - 32, - 1, - 69, - 134, - 174, - 67, - 53, - 109, - 42, - 236, - 98, - 87, - 218, - 8, - 98, - 34, - 246, - 4, - 221, - 183, - 93, - 105, - 115, - 59, - 134, - 252, - 76 - ] - } - }"#, - ) - .unwrap(); - - let initial_accounts = vec![initial_acc1, initial_acc2]; - - initial_accounts + vec![ + InitialAccountData::Public(InitialAccountDataPublic { + account_id: nssa::AccountId::from_str( + "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", + ) + .unwrap(), + pub_sign_key: PrivateKey::try_new([ + 127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, 141, + 28, 127, 1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251, + ]) + .unwrap(), + }), + InitialAccountData::Public(InitialAccountDataPublic { + account_id: nssa::AccountId::from_str( + "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", + ) + .unwrap(), + pub_sign_key: PrivateKey::try_new([ + 244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, 218, + 8, 98, 34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76, + ]) + .unwrap(), + }), + ] } fn create_sample_wallet_config() -> WalletConfig { diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/wallet/src/cli/programs/native_token_transfer.rs index 910c6914..b3f833ac 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/wallet/src/cli/programs/native_token_transfer.rs @@ -62,7 +62,7 @@ impl WalletSubcommand for AuthTransferSubcommand { .register_account(account_id) .await?; - println!("Results of tx send are {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -77,7 +77,7 @@ impl WalletSubcommand for AuthTransferSubcommand { .register_account_private(account_id) .await?; - println!("Results of tx send are {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -313,7 +313,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { .send_private_transfer_to_owned_account(from, to, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -352,7 +352,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { .send_private_transfer_to_outer_account(from, to_npk, to_vpk, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -387,7 +387,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { .send_shielded_transfer(from, to, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -427,7 +427,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { .send_shielded_transfer_to_outer_account(from, to_npk, to_vpk, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); wallet_core.store_persistent_data().await?; @@ -457,7 +457,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { .send_deshielded_transfer(from, to, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -482,7 +482,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { .send_public_transfer(from, to, amount) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; diff --git a/wallet/src/cli/programs/pinata.rs b/wallet/src/cli/programs/pinata.rs index 9dba482c..94cb0649 100644 --- a/wallet/src/cli/programs/pinata.rs +++ b/wallet/src/cli/programs/pinata.rs @@ -116,7 +116,7 @@ impl WalletSubcommand for PinataProgramSubcommandPublic { .claim(pinata_account_id, winner_account_id, solution) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -151,7 +151,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { .claim_private_owned_account(pinata_account_id, winner_account_id, solution) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index cd5ec4b2..4274b1da 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -721,7 +721,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -769,7 +769,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -802,7 +802,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -838,7 +838,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -887,7 +887,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -930,7 +930,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -963,7 +963,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -996,7 +996,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1051,7 +1051,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1079,7 +1079,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1112,7 +1112,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1145,7 +1145,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1191,7 +1191,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1231,7 +1231,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1269,7 +1269,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; @@ -1304,7 +1304,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ) .await?; - println!("Transaction hash is {tx_hash:#?}"); + println!("Transaction hash is {tx_hash}"); let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; diff --git a/wallet/src/config.rs b/wallet/src/config.rs index 7419762c..7e8a526f 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -2,6 +2,7 @@ use std::{ collections::HashMap, io::{BufReader, Write as _}, path::Path, + str::FromStr as _, time::Duration, }; @@ -217,481 +218,52 @@ impl Default for WalletConfig { seq_poll_max_retries: 5, seq_block_poll_max_amount: 100, basic_auth: None, - initial_accounts: { - let init_acc_json = r#" - [ - { - "Public": { - "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", - "pub_sign_key": [ - 127, - 39, - 48, - 152, - 242, - 91, - 113, - 230, - 192, - 5, - 169, - 81, - 159, - 38, - 120, - 218, - 141, - 28, - 127, - 1, - 246, - 162, - 119, - 120, - 226, - 217, - 148, - 138, - 189, - 249, - 1, - 251 - ] - } - }, - { - "Public": { - "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", - "pub_sign_key": [ - 244, - 52, - 248, - 116, - 23, - 32, - 1, - 69, - 134, - 174, - 67, - 53, - 109, - 42, - 236, - 98, - 87, - 218, - 8, - 98, - 34, - 246, - 4, - 221, - 183, - 93, - 105, - 115, - 59, - 134, - 252, - 76 - ] - } - }, - { - "Private": { - "account_id": "HWkW5qd4XK3me6sCAb4bfPj462k33DjtKtEcYpuzNwB", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 10000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 14, - 202, - 241, - 109, - 32, - 181, - 152, - 140, - 76, - 153, - 108, - 57, - 77, - 192, - 181, - 97, - 108, - 144, - 122, - 45, - 219, - 5, - 203, - 193, - 82, - 123, - 83, - 34, - 250, - 214, - 137, - 63 - ], - "private_key_holder": { - "nullifier_secret_key": [ - 174, - 56, - 101, - 30, - 248, - 249, - 100, - 0, - 122, - 199, - 209, - 246, - 58, - 163, - 223, - 146, - 59, - 143, - 78, - 95, - 41, - 186, - 106, - 187, - 53, - 63, - 75, - 244, - 233, - 185, - 110, - 199 - ], - "viewing_secret_key": [ - 251, - 85, - 223, - 73, - 142, - 127, - 134, - 132, - 185, - 210, - 100, - 103, - 198, - 108, - 229, - 80, - 176, - 211, - 249, - 114, - 110, - 7, - 225, - 17, - 7, - 69, - 204, - 32, - 47, - 242, - 103, - 247 - ] + initial_accounts: vec![ + InitialAccountData::Public(InitialAccountDataPublic { + account_id: nssa::AccountId::from_str( + "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", + ) + .unwrap(), + pub_sign_key: nssa::PrivateKey::try_new([ + 127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, + 141, 28, 127, 1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251, + ]) + .unwrap(), + }), + InitialAccountData::Public(InitialAccountDataPublic { + account_id: nssa::AccountId::from_str( + "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", + ) + .unwrap(), + pub_sign_key: nssa::PrivateKey::try_new([ + 244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, + 218, 8, 98, 34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76, + ]) + .unwrap(), + }), + InitialAccountData::Private(Box::new(InitialAccountDataPrivate { + account_id: nssa::AccountId::from_str( + "HWkW5qd4XK3me6sCAb4bfPj462k33DjtKtEcYpuzNwB", + ) + .unwrap(), + account: nssa::Account { + balance: 10_000, + ..Default::default() }, - "nullifier_public_key": [ - 139, - 19, - 158, - 11, - 155, - 231, - 85, - 206, - 132, - 228, - 220, - 114, - 145, - 89, - 113, - 156, - 238, - 142, - 242, - 74, - 182, - 91, - 43, - 100, - 6, - 190, - 31, - 15, - 31, - 88, - 96, - 204 - ], - "viewing_public_key": [ - 3, - 136, - 153, - 50, - 191, - 184, - 135, - 36, - 29, - 107, - 57, - 9, - 218, - 135, - 249, - 213, - 118, - 215, - 118, - 173, - 30, - 137, - 116, - 77, - 17, - 86, - 62, - 154, - 31, - 173, - 19, - 167, - 211 - ] - } - } - }, - { - "Private": { - "account_id": "HUpbRQ1vEcZv5y6TDYv9tpt1VA64ji2v4RDLJfK2rpZn", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 20000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 32, - 162, - 244, - 221, - 2, - 133, - 168, - 250, - 240, - 52, - 92, - 187, - 157, - 116, - 249, - 203, - 143, - 194, - 214, - 112, - 115, - 142, - 153, - 78, - 241, - 173, - 103, - 242, - 192, - 196, - 29, - 133 - ], - "private_key_holder": { - "nullifier_secret_key": [ - 188, - 235, - 121, - 54, - 131, - 206, - 7, - 215, - 94, - 231, - 102, - 22, - 12, - 27, - 253, - 161, - 248, - 206, - 41, - 160, - 206, - 149, - 5, - 217, - 127, - 235, - 154, - 230, - 198, - 232, - 102, - 31 - ], - "viewing_secret_key": [ - 89, - 116, - 140, - 122, - 211, - 179, - 190, - 229, - 18, - 94, - 56, - 235, - 48, - 99, - 104, - 228, - 111, - 72, - 231, - 18, - 247, - 97, - 110, - 60, - 238, - 138, - 0, - 25, - 92, - 44, - 30, - 145 - ] + key_chain: KeyChain::new_mnemonic("default_private_account_1".to_owned()), + })), + InitialAccountData::Private(Box::new(InitialAccountDataPrivate { + account_id: nssa::AccountId::from_str( + "HUpbRQ1vEcZv5y6TDYv9tpt1VA64ji2v4RDLJfK2rpZn", + ) + .unwrap(), + account: nssa::Account { + balance: 20_000, + ..Default::default() }, - "nullifier_public_key": [ - 173, - 134, - 33, - 223, - 54, - 226, - 10, - 71, - 215, - 254, - 143, - 172, - 24, - 244, - 243, - 208, - 65, - 112, - 118, - 70, - 217, - 240, - 69, - 100, - 129, - 3, - 121, - 25, - 213, - 132, - 42, - 45 - ], - "viewing_public_key": [ - 2, - 43, - 42, - 253, - 112, - 83, - 195, - 164, - 26, - 141, - 92, - 28, - 224, - 120, - 155, - 119, - 225, - 1, - 45, - 42, - 245, - 172, - 134, - 136, - 52, - 183, - 170, - 96, - 115, - 212, - 114, - 120, - 37 - ] - } - } - } - ] - "#; - serde_json::from_str(init_acc_json).unwrap() - }, + key_chain: KeyChain::new_mnemonic("default_private_account_2".to_owned()), + })), + ], } } } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 5ebbaf82..86e27784 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -299,8 +299,7 @@ impl WalletCore { self.sequencer_client .get_proof_for_commitment(acc_comm) .await - .map(Some) - .map_err(anyhow::Error::from) + .map_err(Into::into) } else { Ok(None) } From 325960d696de2e9e70832d9a260e4420eeadbb4e Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Mon, 16 Mar 2026 17:08:15 +0300 Subject: [PATCH 06/10] feat: remove `override_rust_log` from wallet config --- .../sequencer/sequencer_config.json | 2 -- integration_tests/src/config.rs | 1 - .../service/configs/debug/sequencer_config.json | 2 -- .../service/configs/docker/sequencer_config.json | 2 -- wallet/configs/debug/wallet_config.json | 1 - wallet/src/chain_storage.rs | 1 - wallet/src/cli/config.rs | 12 ------------ wallet/src/config.rs | 10 ---------- 8 files changed, 31 deletions(-) diff --git a/configs/docker-all-in-one/sequencer/sequencer_config.json b/configs/docker-all-in-one/sequencer/sequencer_config.json index c03cbf5e..d7fd3490 100644 --- a/configs/docker-all-in-one/sequencer/sequencer_config.json +++ b/configs/docker-all-in-one/sequencer/sequencer_config.json @@ -1,6 +1,5 @@ { "home": "/var/lib/sequencer_service", - "override_rust_log": null, "genesis_id": 1, "is_genesis_random": true, "max_num_tx_in_block": 20, @@ -8,7 +7,6 @@ "mempool_max_size": 10000, "block_create_timeout": "10s", "retry_pending_blocks_timeout": "7s", - "port": 3040, "bedrock_config": { "backoff": { "start_delay": "100ms", diff --git a/integration_tests/src/config.rs b/integration_tests/src/config.rs index dc24c8f0..22444458 100644 --- a/integration_tests/src/config.rs +++ b/integration_tests/src/config.rs @@ -234,7 +234,6 @@ pub fn wallet_config( initial_data: &InitialData, ) -> Result { Ok(WalletConfig { - override_rust_log: None, sequencer_addr: addr_to_url(UrlProtocol::Http, sequencer_addr) .context("Failed to convert sequencer addr to URL")?, seq_poll_timeout: Duration::from_secs(30), diff --git a/sequencer/service/configs/debug/sequencer_config.json b/sequencer/service/configs/debug/sequencer_config.json index 8491c2a1..4088fc4a 100644 --- a/sequencer/service/configs/debug/sequencer_config.json +++ b/sequencer/service/configs/debug/sequencer_config.json @@ -1,6 +1,5 @@ { "home": ".", - "override_rust_log": null, "genesis_id": 1, "is_genesis_random": true, "max_num_tx_in_block": 20, @@ -8,7 +7,6 @@ "mempool_max_size": 1000, "block_create_timeout": "15s", "retry_pending_blocks_timeout": "5s", - "port": 3040, "bedrock_config": { "backoff": { "start_delay": "100ms", diff --git a/sequencer/service/configs/docker/sequencer_config.json b/sequencer/service/configs/docker/sequencer_config.json index adefe1f4..f5a243d5 100644 --- a/sequencer/service/configs/docker/sequencer_config.json +++ b/sequencer/service/configs/docker/sequencer_config.json @@ -1,13 +1,11 @@ { "home": "/var/lib/sequencer_service", - "override_rust_log": null, "genesis_id": 1, "is_genesis_random": true, "max_num_tx_in_block": 20, "max_block_size": "1 MiB", "mempool_max_size": 10000, "block_create_timeout": "10s", - "port": 3040, "retry_pending_blocks_timeout": "7s", "bedrock_config": { "backoff": { diff --git a/wallet/configs/debug/wallet_config.json b/wallet/configs/debug/wallet_config.json index d279c0cb..759d67ee 100644 --- a/wallet/configs/debug/wallet_config.json +++ b/wallet/configs/debug/wallet_config.json @@ -1,5 +1,4 @@ { - "override_rust_log": null, "sequencer_addr": "http://127.0.0.1:3040", "seq_poll_timeout": "30s", "seq_tx_poll_max_blocks": 15, diff --git a/wallet/src/chain_storage.rs b/wallet/src/chain_storage.rs index 8a2cd09b..a88e0b8b 100644 --- a/wallet/src/chain_storage.rs +++ b/wallet/src/chain_storage.rs @@ -203,7 +203,6 @@ mod tests { fn create_sample_wallet_config() -> WalletConfig { WalletConfig { - override_rust_log: None, sequencer_addr: "http://127.0.0.1".parse().unwrap(), seq_poll_timeout: std::time::Duration::from_secs(12), seq_tx_poll_max_blocks: 5, diff --git a/wallet/src/cli/config.rs b/wallet/src/cli/config.rs index ac94a1b7..c9a5796f 100644 --- a/wallet/src/cli/config.rs +++ b/wallet/src/cli/config.rs @@ -37,15 +37,6 @@ impl WalletSubcommand for ConfigSubcommand { println!("{config_str}"); } else if let Some(key) = key { match key.as_str() { - "override_rust_log" => { - if let Some(value) = - &wallet_core.storage.wallet_config.override_rust_log - { - println!("{value}"); - } else { - println!("Not set"); - } - } "sequencer_addr" => { println!("{}", wallet_core.storage.wallet_config.sequencer_addr); } @@ -88,9 +79,6 @@ impl WalletSubcommand for ConfigSubcommand { } Self::Set { key, value } => { match key.as_str() { - "override_rust_log" => { - wallet_core.storage.wallet_config.override_rust_log = Some(value); - } "sequencer_addr" => { wallet_core.storage.wallet_config.sequencer_addr = value.parse()?; } diff --git a/wallet/src/config.rs b/wallet/src/config.rs index 7e8a526f..e74cd437 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -187,9 +187,6 @@ pub struct GasConfig { #[optfield::optfield(pub WalletConfigOverrides, rewrap, attrs = (derive(Debug, Default, Clone)))] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WalletConfig { - /// Override rust log (env var logging level). - #[serde(skip_serializing_if = "Option::is_none")] - pub override_rust_log: Option, /// Sequencer URL. pub sequencer_addr: Url, /// Sequencer polling duration for new blocks. @@ -211,7 +208,6 @@ pub struct WalletConfig { impl Default for WalletConfig { fn default() -> Self { Self { - override_rust_log: None, sequencer_addr: "http://127.0.0.1:3040".parse().unwrap(), seq_poll_timeout: Duration::from_secs(12), seq_tx_poll_max_blocks: 5, @@ -308,7 +304,6 @@ impl WalletConfig { pub fn apply_overrides(&mut self, overrides: WalletConfigOverrides) { let Self { - override_rust_log, sequencer_addr, seq_poll_timeout, seq_tx_poll_max_blocks, @@ -319,7 +314,6 @@ impl WalletConfig { } = self; let WalletConfigOverrides { - override_rust_log: o_override_rust_log, sequencer_addr: o_sequencer_addr, seq_poll_timeout: o_seq_poll_timeout, seq_tx_poll_max_blocks: o_seq_tx_poll_max_blocks, @@ -329,10 +323,6 @@ impl WalletConfig { basic_auth: o_basic_auth, } = overrides; - if let Some(v) = o_override_rust_log { - warn!("Overriding wallet config 'override_rust_log' to {v:#?}"); - *override_rust_log = v; - } if let Some(v) = o_sequencer_addr { warn!("Overriding wallet config 'sequencer_addr' to {v}"); *sequencer_addr = v; From 7b20a83379deeaa843e97daa78846fc6353fbe81 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Wed, 18 Mar 2026 21:58:36 +0300 Subject: [PATCH 07/10] fix: fixes after rebase & address comments --- .../bin/run_hello_world_with_authorization.rs | 9 +------- indexer/core/src/block_store.rs | 2 +- indexer/service/src/lib.rs | 4 ++-- integration_tests/src/lib.rs | 8 +++---- key_protocol/src/key_protocol_core/mod.rs | 4 ++-- sequencer/service/src/lib.rs | 15 ++++++++---- sequencer/service/src/main.rs | 4 ++-- wallet/src/lib.rs | 6 +++-- wallet/src/program_facades/amm.rs | 20 ++++------------ .../native_token_transfer/public.rs | 23 +++---------------- wallet/src/program_facades/token.rs | 15 +++--------- 11 files changed, 36 insertions(+), 74 deletions(-) diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs index 39e1380f..a9750bce 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs @@ -4,7 +4,6 @@ use nssa::{ program::Program, public_transaction::{Message, WitnessSet}, }; -use nssa_core::account::Nonce; use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; @@ -65,13 +64,7 @@ async fn main() { .await .expect("Node should be reachable to query account data"); let signing_keys = [signing_key]; - let message = Message::try_new( - program.id(), - vec![account_id], - nonces.iter().map(|x| Nonce(*x)).collect(), - greeting, - ) - .unwrap(); + let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap(); // Pass the signing key to sign the message. This will be used by the node // to flag the pre_state as `is_authorized` when executing the program let witness_set = WitnessSet::for_message(&message, &signing_keys); diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index 384217ff..bf3516e3 100644 --- a/indexer/core/src/block_store.rs +++ b/indexer/core/src/block_store.rs @@ -176,7 +176,7 @@ mod tests { ) .unwrap(); - let block = storage.get_block_at_id(1).unwrap(); + let block = storage.get_block_at_id(1).unwrap().unwrap(); let final_id = storage.get_last_block_id().unwrap(); assert_eq!(block.header.hash, genesis_block().header.hash); diff --git a/indexer/service/src/lib.rs b/indexer/service/src/lib.rs index 47f9289e..10f1cade 100644 --- a/indexer/service/src/lib.rs +++ b/indexer/service/src/lib.rs @@ -40,10 +40,10 @@ impl IndexerHandle { } #[must_use] - pub fn is_stopped(&self) -> bool { + pub fn is_healthy(&self) -> bool { self.server_handle .as_ref() - .is_none_or(ServerHandle::is_stopped) + .is_some_and(|handle| !handle.is_stopped()) } } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 2128a482..08e7cf9f 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -338,17 +338,17 @@ impl Drop for TestContext { let sequencer_handle = sequencer_handle .take() .expect("Sequencer handle should be present in TestContext drop"); - if sequencer_handle.is_stopped() { + if !sequencer_handle.is_healthy() { let Err(err) = sequencer_handle - .stopped() + .failed() .now_or_never() - .expect("Sequencer handle should be stopped"); + .expect("Sequencer handle should not be running"); error!( "Sequencer handle has unexpectedly stopped before TestContext drop with error: {err:#}" ); } - if indexer_handle.is_stopped() { + if !indexer_handle.is_healthy() { error!("Indexer handle has unexpectedly stopped before TestContext drop"); } diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index cb21748c..8232d9f4 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -66,13 +66,13 @@ impl NSSAUserData { ) -> Result { if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) { anyhow::bail!( - "Key transaction pairing check not satisfied, there are public account_ids, which is not derived from keys" + "Key transaction pairing check not satisfied, there are public account_ids, which are not derived from keys" ); } if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) { anyhow::bail!( - "Key transaction pairing check not satisfied, there are private account_ids, which is not derived from keys" + "Key transaction pairing check not satisfied, there are private account_ids, which are not derived from keys" ); } diff --git a/sequencer/service/src/lib.rs b/sequencer/service/src/lib.rs index bc9a4ef5..5373b31f 100644 --- a/sequencer/service/src/lib.rs +++ b/sequencer/service/src/lib.rs @@ -50,12 +50,12 @@ impl SequencerHandle { } } - /// Wait for all Sequencer tasks to stop. + /// Wait for any of the sequencer tasks to fail and return the error. #[expect( clippy::integer_division_remainder_used, reason = "Generated by select! macro, can't be easily rewritten to avoid this lint" )] - pub async fn stopped(mut self) -> Result { + pub async fn failed(mut self) -> Result { let Self { addr: _, server_handle, @@ -88,8 +88,12 @@ impl SequencerHandle { } } + /// Check if all Sequencer tasks are still running. + /// + /// Return `false` if any of the tasks has failed and `true` otherwise. + /// Error of the failed task can be retrieved by awaiting on [`Self::failed()`]. #[must_use] - pub fn is_stopped(&self) -> bool { + pub fn is_healthy(&self) -> bool { let Self { addr: _, server_handle, @@ -98,10 +102,11 @@ impl SequencerHandle { listen_for_bedrock_blocks_loop_handle, } = self; - server_handle.as_ref().is_none_or(ServerHandle::is_stopped) + let stopped = server_handle.as_ref().is_none_or(ServerHandle::is_stopped) || main_loop_handle.is_finished() || retry_pending_blocks_loop_handle.is_finished() - || listen_for_bedrock_blocks_loop_handle.is_finished() + || listen_for_bedrock_blocks_loop_handle.is_finished(); + !stopped } #[must_use] diff --git a/sequencer/service/src/main.rs b/sequencer/service/src/main.rs index 326ded70..e78ad502 100644 --- a/sequencer/service/src/main.rs +++ b/sequencer/service/src/main.rs @@ -33,8 +33,8 @@ async fn main() -> Result<()> { () = cancellation_token.cancelled() => { info!("Shutting down sequencer..."); } - Err(err) = sequencer_handle.stopped() => { - error!("Sequencer stopped unexpectedly: {err}"); + Err(err) = sequencer_handle.failed() => { + error!("Sequencer failed unexpectedly: {err}"); } } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 86e27784..bf82a1bd 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -22,7 +22,9 @@ use nssa::{ circuit::ProgramWithDependencies, message::EncryptedAccountData, }, }; -use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData}; +use nssa_core::{ + Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData, +}; pub use privacy_preserving_tx::PrivacyPreservingAccount; use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; use tokio::io::AsyncWriteExt as _; @@ -253,7 +255,7 @@ impl WalletCore { } /// Get accounts nonces. - pub async fn get_accounts_nonces(&self, accs: Vec) -> Result> { + pub async fn get_accounts_nonces(&self, accs: Vec) -> Result> { Ok(self.sequencer_client.get_accounts_nonces(accs).await?) } diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index c430f29d..f1b94621 100644 --- a/wallet/src/program_facades/amm.rs +++ b/wallet/src/program_facades/amm.rs @@ -81,10 +81,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -195,10 +192,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -289,10 +283,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -378,10 +369,7 @@ impl Amm<'_> { let message = nssa::public_transaction::Message::try_new( program.id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); diff --git a/wallet/src/program_facades/native_token_transfer/public.rs b/wallet/src/program_facades/native_token_transfer/public.rs index a54a215f..f91171db 100644 --- a/wallet/src/program_facades/native_token_transfer/public.rs +++ b/wallet/src/program_facades/native_token_transfer/public.rs @@ -31,16 +31,8 @@ impl NativeTokenTransfer<'_> { let account_ids = vec![from, to]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), - balance_to_move, - ) - .unwrap(); + let message = + Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); @@ -75,16 +67,7 @@ impl NativeTokenTransfer<'_> { let instruction: u128 = 0; let account_ids = vec![from]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), - instruction, - ) - .unwrap(); + let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap(); let signing_key = self.0.storage.user_data.get_pub_account_signing_key(from); diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index ca36e723..3aa6891f 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -146,10 +146,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( program_id, account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); @@ -354,10 +351,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .expect("Instruction should serialize"); @@ -491,10 +485,7 @@ impl Token<'_> { let message = nssa::public_transaction::Message::try_new( Program::token().id(), account_ids, - nonces - .iter() - .map(|x| nssa_core::account::Nonce(*x)) - .collect(), + nonces, instruction, ) .unwrap(); From 05c2c3a56d7068b934b1a90a14547f8a5a77e9eb Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Thu, 19 Mar 2026 00:42:30 +0300 Subject: [PATCH 08/10] fix: encode transactions with borsh in sequencer rpc --- Cargo.lock | 15 ++++++++--- Cargo.toml | 2 ++ common/Cargo.toml | 1 + common/src/block.rs | 24 +++++++++++++----- common/src/borsh_base64.rs | 25 +++++++++++++++++++ common/src/lib.rs | 1 + common/src/transaction.rs | 14 ++++++++++- nssa/Cargo.toml | 1 - nssa/src/base64.rs | 14 ----------- nssa/src/lib.rs | 1 - .../privacy_preserving_transaction/circuit.rs | 5 ++-- .../privacy_preserving_transaction/message.rs | 5 ++-- .../transaction.rs | 3 +-- .../witness_set.rs | 3 +-- .../program_deployment_transaction/message.rs | 4 +-- .../transaction.rs | 3 +-- nssa/src/public_transaction/message.rs | 4 +-- nssa/src/public_transaction/transaction.rs | 3 +-- nssa/src/public_transaction/witness_set.rs | 3 +-- nssa/src/signature/mod.rs | 5 +--- sequencer/service/Cargo.toml | 4 +-- sequencer/service/protocol/Cargo.toml | 13 ++++++++++ sequencer/service/protocol/src/lib.rs | 9 +++++++ sequencer/service/rpc/Cargo.toml | 4 +-- sequencer/service/rpc/src/lib.rs | 19 +++++++------- sequencer/service/src/service.rs | 23 ++++++----------- wallet/src/pinata_interactions.rs | 6 ++--- wallet/src/transaction_utils.rs | 16 ++++++------ 28 files changed, 137 insertions(+), 93 deletions(-) create mode 100644 common/src/borsh_base64.rs delete mode 100644 nssa/src/base64.rs create mode 100644 sequencer/service/protocol/Cargo.toml create mode 100644 sequencer/service/protocol/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 58b9c1cd..6e0461fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,6 +1498,7 @@ name = "common" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.22.1", "borsh", "hex", "log", @@ -5244,7 +5245,6 @@ name = "nssa" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.1", "borsh", "env_logger", "hex", @@ -7177,23 +7177,30 @@ dependencies = [ "log", "mempool", "nssa", - "nssa_core", "sequencer_core", + "sequencer_service_protocol", "sequencer_service_rpc", "tokio", "tokio-util", ] [[package]] -name = "sequencer_service_rpc" +name = "sequencer_service_protocol" version = "0.1.0" dependencies = [ "common", - "jsonrpsee", "nssa", "nssa_core", ] +[[package]] +name = "sequencer_service_rpc" +version = "0.1.0" +dependencies = [ + "jsonrpsee", + "sequencer_service_protocol", +] + [[package]] name = "serde" version = "1.0.228" diff --git a/Cargo.toml b/Cargo.toml index abe84745..829a6539 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "programs/token", "sequencer/core", "sequencer/service", + "sequencer/service/protocol", "sequencer/service/rpc", "indexer/core", "indexer/service", @@ -43,6 +44,7 @@ mempool = { path = "mempool" } storage = { path = "storage" } key_protocol = { path = "key_protocol" } sequencer_core = { path = "sequencer/core" } +sequencer_service_protocol = { path = "sequencer/service/protocol" } sequencer_service_rpc = { path = "sequencer/service/rpc" } sequencer_service = { path = "sequencer/service" } indexer_core = { path = "indexer/core" } diff --git a/common/Cargo.toml b/common/Cargo.toml index 002e0cfc..0ae0b220 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,6 +15,7 @@ anyhow.workspace = true thiserror.workspace = true serde.workspace = true serde_with.workspace = true +base64.workspace = true sha2.workspace = true log.workspace = true hex.workspace = true diff --git a/common/src/block.rs b/common/src/block.rs index 7759333a..11446314 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -10,7 +10,7 @@ pub type BlockHash = HashType; pub type BlockId = u64; pub type TimeStamp = u64; -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockMeta { pub id: BlockId, pub hash: BlockHash, @@ -31,7 +31,7 @@ impl OwnHasher { } } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: BlockHash, @@ -40,19 +40,19 @@ pub struct BlockHeader { pub signature: nssa::Signature, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockBody { pub transactions: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub enum BedrockStatus { Pending, Safe, Finalized, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct Block { pub header: BlockHeader, pub body: BlockBody, @@ -60,7 +60,19 @@ pub struct Block { pub bedrock_parent_id: MantleMsgId, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +impl Serialize for Block { + fn serialize(&self, serializer: S) -> Result { + crate::borsh_base64::serialize(self, serializer) + } +} + +impl<'de> Deserialize<'de> for Block { + fn deserialize>(deserializer: D) -> Result { + crate::borsh_base64::deserialize(deserializer) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, diff --git a/common/src/borsh_base64.rs b/common/src/borsh_base64.rs new file mode 100644 index 00000000..2dc7bdec --- /dev/null +++ b/common/src/borsh_base64.rs @@ -0,0 +1,25 @@ +//! This module provides utilities for serializing and deserializing data by combining Borsh and +//! Base64 encodings. + +use base64::{Engine as _, engine::general_purpose::STANDARD}; +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +pub fn serialize( + value: &T, + serializer: S, +) -> Result { + let borsh_encoded = borsh::to_vec(value).map_err(serde::ser::Error::custom)?; + let base64_encoded = STANDARD.encode(&borsh_encoded); + Serialize::serialize(&base64_encoded, serializer) +} + +pub fn deserialize<'de, T: BorshDeserialize, D: serde::Deserializer<'de>>( + deserializer: D, +) -> Result { + let base64_encoded = ::deserialize(deserializer)?; + let borsh_encoded = STANDARD + .decode(base64_encoded.as_bytes()) + .map_err(serde::de::Error::custom)?; + borsh::from_slice(&borsh_encoded).map_err(serde::de::Error::custom) +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 57d70b64..a7744d63 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,6 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; pub mod block; +mod borsh_base64; pub mod config; pub mod transaction; diff --git a/common/src/transaction.rs b/common/src/transaction.rs index e11b91c3..29ae8caf 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -5,13 +5,25 @@ use serde::{Deserialize, Serialize}; use crate::HashType; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub enum NSSATransaction { Public(nssa::PublicTransaction), PrivacyPreserving(nssa::PrivacyPreservingTransaction), ProgramDeployment(nssa::ProgramDeploymentTransaction), } +impl Serialize for NSSATransaction { + fn serialize(&self, serializer: S) -> Result { + crate::borsh_base64::serialize(self, serializer) + } +} + +impl<'de> Deserialize<'de> for NSSATransaction { + fn deserialize>(deserializer: D) -> Result { + crate::borsh_base64::deserialize(deserializer) + } +} + impl NSSATransaction { #[must_use] pub fn hash(&self) -> HashType { diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 89dae607..ceebaa2e 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -19,7 +19,6 @@ sha2.workspace = true rand.workspace = true borsh.workspace = true hex.workspace = true -base64.workspace = true secp256k1 = "0.31.1" risc0-binfmt = "3.0.2" log.workspace = true diff --git a/nssa/src/base64.rs b/nssa/src/base64.rs deleted file mode 100644 index cc782e9c..00000000 --- a/nssa/src/base64.rs +++ /dev/null @@ -1,14 +0,0 @@ -use base64::prelude::{BASE64_STANDARD, Engine as _}; -use serde::{Deserialize as _, Deserializer, Serialize as _, Serializer}; - -pub fn serialize(v: &[u8], s: S) -> Result { - let base64 = BASE64_STANDARD.encode(v); - String::serialize(&base64, s) -} - -pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { - let base64 = String::deserialize(d)?; - BASE64_STANDARD - .decode(base64.as_bytes()) - .map_err(serde::de::Error::custom) -} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 973433ee..bc7cf121 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -18,7 +18,6 @@ pub use public_transaction::PublicTransaction; pub use signature::{PrivateKey, PublicKey, Signature}; pub use state::V02State; -mod base64; pub mod encoding; pub mod error; mod merkle_tree; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 9f0bf83f..2ab141a3 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -8,7 +8,6 @@ use nssa_core::{ program::{ChainedCall, InstructionData, ProgramId, ProgramOutput}, }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; -use serde::{Deserialize, Serialize}; use crate::{ error::NssaError, @@ -18,8 +17,8 @@ use crate::{ }; /// Proof of the privacy preserving execution circuit. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] -pub struct Proof(#[serde(with = "crate::base64")] pub(crate) Vec); +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +pub struct Proof(pub(crate) Vec); impl Proof { #[must_use] diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index a2d6812e..4b93e820 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -4,14 +4,13 @@ use nssa_core::{ account::{Account, Nonce}, encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256}; use crate::{AccountId, error::NssaError}; pub type ViewTag = u8; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct EncryptedAccountData { pub ciphertext: Ciphertext, pub epk: EphemeralPublicKey, @@ -45,7 +44,7 @@ impl EncryptedAccountData { } } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub public_account_ids: Vec, pub nonces: Vec, diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 012b3bd5..2b268c07 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -8,7 +8,6 @@ use nssa_core::{ Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput, account::{Account, AccountWithMetadata}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use super::{message::Message, witness_set::WitnessSet}; @@ -18,7 +17,7 @@ use crate::{ privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData}, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PrivacyPreservingTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/nssa/src/privacy_preserving_transaction/witness_set.rs index 4f570a22..373bbc9c 100644 --- a/nssa/src/privacy_preserving_transaction/witness_set.rs +++ b/nssa/src/privacy_preserving_transaction/witness_set.rs @@ -1,12 +1,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; use crate::{ PrivateKey, PublicKey, Signature, privacy_preserving_transaction::{circuit::Proof, message::Message}, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, pub(crate) proof: Proof, diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index d4758ae2..a51e4149 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -1,9 +1,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { - #[serde(with = "crate::base64")] pub(crate) bytecode: Vec, } diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/nssa/src/program_deployment_transaction/transaction.rs index 939d81be..1e53388d 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/nssa/src/program_deployment_transaction/transaction.rs @@ -1,13 +1,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::account::AccountId; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct ProgramDeploymentTransaction { pub message: Message, } diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index e3651ba3..d4838b87 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -3,11 +3,11 @@ use nssa_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use crate::{AccountId, error::NssaError, program::Program}; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub program_id: ProgramId, pub account_ids: Vec, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 00d29a05..8c84d83c 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -6,7 +6,6 @@ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata}, program::{ChainedCall, DEFAULT_PROGRAM_ID, validate_execution}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ @@ -16,7 +15,7 @@ use crate::{ state::MAX_NUMBER_CHAINED_CALLS, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PublicTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index e796fbfe..d6b32891 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -1,9 +1,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, } diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index f0e5a863..9dfd47b3 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -4,14 +4,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub use private_key::PrivateKey; pub use public_key::PublicKey; use rand::{RngCore as _, rngs::OsRng}; -use serde_with::{DeserializeFromStr, SerializeDisplay}; mod private_key; mod public_key; -#[derive( - Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr, BorshSerialize, BorshDeserialize, -)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Signature { pub value: [u8; 64], } diff --git a/sequencer/service/Cargo.toml b/sequencer/service/Cargo.toml index 3efb380d..6fee808c 100644 --- a/sequencer/service/Cargo.toml +++ b/sequencer/service/Cargo.toml @@ -10,10 +10,9 @@ workspace = true [dependencies] common.workspace = true nssa.workspace = true -nssa_core.workspace = true mempool.workspace = true -borsh.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } +sequencer_service_protocol.workspace = true sequencer_service_rpc = { workspace = true, features = ["server"] } indexer_service_rpc = { workspace = true, features = ["client"] } @@ -26,6 +25,7 @@ tokio-util.workspace = true jsonrpsee.workspace = true futures.workspace = true bytesize.workspace = true +borsh.workspace = true [features] default = [] diff --git a/sequencer/service/protocol/Cargo.toml b/sequencer/service/protocol/Cargo.toml new file mode 100644 index 00000000..be913104 --- /dev/null +++ b/sequencer/service/protocol/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sequencer_service_protocol" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +common.workspace = true +nssa.workspace = true +nssa_core.workspace = true diff --git a/sequencer/service/protocol/src/lib.rs b/sequencer/service/protocol/src/lib.rs new file mode 100644 index 00000000..eb868c0e --- /dev/null +++ b/sequencer/service/protocol/src/lib.rs @@ -0,0 +1,9 @@ +//! Reexports of types used by sequencer rpc specification. + +pub use common::{ + HashType, + block::{Block, BlockId}, + transaction::NSSATransaction, +}; +pub use nssa::{Account, AccountId, ProgramId}; +pub use nssa_core::{Commitment, MembershipProof, account::Nonce}; diff --git a/sequencer/service/rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml index 193b948f..d8f16b86 100644 --- a/sequencer/service/rpc/Cargo.toml +++ b/sequencer/service/rpc/Cargo.toml @@ -8,9 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -common.workspace = true -nssa.workspace = true -nssa_core.workspace = true +sequencer_service_protocol.workspace = true jsonrpsee = { workspace = true, features = ["macros"] } diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs index 620d93fb..6c03cdb6 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/sequencer/service/rpc/src/lib.rs @@ -1,17 +1,14 @@ use std::collections::BTreeMap; -use common::{ - HashType, - block::{Block, BlockId}, - transaction::NSSATransaction, -}; use jsonrpsee::proc_macros::rpc; #[cfg(feature = "server")] use jsonrpsee::types::ErrorObjectOwned; #[cfg(feature = "client")] pub use jsonrpsee::{core::ClientError, http_client::HttpClientBuilder as SequencerClientBuilder}; -use nssa::{Account, AccountId, ProgramId}; -use nssa_core::{Commitment, MembershipProof, account::Nonce}; +use sequencer_service_protocol::{ + Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, NSSATransaction, + Nonce, ProgramId, +}; #[cfg(all(not(feature = "server"), not(feature = "client")))] compile_error!("At least one of `server` or `client` features must be enabled."); @@ -22,10 +19,14 @@ compile_error!("At least one of `server` or `client` features must be enabled.") /// /// # Example /// -/// ```ignore -/// use sequencer_service_rpc::{SequencerClientBuilder, RpcClient as _}; +/// ```no_run +/// use common::transaction::NSSATransaction; +/// use sequencer_service_rpc::{RpcClient as _, SequencerClientBuilder}; /// +/// let url = "http://localhost:3040".parse()?; /// let client = SequencerClientBuilder::default().build(url)?; +/// +/// let tx: NSSATransaction = unimplemented!("Construct your transaction here"); /// let tx_hash = client.send_transaction(tx).await?; /// ``` #[cfg(feature = "client")] diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs index e31cae1e..71645363 100644 --- a/sequencer/service/src/service.rs +++ b/sequencer/service/src/service.rs @@ -1,10 +1,6 @@ use std::{collections::BTreeMap, sync::Arc}; -use common::{ - HashType, - block::{Block, BlockId}, - transaction::NSSATransaction, -}; +use common::transaction::NSSATransaction; use jsonrpsee::{ core::async_trait, types::{ErrorCode, ErrorObjectOwned}, @@ -12,15 +8,13 @@ use jsonrpsee::{ use log::warn; use mempool::MemPoolHandle; use nssa::{self, program::Program}; -use nssa_core::{ - Commitment, MembershipProof, - account::{Account, AccountId, Nonce}, - program::ProgramId, -}; use sequencer_core::{ DbError, SequencerCore, block_settlement_client::BlockSettlementClientTrait, indexer_client::IndexerClientTrait, }; +use sequencer_service_protocol::{ + Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, Nonce, ProgramId, +}; use tokio::sync::Mutex; const NOT_FOUND_ERROR_CODE: i32 = -31999; @@ -55,12 +49,9 @@ impl Date: Thu, 19 Mar 2026 01:11:07 +0300 Subject: [PATCH 09/10] chore: move `nssa` dependency of `amm` to `dev-dependencies` --- programs/amm/Cargo.toml | 7 ++----- programs/amm/src/tests.rs | 22 ++++------------------ 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/programs/amm/Cargo.toml b/programs/amm/Cargo.toml index 30074ac8..4fcadb9f 100644 --- a/programs/amm/Cargo.toml +++ b/programs/amm/Cargo.toml @@ -8,12 +8,9 @@ license = { workspace = true } workspace = true [dependencies] -nssa = { workspace = true, optional = true, features = [ - "test-utils", -], default-features = true } nssa_core.workspace = true token_core.workspace = true amm_core.workspace = true -[features] -nssa = ["dep:nssa"] +[dev-dependencies] +nssa = { workspace = true, features = ["test-utils"] } diff --git a/programs/amm/src/tests.rs b/programs/amm/src/tests.rs index e1e8698d..0176c3f0 100644 --- a/programs/amm/src/tests.rs +++ b/programs/amm/src/tests.rs @@ -4,7 +4,6 @@ use amm_core::{ PoolDefinition, compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_vault_pda, compute_vault_pda_seed, }; -#[cfg(feature = "nssa")] use nssa::{ PrivateKey, PublicKey, PublicTransaction, V02State, program::Program, public_transaction, }; @@ -25,16 +24,15 @@ struct BalanceForTests; struct ChainedCallForTests; struct IdForTests; struct AccountWithMetadataForTests; -#[cfg(feature = "nssa")] + struct PrivateKeysForTests; -#[cfg(feature = "nssa")] + struct IdForExeTests; -#[cfg(feature = "nssa")] + struct BalanceForExeTests; -#[cfg(feature = "nssa")] + struct AccountsForExeTests; -#[cfg(feature = "nssa")] impl PrivateKeysForTests { fn user_token_a_key() -> PrivateKey { PrivateKey::try_new([31; 32]).expect("Keys constructor expects valid private key") @@ -1008,7 +1006,6 @@ impl AccountWithMetadataForTests { } } -#[cfg(feature = "nssa")] impl BalanceForExeTests { fn user_token_a_holding_init() -> u128 { 10_000 @@ -1172,7 +1169,6 @@ impl BalanceForExeTests { } } -#[cfg(feature = "nssa")] impl IdForExeTests { fn pool_definition_id() -> AccountId { amm_core::compute_pool_pda( @@ -1229,7 +1225,6 @@ impl IdForExeTests { } } -#[cfg(feature = "nssa")] impl AccountsForExeTests { fn user_token_a_holding() -> Account { Account { @@ -2641,7 +2636,6 @@ fn new_definition_lp_symmetric_amounts() { assert_eq!(chained_call_lp, expected_lp_call); } -#[cfg(feature = "nssa")] fn state_for_amm_tests() -> V02State { let initial_data = []; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); @@ -2685,7 +2679,6 @@ fn state_for_amm_tests() -> V02State { state } -#[cfg(feature = "nssa")] fn state_for_amm_tests_with_new_def() -> V02State { let initial_data = []; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); @@ -2708,7 +2701,6 @@ fn state_for_amm_tests_with_new_def() -> V02State { state } -#[cfg(feature = "nssa")] #[test] fn simple_amm_remove() { let mut state = state_for_amm_tests(); @@ -2768,7 +2760,6 @@ fn simple_amm_remove() { assert_eq!(user_token_lp_post, expected_user_token_lp); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { let mut state = state_for_amm_tests_with_new_def(); @@ -2849,7 +2840,6 @@ fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { assert_eq!(user_token_lp_post, expected_user_token_lp); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { let mut state = state_for_amm_tests_with_new_def(); @@ -2934,7 +2924,6 @@ fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { assert_eq!(user_token_lp_post, expected_user_token_lp); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_new_definition_uninitialized_pool() { let mut state = state_for_amm_tests_with_new_def(); @@ -3007,7 +2996,6 @@ fn simple_amm_new_definition_uninitialized_pool() { assert_eq!(user_token_lp_post, expected_user_token_lp); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_add() { let mut state = state_for_amm_tests(); @@ -3070,7 +3058,6 @@ fn simple_amm_add() { assert_eq!(user_token_lp_post, expected_user_token_lp); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_swap_1() { let mut state = state_for_amm_tests(); @@ -3122,7 +3109,6 @@ fn simple_amm_swap_1() { assert_eq!(user_token_b_post, expected_user_token_b); } -#[cfg(feature = "nssa")] #[test] fn simple_amm_swap_2() { let mut state = state_for_amm_tests(); From 3913446cd2254e3c1341b10d76e7e062cea2661f Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Fri, 20 Mar 2026 01:21:50 +0300 Subject: [PATCH 10/10] fix: some wallet default config fixes after rebase --- wallet/configs/debug/wallet_config.json | 613 ++++++++++++------------ wallet/src/config.rs | 59 +-- 2 files changed, 336 insertions(+), 336 deletions(-) diff --git a/wallet/configs/debug/wallet_config.json b/wallet/configs/debug/wallet_config.json index 759d67ee..6604f65b 100644 --- a/wallet/configs/debug/wallet_config.json +++ b/wallet/configs/debug/wallet_config.json @@ -19,7 +19,7 @@ }, { "Private": { - "account_id": "HWkW5qd4XK3me6sCAb4bfPj462k33DjtKtEcYpuzNwB", + "account_id": "9DGDXnrNo4QhUUb2F8WDuDrPESja3eYDkZG5HkzvAvMC", "account": { "program_owner": [ 0, @@ -37,184 +37,184 @@ }, "key_chain": { "secret_spending_key": [ - 14, - 202, - 241, - 109, - 32, - 181, - 152, - 140, - 76, - 153, - 108, - 57, - 77, - 192, - 181, - 97, - 108, + 75, + 231, 144, - 122, - 45, - 219, + 165, 5, - 203, - 193, + 36, + 183, + 237, + 190, + 227, + 238, + 13, + 132, + 39, + 114, + 228, + 172, 82, - 123, - 83, - 34, - 250, - 214, - 137, - 63 + 119, + 164, + 233, + 132, + 130, + 224, + 201, + 90, + 200, + 156, + 108, + 199, + 56, + 22 ], "private_key_holder": { "nullifier_secret_key": [ - 174, - 56, - 101, - 30, - 248, - 249, - 100, - 0, - 122, - 199, - 209, - 246, - 58, - 163, - 223, - 146, - 59, - 143, - 78, - 95, - 41, - 186, - 106, - 187, - 53, - 63, - 75, - 244, - 233, - 185, - 110, - 199 + 212, + 34, + 166, + 184, + 182, + 77, + 127, + 176, + 147, + 68, + 148, + 190, + 41, + 244, + 8, + 202, + 51, + 10, + 44, + 43, + 93, + 41, + 229, + 130, + 54, + 96, + 198, + 242, + 10, + 227, + 119, + 1 ], "viewing_secret_key": [ - 251, - 85, - 223, - 73, - 142, - 127, - 134, - 132, - 185, - 210, - 100, - 103, - 198, - 108, - 229, - 80, - 176, - 211, - 249, - 114, - 110, - 7, - 225, - 17, - 7, - 69, - 204, - 32, - 47, - 242, - 103, - 247 + 205, + 10, + 5, + 19, + 148, + 98, + 49, + 19, + 251, + 186, + 247, + 216, + 75, + 53, + 184, + 36, + 84, + 87, + 236, + 205, + 105, + 217, + 213, + 21, + 61, + 183, + 133, + 174, + 121, + 115, + 51, + 203 ] }, "nullifier_public_key": [ - 139, - 19, - 158, - 11, - 155, - 231, - 85, - 206, - 132, - 228, - 220, - 114, - 145, - 89, + 122, + 213, 113, - 156, - 238, - 142, - 242, - 74, - 182, - 91, - 43, + 8, + 118, + 179, + 235, + 94, + 5, + 219, + 131, + 106, + 246, + 253, + 14, + 204, + 65, + 93, + 0, + 198, 100, + 108, + 57, + 48, 6, - 190, + 65, + 183, 31, - 15, - 31, - 88, - 96, - 204 + 136, + 86, + 82, + 165 ], "viewing_public_key": [ 3, - 136, - 153, - 50, - 191, - 184, - 135, - 36, - 29, - 107, - 57, - 9, - 218, - 135, - 249, - 213, - 118, + 165, + 235, 215, - 118, - 173, - 30, - 137, - 116, 77, - 17, - 86, - 62, - 154, - 31, - 173, + 4, 19, + 45, + 0, + 27, + 18, + 26, + 11, + 226, + 126, + 174, + 144, 167, - 211 + 160, + 199, + 14, + 23, + 49, + 163, + 49, + 138, + 129, + 229, + 79, + 9, + 15, + 234, + 30 ] } } }, { "Private": { - "account_id": "HUpbRQ1vEcZv5y6TDYv9tpt1VA64ji2v4RDLJfK2rpZn", + "account_id": "A6AT9UvsgitUi8w4BH43n6DyX1bK37DtSCfjEWXQQUrQ", "account": { "program_owner": [ 0, @@ -232,181 +232,180 @@ }, "key_chain": { "secret_spending_key": [ - 32, + 107, + 49, + 136, + 174, 162, - 244, - 221, - 2, - 133, - 168, + 107, 250, - 240, - 52, - 92, - 187, - 157, - 116, - 249, - 203, - 143, - 194, - 214, - 112, - 115, - 142, + 105, + 252, + 146, + 166, + 197, + 163, + 132, 153, - 78, - 241, - 173, - 103, - 242, - 192, - 196, - 29, - 133 + 222, + 68, + 17, + 87, + 101, + 22, + 113, + 88, + 97, + 180, + 203, + 139, + 18, + 28, + 62, + 51, + 149 ], "private_key_holder": { "nullifier_secret_key": [ - 188, - 235, - 121, - 54, - 131, - 206, - 7, - 215, - 94, - 231, - 102, - 22, - 12, - 27, - 253, - 161, - 248, - 206, - 41, - 160, - 206, - 149, - 5, - 217, - 127, - 235, - 154, - 230, - 198, - 232, - 102, - 31 + 219, + 5, + 233, + 185, + 144, + 150, + 100, + 58, + 97, + 5, + 57, + 163, + 110, + 46, + 241, + 216, + 155, + 217, + 100, + 51, + 184, + 21, + 225, + 148, + 198, + 9, + 121, + 239, + 232, + 98, + 22, + 218 ], "viewing_secret_key": [ - 89, - 116, - 140, - 122, - 211, - 179, - 190, - 229, - 18, - 94, - 56, - 235, - 48, - 99, - 104, - 228, - 111, - 72, - 231, - 18, - 247, - 97, - 110, - 60, - 238, - 138, - 0, - 25, - 92, - 44, - 30, - 145 + 35, + 105, + 230, + 121, + 218, + 177, + 21, + 55, + 83, + 80, + 95, + 235, + 161, + 83, + 11, + 221, + 67, + 83, + 1, + 218, + 49, + 242, + 53, + 29, + 26, + 171, + 170, + 144, + 49, + 233, + 159, + 48 ] }, "nullifier_public_key": [ - 173, - 134, 33, - 223, - 54, - 226, - 10, - 71, - 215, - 254, - 143, - 172, - 24, - 244, + 68, + 229, + 154, + 12, + 235, + 210, + 229, + 236, + 144, + 126, + 122, + 58, + 107, + 36, + 58, 243, - 208, - 65, - 112, - 118, - 70, - 217, - 240, - 69, - 100, - 129, - 3, - 121, - 25, - 213, - 132, - 42, - 45 + 128, + 174, + 197, + 141, + 137, + 162, + 190, + 155, + 234, + 94, + 156, + 218, + 34, + 13, + 221 ], "viewing_public_key": [ - 2, - 43, - 42, - 253, - 112, - 83, - 195, - 164, - 26, - 141, - 92, - 28, - 224, - 120, - 155, - 119, - 225, - 1, - 45, - 42, - 245, - 172, + 3, + 122, + 7, + 137, + 250, + 84, + 10, + 85, + 3, + 15, 134, - 136, - 52, - 183, - 170, - 96, - 115, - 212, - 114, + 250, + 205, + 40, + 126, + 211, + 14, 120, - 37 + 15, + 55, + 56, + 214, + 72, + 243, + 83, + 17, + 124, + 242, + 251, + 184, + 174, + 150, + 83 ] } } } - ], - "basic_auth": null + ] } \ No newline at end of file diff --git a/wallet/src/config.rs b/wallet/src/config.rs index e74cd437..60164e86 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -2,7 +2,6 @@ use std::{ collections::HashMap, io::{BufReader, Write as _}, path::Path, - str::FromStr as _, time::Duration, }; @@ -207,6 +206,28 @@ pub struct WalletConfig { impl Default for WalletConfig { fn default() -> Self { + let pub_sign_key1 = nssa::PrivateKey::try_new([ + 127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, 141, 28, 127, + 1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251, + ]) + .unwrap(); + let public_key1 = nssa::PublicKey::new_from_private_key(&pub_sign_key1); + let public_account_id1 = nssa::AccountId::from(&public_key1); + + let pub_sign_key2 = nssa::PrivateKey::try_new([ + 244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, 218, 8, 98, + 34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76, + ]) + .unwrap(); + let public_key2 = nssa::PublicKey::new_from_private_key(&pub_sign_key2); + let public_account_id2 = nssa::AccountId::from(&public_key2); + + let key_chain1 = KeyChain::new_mnemonic("default_private_account_1".to_owned()); + let private_account_id1 = nssa::AccountId::from(&key_chain1.nullifier_public_key); + + let key_chain2 = KeyChain::new_mnemonic("default_private_account_2".to_owned()); + let private_account_id2 = nssa::AccountId::from(&key_chain2.nullifier_public_key); + Self { sequencer_addr: "http://127.0.0.1:3040".parse().unwrap(), seq_poll_timeout: Duration::from_secs(12), @@ -216,48 +237,28 @@ impl Default for WalletConfig { basic_auth: None, initial_accounts: vec![ InitialAccountData::Public(InitialAccountDataPublic { - account_id: nssa::AccountId::from_str( - "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", - ) - .unwrap(), - pub_sign_key: nssa::PrivateKey::try_new([ - 127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, - 141, 28, 127, 1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251, - ]) - .unwrap(), + account_id: public_account_id1, + pub_sign_key: pub_sign_key1, }), InitialAccountData::Public(InitialAccountDataPublic { - account_id: nssa::AccountId::from_str( - "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", - ) - .unwrap(), - pub_sign_key: nssa::PrivateKey::try_new([ - 244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, - 218, 8, 98, 34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76, - ]) - .unwrap(), + account_id: public_account_id2, + pub_sign_key: pub_sign_key2, }), InitialAccountData::Private(Box::new(InitialAccountDataPrivate { - account_id: nssa::AccountId::from_str( - "HWkW5qd4XK3me6sCAb4bfPj462k33DjtKtEcYpuzNwB", - ) - .unwrap(), + account_id: private_account_id1, account: nssa::Account { balance: 10_000, ..Default::default() }, - key_chain: KeyChain::new_mnemonic("default_private_account_1".to_owned()), + key_chain: key_chain1, })), InitialAccountData::Private(Box::new(InitialAccountDataPrivate { - account_id: nssa::AccountId::from_str( - "HUpbRQ1vEcZv5y6TDYv9tpt1VA64ji2v4RDLJfK2rpZn", - ) - .unwrap(), + account_id: private_account_id2, account: nssa::Account { balance: 20_000, ..Default::default() }, - key_chain: KeyChain::new_mnemonic("default_private_account_2".to_owned()), + key_chain: key_chain2, })), ], }