diff --git a/.github/workflows/publish_image.yml b/.github/workflows/publish_images.yml similarity index 87% rename from .github/workflows/publish_image.yml rename to .github/workflows/publish_images.yml index 457a98d0..5076a430 100644 --- a/.github/workflows/publish_image.yml +++ b/.github/workflows/publish_images.yml @@ -2,6 +2,9 @@ name: Publish Docker Images on: workflow_dispatch: + push: + tags: + - "v*" jobs: publish: @@ -9,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 @@ -42,6 +45,7 @@ jobs: with: images: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository }}/${{ matrix.name }} tags: | + type=ref,event=tag type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} 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..6e0461fd 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" @@ -1732,20 +1500,15 @@ 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]] @@ -1877,15 +1640,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 +1746,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 +2042,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 +2843,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.4.0", + "http", "js-sys", "pin-project", "serde", @@ -3163,7 +2907,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap 2.13.0", "slab", "tokio", @@ -3318,17 +3062,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 +3079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -3357,7 +3090,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "pin-project-lite", ] @@ -3432,7 +3165,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http", "http-body", "httparse", "httpdate", @@ -3465,7 +3198,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 +3249,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 +3417,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 +3452,6 @@ version = "0.1.0" dependencies = [ "anyhow", "arc-swap", - "async-trait", "clap", "env_logger", "futures", @@ -3825,8 +3551,6 @@ name = "integration_tests" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.1", - "borsh", "bytesize", "common", "env_logger", @@ -3839,7 +3563,8 @@ dependencies = [ "nssa", "nssa_core", "sequencer_core", - "sequencer_runner", + "sequencer_service", + "sequencer_service_rpc", "serde_json", "tempfile", "testcontainers", @@ -4048,7 +3773,7 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http 1.4.0", + "http", "jsonrpsee-core", "pin-project", "rustls", @@ -4073,7 +3798,7 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "jsonrpsee-types", @@ -4134,7 +3859,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 +3885,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 +3909,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 +3963,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 +4339,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 +5097,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] @@ -5398,7 +5110,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.4.0", + "http", "httparse", "memchr", "mime", @@ -5545,6 +5257,7 @@ dependencies = [ "risc0-zkvm", "secp256k1", "serde", + "serde_with", "sha2", "test-case", "test_program_methods", @@ -6148,8 +5861,10 @@ name = "program_deployment" version = "0.1.0" dependencies = [ "clap", + "common", "nssa", "nssa_core", + "sequencer_service_rpc", "tokio", "wallet", ] @@ -6270,7 +5985,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -6307,7 +6022,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -6581,12 +6296,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 +6315,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -7453,47 +7162,43 @@ dependencies = [ ] [[package]] -name = "sequencer_rpc" +name = "sequencer_service" 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_runner" -version = "0.1.0" -dependencies = [ - "actix", - "actix-web", - "anyhow", "clap", "common", "env_logger", "futures", "indexer_service_rpc", + "jsonrpsee", "log", + "mempool", + "nssa", "sequencer_core", - "sequencer_rpc", + "sequencer_service_protocol", + "sequencer_service_rpc", "tokio", + "tokio-util", +] + +[[package]] +name = "sequencer_service_protocol" +version = "0.1.0" +dependencies = [ + "common", + "nssa", + "nssa_core", +] + +[[package]] +name = "sequencer_service_rpc" +version = "0.1.0" +dependencies = [ + "jsonrpsee", + "sequencer_service_protocol", ] [[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", ] @@ -8955,8 +8650,6 @@ dependencies = [ "anyhow", "async-stream", "base58", - "base64 0.22.1", - "borsh", "clap", "common", "env_logger", @@ -8972,9 +8665,11 @@ dependencies = [ "nssa_core", "optfield", "rand 0.8.5", + "sequencer_service_rpc", "serde", "serde_json", "sha2", + "thiserror 2.0.18", "token_core", "tokio", "url", @@ -8985,9 +8680,9 @@ name = "wallet-ffi" version = "0.1.0" dependencies = [ "cbindgen", - "common", "nssa", "nssa_core", + "sequencer_service_rpc", "tempfile", "tokio", "wallet", diff --git a/Cargo.toml b/Cargo.toml index bcd11651..829a6539 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,10 @@ members = [ "programs/amm", "programs/token/core", "programs/token", - "sequencer_core", - "sequencer_rpc", - "sequencer_runner", + "sequencer/core", + "sequencer/service", + "sequencer/service/protocol", + "sequencer/service/rpc", "indexer/core", "indexer/service", "indexer/service/protocol", @@ -42,9 +43,10 @@ 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_runner = { path = "sequencer_runner" } +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" } indexer_service = { path = "indexer/service" } indexer_service_protocol = { path = "indexer/service/protocol" } diff --git a/Justfile b/Justfile index c8ffe09d..ac003a15 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/sequencer_config.json # Run Indexer [working-directory: 'indexer/service'] @@ -62,8 +62,9 @@ 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 cd bedrock && docker compose down -v diff --git a/README.md b/README.md index b0086f4a..a08b81fb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Public accounts are stored on-chain as a visible map from IDs to account states, ### Programmability and selective privacy -LEZ aims to deliver full programmability in a hybrid public/private model, with the same flexibility and composability as public blockchains. Developers write and deploy programs in LEZ just as they would elsewhere. The protocol automatically supports executions that involve any combination of public and private accounts. From the program’s perspective, all accounts look the same, and privacy is enforced transparently. This lets developers focus on business logic while the system guarantees privacy and correctness. +LEZ aims to deliver full programmability in a hybrid public/private model, with the same flexibility and composability as public blockchains. Developers write and deploy programs in LEZ without addressing privacy concerns. The protocol automatically supports executions that involve any combination of public and private accounts. From the program’s perspective, all accounts look the same, and privacy is enforced transparently. This lets developers focus on business logic while the system guarantees privacy and correctness. To our knowledge, this design is unique to LEZ. Other privacy-focused programmable blockchains often require developers to explicitly handle private inputs inside their app logic. In LEZ, privacy is protocol-level: programs do not change, accounts are treated uniformly, and private execution works out of the box. @@ -73,6 +73,16 @@ This design keeps public transactions as fast as any RISC-V–based VM and makes --- --- +# Versioning + +We release versions as git tags (e.g. `v0.1.0`). If no critical issues with version is found you can expect it to be immutable. All further features and fixes will be a part of the next tag. As the project is in active development we don't provide backward compatibility yet. +For each tag we publish docker images of our services. +If you depend on this project you can pin your rust dependency to a git tag like this: + +```toml +nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.1.0" } +``` + # Install dependencies ### Install build dependencies @@ -141,17 +151,17 @@ The sequencer and logos blockchain node can be run locally: - `./scripts/setup-logos-blockchain-circuits.sh` - `cargo build --all-features` - `./target/debug/logos-blockchain-node --deployment nodes/node/standalone-deployment-config.yaml nodes/node/standalone-node-config.yaml` - + - Alternatively (WARNING: This node is outdated) go to `logos-blockchain/lssa/` repo and run the node from docker: - `cd bedrock` - Change line 14 of `docker-compose.yml` from `"0:18080/tcp"` into `"8080:18080/tcp"` - `docker compose up` - + 2. On another terminal go to the `logos-blockchain/lssa` repo and run indexer service: - `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` @@ -161,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) @@ -210,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/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index a8ca1f4e..d6e08b64 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index 0bc3de67..5dc0bf97 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index 64aaa346..cd2ffa53 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index a47d90f4..c6a2a8dd 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 8e151aa7..91dd81d5 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index 9a1269c5..d047e652 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index b055fbdb..0c0f3089 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index c650f1f9..1abe0774 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 2dea3a0d..8c24294d 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index fb881bbc..674ca600 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 5a7a8600..bd5ea48a 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index fc8dc194..ab13c315 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index 99dcd50f..ebe05ff6 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index 7ea603a5..407142e1 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index 3b2379c7..75c7d69e 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index 48900c0c..e78597c9 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index b5ef1b9a..4e7c1f5e 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index c3b1d1d6..3384a65a 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index b697cc70..b88ade13 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index b54383e2..8ae149e0 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/common/Cargo.toml b/common/Cargo.toml index 8aafed40..0ae0b220 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -13,16 +13,11 @@ nssa_core.workspace = true anyhow.workspace = true thiserror.workspace = true -serde_json.workspace = true serde.workspace = true serde_with.workspace = true -reqwest.workspace = true +base64.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/common/src/block.rs b/common/src/block.rs index 8ef2eb0c..11446314 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -60,6 +60,18 @@ pub struct Block { pub bedrock_parent_id: MantleMsgId, } +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, 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/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..a7744d63 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,10 +4,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; pub mod block; +mod borsh_base64; 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/test_utils.rs b/common/src/test_utils.rs index d5b6a437..720bd2f9 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -68,7 +68,7 @@ pub fn create_transaction_native_token_transfer( signing_key: &nssa::PrivateKey, ) -> NSSATransaction { let account_ids = vec![from, to]; - let nonces = vec![nonce]; + let nonces = vec![nonce.into()]; let program_id = nssa::program::Program::authenticated_transfer_program().id(); let message = nssa::public_transaction::Message::try_new( program_id, diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 8fdc2074..29ae8caf 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -12,6 +12,18 @@ pub enum NSSATransaction { 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 { @@ -87,7 +99,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/configs/docker-all-in-one/sequencer/sequencer_config.json b/configs/docker-all-in-one/sequencer/sequencer_config.json index 8fc34911..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_runner", - "override_rust_log": null, + "home": "/var/lib/sequencer_service", "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/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/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 5e7df2d2..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 @@ -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_with_authorization.rs` guest program with: @@ -71,7 +73,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/Cargo.toml b/indexer/core/Cargo.toml index 8129c1ea..13e81088 100644 --- a/indexer/core/Cargo.toml +++ b/indexer/core/Cargo.toml @@ -28,4 +28,3 @@ async-stream.workspace = true [dev-dependencies] tempfile.workspace = true - diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index db2f855b..bf3516e3 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( @@ -171,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/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/configs/indexer_config.json b/indexer/service/configs/indexer_config.json index bcefffce..e4dd8f93 100644 --- a/indexer/service/configs/indexer_config.json +++ b/indexer/service/configs/indexer_config.json @@ -11,50 +11,50 @@ "channel_id": "0101010101010101010101010101010101010101010101010101010101010101", "initial_accounts": [ { - "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", + "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", "balance": 10000 }, { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", + "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", "balance": 20000 } ], "initial_commitments": [ { - "npk":[ - 177, - 64, - 1, + "npk": [ + 139, + 19, + 158, 11, - 87, - 38, - 254, - 159, + 155, 231, - 165, - 1, - 94, - 64, - 137, - 243, - 76, - 249, - 101, - 251, - 129, - 33, - 101, - 189, - 30, - 42, - 11, - 191, - 34, - 103, - 186, - 227, - 230 - ] , + 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 + ], "account": { "program_owner": [ 0, @@ -73,38 +73,38 @@ }, { "npk": [ - 32, - 67, - 72, - 164, - 106, - 53, - 66, - 239, - 141, - 15, - 52, - 230, - 136, - 177, - 2, - 236, - 207, - 243, + 173, 134, - 135, - 210, - 143, - 87, - 232, + 33, + 223, + 54, + 226, + 10, + 71, 215, - 128, - 194, - 120, - 113, - 224, - 4, - 165 + 254, + 143, + 172, + 24, + 244, + 243, + 208, + 65, + 112, + 118, + 70, + 217, + 240, + 69, + 100, + 129, + 3, + 121, + 25, + 213, + 132, + 42, + 45 ], "account": { "program_owner": [ @@ -157,4 +157,4 @@ 37, 37 ] -} +} \ No newline at end of file diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index cbafa0b3..6114620f 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -1,5 +1,7 @@ //! Conversions between `indexer_service_protocol` types and `nssa/nssa_core` types. +use nssa_core::account::Nonce; + use crate::{ Account, AccountId, BedrockStatus, Block, BlockBody, BlockHeader, Ciphertext, Commitment, CommitmentSetDigest, Data, EncryptedAccountData, EphemeralPublicKey, HashType, MantleMsgId, @@ -52,7 +54,7 @@ impl From for Account { program_owner: program_owner.into(), balance, data: data.into(), - nonce, + nonce: nonce.0, } } } @@ -72,7 +74,7 @@ impl TryFrom for nssa_core::account::Account { program_owner: program_owner.into(), balance, data: data.try_into()?, - nonce, + nonce: Nonce(nonce), }) } } @@ -250,7 +252,7 @@ impl From for PublicMessage { Self { program_id: program_id.into(), account_ids: account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces.iter().map(|x| x.0).collect(), instruction_data, } } @@ -267,7 +269,10 @@ impl From for nssa::public_transaction::Message { Self::new_preserialized( program_id.into(), account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), instruction_data, ) } @@ -285,7 +290,7 @@ impl From for PrivacyPre } = value; Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces.iter().map(|x| x.0).collect(), public_post_states: public_post_states.into_iter().map(Into::into).collect(), encrypted_private_post_states: encrypted_private_post_states .into_iter() @@ -314,7 +319,10 @@ impl TryFrom for nssa::privacy_preserving_transaction: } = value; Ok(Self { public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), - nonces, + nonces: nonces + .iter() + .map(|x| nssa_core::account::Nonce(*x)) + .collect(), public_post_states: public_post_states .into_iter() .map(TryInto::try_into) @@ -351,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, + } } } @@ -368,7 +380,7 @@ impl From for Wit .into_iter() .map(|(sig, pk)| (sig.into(), pk.into())) .collect(), - proof: proof.into(), + proof: Some(proof.into()), } } } @@ -388,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_owned()))?, )) } } @@ -408,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/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 1f87e929..10f1cade 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; @@ -13,10 +13,11 @@ pub mod mock_service; pub struct IndexerHandle { addr: SocketAddr, - server_handle: Option, + /// Option because of `Drop` which forbids to simply move out of `self` in `stopped()`. + 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), @@ -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 { + pub fn is_healthy(&self) -> bool { self.server_handle .as_ref() - .is_none_or(|handle| handle.is_stopped()) + .is_some_and(|handle| !handle.is_stopped()) } } diff --git a/indexer/service/src/mock_service.rs b/indexer/service/src/mock_service.rs index bc131740..eb6f11f7 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, @@ -198,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 { @@ -227,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 256ef33d..e2f8a321 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, @@ -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 b18b782f..c88ec1fd 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 @@ -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 @@ -26,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/config.rs b/integration_tests/src/config.rs index 0ce55177..22444458 100644 --- a/integration_tests/src/config.rs +++ b/integration_tests/src/config.rs @@ -59,11 +59,11 @@ impl InitialData { let mut private_charlie_key_chain = KeyChain::new_os_random(); let mut private_charlie_account_id = - AccountId::from(&private_charlie_key_chain.nullifer_public_key); + AccountId::from(&private_charlie_key_chain.nullifier_public_key); let mut private_david_key_chain = KeyChain::new_os_random(); let mut private_david_account_id = - AccountId::from(&private_david_key_chain.nullifer_public_key); + AccountId::from(&private_david_key_chain.nullifier_public_key); // Ensure consistent ordering if private_charlie_account_id > private_david_account_id { @@ -86,7 +86,7 @@ impl InitialData { balance: 10_000, data: Data::default(), program_owner: DEFAULT_PROGRAM_ID, - nonce: 0, + nonce: 0_u128.into(), }, ), ( @@ -95,7 +95,7 @@ impl InitialData { balance: 20_000, data: Data::default(), program_owner: DEFAULT_PROGRAM_ID, - nonce: 0, + nonce: 0_u128.into(), }, ), ], @@ -120,7 +120,7 @@ impl InitialData { self.private_accounts .iter() .map(|(key_chain, account)| CommitmentsInitialData { - npk: key_chain.nullifer_public_key.clone(), + npk: key_chain.nullifier_public_key.clone(), account: account.clone(), }) .collect() @@ -138,7 +138,7 @@ impl InitialData { }) }) .chain(self.private_accounts.iter().map(|(key_chain, account)| { - let account_id = AccountId::from(&key_chain.nullifer_public_key); + let account_id = AccountId::from(&key_chain.nullifier_public_key); InitialAccountData::Private(Box::new(InitialAccountDataPrivate { account_id, account: account.clone(), @@ -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], @@ -236,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/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 6929ec92..08e7cf9f 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -3,15 +3,15 @@ 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}; 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 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_runner::startup_sequencer(config).await?; + let sequencer_handle = sequencer_service::run(config, 0).await?; Ok((sequencer_handle, temp_sequencer_dir)) } @@ -333,18 +335,20 @@ 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_healthy() { + let Err(err) = sequencer_handle + .failed() .now_or_never() - .expect("Future is finished and should be ready"); + .expect("Sequencer handle should not be running"); error!( - "Sequencer handle has unexpectedly finished before TestContext drop with error: {err:#}" + "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"); } @@ -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,10 @@ 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 + .ok() + .flatten() + .is_some() } diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index 02813b4c..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, @@ -30,7 +30,7 @@ async fn get_existing_account() -> Result<()> { ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); - assert_eq!(account.nonce, 0); + assert_eq!(account.nonce.0, 0); info!("Successfully retrieved account with correct details"); 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 fb5643c8..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"); @@ -175,7 +176,7 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: format_private_account_id(from), to: None, - to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, }); @@ -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"); @@ -335,7 +336,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: format_private_account_id(from), to: None, - to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, }); diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 75ae2c12..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,18 +231,14 @@ 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, Program::authenticated_transfer_program().id() ); assert_eq!(account.balance, 0); - assert_eq!(account.nonce, 1); + assert_eq!(account.nonce.0, 1); assert!(account.data.is_empty()); info!("Successfully initialized public account"); 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 f438ef70..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, @@ -70,7 +71,7 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: format_private_account_id(from), to: None, - to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), amount: 100, }); @@ -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 76837576..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,23 +49,22 @@ 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); assert_eq!(post_state_account.data.as_ref(), &[0]); - assert_eq!(post_state_account.nonce, 0); + assert_eq!(post_state_account.nonce.0, 0); info!("Successfully deployed and executed program"); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index d3fbfdc1..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, @@ -1123,7 +1110,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { let subcommand = TokenProgramAgnosticSubcommand::Mint { definition: format_private_account_id(definition_account_id), holder: None, - holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)), + holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)), holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)), amount: mint_amount, }; diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index c89ee761..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}, @@ -27,9 +28,10 @@ use nssa::{ }; use nssa_core::{ MembershipProof, NullifierPublicKey, - account::{AccountWithMetadata, data::Data}, + account::{AccountWithMetadata, Nonce, data::Data}, encryption::ViewingPublicKey, }; +use sequencer_service_rpc::RpcClient as _; use tokio::test; pub(crate) struct TpsTestManager { @@ -78,7 +80,7 @@ impl TpsTestManager { let message = putx::Message::try_new( program.id(), [pair[0].1, pair[1].1].to_vec(), - [0_u128].to_vec(), + [Nonce(0_u128)].to_vec(), amount, ) .unwrap(); @@ -107,7 +109,7 @@ impl TpsTestManager { let key_chain = KeyChain::new_os_random(); let account = Account { balance: 100, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), program_owner: Program::authenticated_transfer_program().id(), data: Data::default(), }; @@ -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; } @@ -216,7 +215,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), program_owner: program.id(), data: Data::default(), }, @@ -250,7 +249,6 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_npk.clone(), sender_ss), (recipient_npk.clone(), recipient_ss), diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 2170734c..dad4c79e 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -491,7 +491,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); - assert_eq!(account.nonce, 0); + assert_eq!(account.nonce.0, 0); unsafe { wallet_ffi_free_account_data(&raw mut out_account); @@ -528,7 +528,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); - assert_eq!(account.nonce, 0); + assert_eq!(account.nonce, 0_u128.into()); unsafe { wallet_ffi_free_account_data(&raw mut out_account); @@ -606,7 +606,7 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> { .unwrap() .0; - let expected_npk = &key_chain.nullifer_public_key; + let expected_npk = &key_chain.nullifier_public_key; let expected_vpk = &key_chain.viewing_public_key; assert_eq!(&keys.npk(), expected_npk); 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/key_tree/keys_private.rs b/key_protocol/src/key_management/key_tree/keys_private.rs index 3fcbb0d2..0b20a310 100644 --- a/key_protocol/src/key_management/key_tree/keys_private.rs +++ b/key_protocol/src/key_management/key_tree/keys_private.rs @@ -39,7 +39,7 @@ impl KeyNode for ChildKeysPrivate { value: ( KeyChain { secret_spending_key: ssk, - nullifer_public_key: npk, + nullifier_public_key: npk, viewing_public_key: vpk, private_key_holder: PrivateKeyHolder { nullifier_secret_key: nsk, @@ -54,10 +54,7 @@ impl KeyNode for ChildKeysPrivate { } fn nth_child(&self, cci: u32) -> Self { - #[expect( - clippy::arithmetic_side_effects, - reason = "Multiplying finite field scalars gives no unexpected side effects" - )] + #[expect(clippy::arithmetic_side_effects, reason = "TODO: fix later")] let parent_pt = Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into()) .expect("Key generated as scalar, must be valid representation") @@ -67,7 +64,8 @@ impl KeyNode for ChildKeysPrivate { input.extend_from_slice(b"LEE_seed_priv"); input.extend_from_slice(&parent_pt.to_bytes()); - input.extend_from_slice(&cci.to_le_bytes()); + #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] + input.extend_from_slice(&cci.to_be_bytes()); let hash_value = hmac_sha512::HMAC::mac(input, self.ccc); @@ -90,7 +88,7 @@ impl KeyNode for ChildKeysPrivate { value: ( KeyChain { secret_spending_key: ssk, - nullifer_public_key: npk, + nullifier_public_key: npk, viewing_public_key: vpk, private_key_holder: PrivateKeyHolder { nullifier_secret_key: nsk, @@ -113,18 +111,26 @@ impl KeyNode for ChildKeysPrivate { } fn account_id(&self) -> nssa::AccountId { - nssa::AccountId::from(&self.value.0.nullifer_public_key) + nssa::AccountId::from(&self.value.0.nullifier_public_key) } } -impl<'keys> From<&'keys ChildKeysPrivate> for &'keys (KeyChain, nssa::Account) { - fn from(value: &'keys ChildKeysPrivate) -> Self { +#[expect( + clippy::single_char_lifetime_names, + reason = "TODO add meaningful name" +)] +impl<'a> From<&'a ChildKeysPrivate> for &'a (KeyChain, nssa::Account) { + fn from(value: &'a ChildKeysPrivate) -> Self { &value.value } } -impl<'keys> From<&'keys mut ChildKeysPrivate> for &'keys mut (KeyChain, nssa::Account) { - fn from(value: &'keys mut ChildKeysPrivate) -> Self { +#[expect( + clippy::single_char_lifetime_names, + reason = "TODO add meaningful name" +)] +impl<'a> From<&'a mut ChildKeysPrivate> for &'a mut (KeyChain, nssa::Account) { + fn from(value: &'a mut ChildKeysPrivate) -> Self { &mut value.value } } @@ -166,7 +172,7 @@ mod tests { 7, 123, 125, 191, 233, 183, 201, 4, 20, 214, 155, 210, 45, 234, 27, 240, 194, 111, 97, 247, 155, 113, 122, 246, 192, 0, 70, 61, 76, 71, 70, 2, ]); - let expected_vsk: ViewingSecretKey = [ + let expected_vsk = [ 155, 90, 54, 75, 228, 130, 68, 201, 129, 251, 180, 195, 250, 64, 34, 230, 241, 204, 216, 50, 149, 156, 10, 67, 208, 74, 9, 10, 47, 59, 50, 202, ]; @@ -179,7 +185,7 @@ mod tests { assert!(expected_ssk == keys.value.0.secret_spending_key); assert!(expected_ccc == keys.ccc); assert!(expected_nsk == keys.value.0.private_key_holder.nullifier_secret_key); - assert!(expected_npk == keys.value.0.nullifer_public_key); + assert!(expected_npk == keys.value.0.nullifier_public_key); assert!(expected_vsk == keys.value.0.private_key_holder.viewing_secret_key); assert!(expected_vpk_as_bytes == keys.value.0.viewing_public_key.to_bytes()); } @@ -197,31 +203,31 @@ mod tests { let child_node = ChildKeysPrivate::nth_child(&root_node, 42_u32); let expected_ccc: [u8; 32] = [ - 145, 59, 225, 32, 54, 168, 14, 45, 60, 253, 57, 202, 31, 86, 142, 234, 51, 57, 154, 88, - 132, 200, 92, 191, 220, 144, 42, 184, 108, 35, 226, 146, + 27, 73, 133, 213, 214, 63, 217, 184, 164, 17, 172, 140, 223, 95, 255, 157, 11, 0, 58, + 53, 82, 147, 121, 120, 199, 50, 30, 28, 103, 24, 121, 187, ]; let expected_nsk: NullifierSecretKey = [ - 19, 100, 119, 73, 191, 225, 234, 219, 129, 88, 40, 229, 63, 225, 189, 136, 69, 172, - 221, 186, 147, 83, 150, 207, 70, 17, 228, 70, 113, 87, 227, 31, + 124, 61, 40, 92, 33, 135, 3, 41, 200, 234, 3, 69, 102, 184, 57, 191, 106, 151, 194, + 192, 103, 132, 141, 112, 249, 108, 192, 117, 24, 48, 70, 216, ]; let expected_npk = nssa_core::NullifierPublicKey([ - 133, 235, 223, 151, 12, 69, 26, 222, 60, 125, 235, 125, 167, 212, 201, 168, 101, 242, - 111, 239, 1, 228, 12, 252, 146, 53, 75, 17, 187, 255, 122, 181, + 116, 231, 246, 189, 145, 240, 37, 59, 219, 223, 216, 246, 116, 171, 223, 55, 197, 200, + 134, 192, 221, 40, 218, 167, 239, 5, 11, 95, 147, 247, 162, 226, ]); let expected_vsk: ViewingSecretKey = [ - 218, 219, 193, 132, 160, 6, 178, 194, 139, 248, 199, 81, 17, 133, 37, 201, 58, 104, 49, - 222, 187, 46, 156, 93, 14, 118, 209, 243, 38, 101, 77, 45, + 33, 155, 68, 60, 102, 70, 47, 105, 194, 129, 44, 26, 143, 198, 44, 244, 185, 31, 236, + 252, 205, 89, 138, 107, 39, 38, 154, 73, 109, 166, 41, 114, ]; let expected_vpk_as_bytes: [u8; 33] = [ - 3, 164, 65, 167, 88, 167, 179, 51, 159, 27, 241, 174, 77, 174, 142, 106, 128, 96, 69, - 74, 117, 231, 42, 193, 235, 153, 206, 116, 102, 7, 101, 192, 45, + 2, 78, 213, 113, 117, 105, 162, 248, 175, 68, 128, 232, 106, 204, 208, 159, 11, 78, 48, + 244, 127, 112, 46, 0, 93, 184, 1, 77, 132, 160, 75, 152, 88, ]; assert!(expected_ccc == child_node.ccc); assert!(expected_nsk == child_node.value.0.private_key_holder.nullifier_secret_key); - assert!(expected_npk == child_node.value.0.nullifer_public_key); + assert!(expected_npk == child_node.value.0.nullifier_public_key); assert!(expected_vsk == child_node.value.0.private_key_holder.viewing_secret_key); assert!(expected_vpk_as_bytes == child_node.value.0.viewing_public_key.to_bytes()); } diff --git a/key_protocol/src/key_management/key_tree/keys_public.rs b/key_protocol/src/key_management/key_tree/keys_public.rs index 470acaaa..73ed7bee 100644 --- a/key_protocol/src/key_management/key_tree/keys_public.rs +++ b/key_protocol/src/key_management/key_tree/keys_public.rs @@ -13,17 +13,25 @@ pub struct ChildKeysPublic { } impl ChildKeysPublic { + #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] fn compute_hash_value(&self, cci: u32) -> [u8; 64] { let mut hash_input = vec![]; - if 2_u32.pow(31) > cci { - // Non-harden - hash_input.extend_from_slice(self.cpk.value()); + if ((2_u32).pow(31)).cmp(&cci) == std::cmp::Ordering::Greater { + // Non-harden. + // BIP-032 compatibility requires 1-byte header from the public_key; + // Not stored in `self.cpk.value()`. + let sk = secp256k1::SecretKey::from_byte_array(*self.csk.value()) + .expect("32 bytes, within curve order"); + let pk = secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &sk); + hash_input.extend_from_slice(&secp256k1::PublicKey::serialize(&pk)); } else { - // Harden + // Harden. + hash_input.extend_from_slice(&[0_u8]); hash_input.extend_from_slice(self.csk.value()); } - hash_input.extend_from_slice(&cci.to_le_bytes()); + + hash_input.extend_from_slice(&cci.to_be_bytes()); hmac_sha512::HMAC::mac(hash_input, self.ccc) } @@ -55,11 +63,13 @@ impl KeyNode for ChildKeysPublic { ) .unwrap(); - let csk = nssa::PrivateKey::try_new( - csk.add_tweak(&Scalar::from_le_bytes(*self.csk.value()).unwrap()) + let csk = nssa::PrivateKey::try_new({ + let scalar = Scalar::from_be_bytes(*self.csk.value()).unwrap(); + + csk.add_tweak(&scalar) .expect("Expect a valid Scalar") - .secret_bytes(), - ) + .secret_bytes() + }) .unwrap(); assert!( @@ -94,8 +104,12 @@ impl KeyNode for ChildKeysPublic { } } -impl<'keys> From<&'keys ChildKeysPublic> for &'keys nssa::PrivateKey { - fn from(value: &'keys ChildKeysPublic) -> Self { +#[expect( + clippy::single_char_lifetime_names, + reason = "TODO add meaningful name" +)] +impl<'a> From<&'a ChildKeysPublic> for &'a nssa::PrivateKey { + fn from(value: &'a ChildKeysPublic) -> Self { &value.csk } } @@ -126,6 +140,7 @@ mod tests { 202, 148, 181, 228, 35, 222, 58, 84, 156, 24, 146, 86, ]) .unwrap(); + let expected_cpk: PublicKey = PublicKey::try_new([ 219, 141, 130, 105, 11, 203, 187, 124, 112, 75, 223, 22, 11, 164, 153, 127, 59, 247, 244, 166, 75, 66, 242, 224, 35, 156, 161, 75, 41, 51, 76, 245, @@ -149,26 +164,20 @@ mod tests { let cci = (2_u32).pow(31) + 13; let child_keys = ChildKeysPublic::nth_child(&root_keys, cci); - print!( - "{} {}", - child_keys.csk.value()[0], - child_keys.csk.value()[1] - ); - let expected_ccc = [ - 126, 175, 244, 41, 41, 173, 134, 103, 139, 140, 195, 86, 194, 147, 116, 48, 71, 107, - 253, 235, 114, 139, 60, 115, 226, 205, 215, 248, 240, 190, 196, 6, + 149, 226, 13, 4, 194, 12, 69, 29, 9, 234, 209, 119, 98, 4, 128, 91, 37, 103, 192, 31, + 130, 126, 123, 20, 90, 34, 173, 209, 101, 248, 155, 36, ]; let expected_csk: PrivateKey = PrivateKey::try_new([ - 128, 148, 53, 165, 222, 155, 163, 108, 186, 182, 124, 67, 90, 86, 59, 123, 95, 224, - 171, 4, 51, 131, 254, 57, 241, 178, 82, 161, 204, 206, 79, 107, + 9, 65, 33, 228, 25, 82, 219, 117, 91, 217, 11, 223, 144, 85, 246, 26, 123, 216, 107, + 213, 33, 52, 188, 22, 198, 246, 71, 46, 245, 174, 16, 47, ]) .unwrap(); let expected_cpk: PublicKey = PublicKey::try_new([ - 149, 240, 55, 15, 178, 67, 245, 254, 44, 141, 95, 223, 238, 62, 85, 11, 248, 9, 11, 40, - 69, 211, 116, 13, 189, 35, 8, 95, 233, 154, 129, 58, + 142, 143, 238, 159, 105, 165, 224, 252, 108, 62, 53, 209, 176, 219, 249, 38, 90, 241, + 201, 81, 194, 146, 236, 5, 83, 152, 238, 243, 138, 16, 229, 15, ]) .unwrap(); @@ -189,26 +198,20 @@ mod tests { let cci = 13; let child_keys = ChildKeysPublic::nth_child(&root_keys, cci); - print!( - "{} {}", - child_keys.csk.value()[0], - child_keys.csk.value()[1] - ); - let expected_ccc = [ - 50, 29, 113, 102, 49, 130, 64, 0, 247, 95, 135, 187, 118, 162, 65, 65, 194, 53, 189, - 242, 66, 178, 168, 2, 51, 193, 155, 72, 209, 2, 207, 251, + 79, 228, 242, 119, 211, 203, 198, 175, 95, 36, 4, 234, 139, 45, 137, 138, 54, 211, 187, + 16, 28, 79, 80, 232, 216, 101, 145, 19, 101, 220, 217, 141, ]; let expected_csk: PrivateKey = PrivateKey::try_new([ - 162, 32, 211, 190, 180, 74, 151, 246, 189, 93, 8, 57, 182, 239, 125, 245, 192, 255, 24, - 186, 251, 23, 194, 186, 252, 121, 190, 54, 147, 199, 1, 109, + 185, 147, 32, 242, 145, 91, 123, 77, 42, 33, 134, 84, 12, 165, 117, 70, 158, 201, 95, + 153, 14, 12, 92, 235, 128, 156, 194, 169, 68, 35, 165, 127, ]) .unwrap(); let expected_cpk: PublicKey = PublicKey::try_new([ - 183, 48, 207, 170, 221, 111, 118, 9, 40, 67, 123, 162, 159, 169, 34, 157, 23, 37, 232, - 102, 231, 187, 199, 191, 205, 146, 159, 22, 79, 100, 10, 223, + 119, 16, 145, 121, 97, 244, 186, 35, 136, 34, 140, 171, 206, 139, 11, 208, 207, 121, + 158, 45, 28, 22, 140, 98, 161, 179, 212, 173, 238, 220, 2, 34, ]) .unwrap(); @@ -230,19 +233,19 @@ mod tests { let child_keys = ChildKeysPublic::nth_child(&root_keys, cci); let expected_ccc = [ - 101, 15, 69, 152, 144, 22, 105, 89, 175, 21, 13, 50, 160, 167, 93, 80, 94, 99, 192, - 252, 1, 126, 196, 217, 149, 164, 60, 75, 237, 90, 104, 83, + 221, 208, 47, 189, 174, 152, 33, 25, 151, 114, 233, 191, 57, 15, 40, 140, 46, 87, 126, + 58, 215, 40, 246, 111, 166, 113, 183, 145, 173, 11, 27, 182, ]; let expected_csk: PrivateKey = PrivateKey::try_new([ - 46, 196, 131, 199, 190, 180, 250, 222, 41, 188, 221, 156, 255, 239, 251, 207, 239, 202, - 166, 216, 107, 236, 195, 48, 167, 69, 97, 13, 132, 117, 76, 89, + 223, 29, 87, 189, 126, 24, 117, 225, 190, 57, 0, 143, 207, 168, 231, 139, 170, 192, 81, + 254, 126, 10, 115, 42, 141, 157, 70, 171, 199, 231, 198, 132, ]) .unwrap(); let expected_cpk: PublicKey = PublicKey::try_new([ - 93, 151, 154, 238, 175, 198, 53, 146, 255, 43, 37, 52, 214, 165, 69, 161, 38, 20, 68, - 166, 143, 80, 149, 216, 124, 203, 240, 114, 168, 111, 33, 83, + 96, 123, 245, 51, 214, 216, 215, 205, 70, 145, 105, 221, 166, 169, 122, 27, 94, 112, + 228, 110, 249, 177, 85, 173, 180, 248, 185, 199, 112, 246, 83, 33, ]) .unwrap(); 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/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index e29e5862..dcdaff45 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -16,7 +16,7 @@ pub type PublicAccountSigningKey = [u8; 32]; pub struct KeyChain { pub secret_spending_key: SecretSpendingKey, pub private_key_holder: PrivateKeyHolder, - pub nullifer_public_key: NullifierPublicKey, + pub nullifier_public_key: NullifierPublicKey, pub viewing_public_key: ViewingPublicKey, } @@ -30,13 +30,13 @@ impl KeyChain { let private_key_holder = secret_spending_key.produce_private_key_holder(None); - let nullifer_public_key = private_key_holder.generate_nullifier_public_key(); + let nullifier_public_key = private_key_holder.generate_nullifier_public_key(); let viewing_public_key = private_key_holder.generate_viewing_public_key(); Self { secret_spending_key, private_key_holder, - nullifer_public_key, + nullifier_public_key, viewing_public_key, } } @@ -50,13 +50,13 @@ impl KeyChain { let private_key_holder = secret_spending_key.produce_private_key_holder(None); - let nullifer_public_key = private_key_holder.generate_nullifier_public_key(); + let nullifier_public_key = private_key_holder.generate_nullifier_public_key(); let viewing_public_key = private_key_holder.generate_viewing_public_key(); Self { secret_spending_key, private_key_holder, - nullifer_public_key, + nullifier_public_key, viewing_public_key, } } @@ -93,7 +93,7 @@ mod tests { // Check that key holder fields are initialized with expected types assert_ne!( - account_id_key_holder.nullifer_public_key.as_ref(), + account_id_key_holder.nullifier_public_key.as_ref(), &[0_u8; 32] ); } @@ -119,7 +119,7 @@ mod tests { let utxo_secret_key_holder = top_secret_key_holder.produce_private_key_holder(None); - let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); + let nullifier_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); let pub_account_signing_key = nssa::PrivateKey::new_os_random(); @@ -150,7 +150,7 @@ mod tests { println!("Account {:?}", account.value().to_base58()); println!( "Nulifier public key {:?}", - hex::encode(nullifer_public_key.to_byte_array()) + hex::encode(nullifier_public_key.to_byte_array()) ); println!( "Viewing public key {:?}", @@ -183,7 +183,7 @@ mod tests { fn non_trivial_chain_index() { let keys = account_with_chain_index_2_for_tests(); - let eph_key_holder = EphemeralKeyHolder::new(&keys.nullifer_public_key); + let eph_key_holder = EphemeralKeyHolder::new(&keys.nullifier_public_key); let key_sender = eph_key_holder.calculate_shared_secret_sender(&keys.viewing_public_key); let key_receiver = keys.calculate_shared_secret_receiver( diff --git a/key_protocol/src/key_management/secret_holders.rs b/key_protocol/src/key_management/secret_holders.rs index db39757e..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; @@ -79,6 +79,7 @@ impl SeedHolder { impl SecretSpendingKey { #[must_use] + #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] pub fn generate_nullifier_secret_key(&self, index: Option) -> NullifierSecretKey { const PREFIX: &[u8; 8] = b"LEE/keys"; const SUFFIX_1: &[u8; 1] = &[1]; @@ -93,13 +94,14 @@ impl SecretSpendingKey { hasher.update(PREFIX); hasher.update(self.0); hasher.update(SUFFIX_1); - hasher.update(index.to_le_bytes()); + hasher.update(index.to_be_bytes()); hasher.update(SUFFIX_2); ::from(hasher.finalize_fixed()) } #[must_use] + #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] pub fn generate_viewing_secret_key(&self, index: Option) -> ViewingSecretKey { const PREFIX: &[u8; 8] = b"LEE/keys"; const SUFFIX_1: &[u8; 1] = &[2]; @@ -114,7 +116,7 @@ impl SecretSpendingKey { hasher.update(PREFIX); hasher.update(self.0); hasher.update(SUFFIX_1); - hasher.update(index.to_le_bytes()); + hasher.update(index.to_be_bytes()); hasher.update(SUFFIX_2); hasher.finalize_fixed().into() diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index abc1135f..8232d9f4 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -46,7 +46,7 @@ impl NSSAUserData { ) -> bool { let mut check_res = true; for (account_id, (key, _)) in accounts_keys_map { - let expected_account_id = nssa::AccountId::from(&key.nullifer_public_key); + let expected_account_id = nssa::AccountId::from(&key.nullifier_public_key); if expected_account_id != *account_id { println!("{expected_account_id}, {account_id}"); check_res = false; @@ -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 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 is 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/nssa/Cargo.toml b/nssa/Cargo.toml index e1b6805f..ceebaa2e 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -14,6 +14,7 @@ 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 @@ -37,4 +38,4 @@ test-case = "3.3.1" [features] default = [] prove = ["risc0-zkvm/prove"] -test-utils = [] \ No newline at end of file +test-utils = [] diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 5eae68ef..0f9248e3 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -6,14 +6,89 @@ use std::{ use base58::{FromBase58 as _, ToBase58 as _}; use borsh::{BorshDeserialize, BorshSerialize}; pub use data::Data; +use risc0_zkvm::sha::{Impl, Sha256 as _}; use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; -use crate::program::ProgramId; +use crate::{NullifierPublicKey, NullifierSecretKey, program::ProgramId}; pub mod data; -pub type Nonce = u128; +#[derive(Copy, Debug, Default, Clone, Eq, PartialEq)] +pub struct Nonce(pub u128); + +impl Nonce { + pub const fn public_account_nonce_increment(&mut self) { + self.0 = self + .0 + .checked_add(1) + .expect("Overflow when incrementing nonce"); + } + + #[must_use] + pub fn private_account_nonce_init(npk: &NullifierPublicKey) -> Self { + let mut bytes: [u8; 64] = [0_u8; 64]; + bytes[..32].copy_from_slice(&npk.0); + let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap(); + let result = result.first_chunk::<16>().unwrap(); + + Self(u128::from_le_bytes(*result)) + } + + #[must_use] + pub fn private_account_nonce_increment(self, nsk: &NullifierSecretKey) -> Self { + let mut bytes: [u8; 64] = [0_u8; 64]; + bytes[..32].copy_from_slice(nsk); + bytes[32..48].copy_from_slice(&self.0.to_le_bytes()); + let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap(); + let result = result.first_chunk::<16>().unwrap(); + + Self(u128::from_le_bytes(*result)) + } +} + +impl From for Nonce { + fn from(value: u128) -> Self { + Self(value) + } +} + +impl From for u128 { + fn from(value: Nonce) -> Self { + value.0 + } +} + +impl Serialize for Nonce { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + Serialize::serialize(&self.0, serializer) + } +} + +impl<'de> Deserialize<'de> for Nonce { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(::deserialize(deserializer)?.into()) + } +} + +impl BorshSerialize for Nonce { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + BorshSerialize::serialize(&self.0, writer) + } +} + +impl BorshDeserialize for Nonce { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + Ok(::deserialize_reader(reader)?.into()) + } +} + pub type Balance = u128; /// Account to be used both in public and private contexts. @@ -154,7 +229,7 @@ mod tests { fn zero_nonce_account_data_creation() { let new_acc = Account::default(); - assert_eq!(new_acc.nonce, 0); + assert_eq!(new_acc.nonce.0, 0); } #[test] @@ -181,7 +256,7 @@ mod tests { .to_vec() .try_into() .unwrap(), - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), }; let fingerprint = AccountId::new([8; 32]); let new_acc_with_metadata = AccountWithMetadata::new(account.clone(), true, fingerprint); @@ -228,4 +303,52 @@ mod tests { let expected_account_id = AccountId::new([0; 32]); assert!(default_account_id == expected_account_id); } + + #[test] + fn initialize_private_nonce() { + let npk = NullifierPublicKey([42; 32]); + let nonce = Nonce::private_account_nonce_init(&npk); + let expected_nonce = Nonce(37_937_661_125_547_691_021_612_781_941_709_513_486); + assert_eq!(nonce, expected_nonce); + } + + #[test] + fn increment_private_nonce() { + let nsk: NullifierSecretKey = [42_u8; 32]; + let nonce = Nonce(37_937_661_125_547_691_021_612_781_941_709_513_486) + .private_account_nonce_increment(&nsk); + let expected_nonce = Nonce(327_300_903_218_789_900_388_409_116_014_290_259_894); + assert_eq!(nonce, expected_nonce); + } + + #[test] + fn increment_public_nonce() { + let value = 42_u128; + let mut nonce = Nonce(value); + nonce.public_account_nonce_increment(); + let expected_nonce = Nonce(value + 1); + assert_eq!(nonce, expected_nonce); + } + + #[test] + fn serde_roundtrip_for_nonce() { + let nonce: Nonce = 7_u128.into(); + + let serde_serialized_nonce = serde_json::to_vec(&nonce).unwrap(); + + let nonce_restored = serde_json::from_slice(&serde_serialized_nonce).unwrap(); + + assert_eq!(nonce, nonce_restored); + } + + #[test] + fn borsh_roundtrip_for_nonce() { + let nonce: Nonce = 7_u128.into(); + + let borsh_serialized_nonce = borsh::to_vec(&nonce).unwrap(); + + let nonce_restored = borsh::from_slice(&borsh_serialized_nonce).unwrap(); + + assert_eq!(nonce, nonce_restored); + } } diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index e4ff6e2d..56d63022 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::{ Commitment, CommitmentSetDigest, MembershipProof, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, - account::{Account, AccountWithMetadata, Nonce}, + account::{Account, AccountWithMetadata}, encryption::Ciphertext, program::{ProgramId, ProgramOutput}, }; @@ -18,8 +18,6 @@ pub struct PrivacyPreservingCircuitInput { /// - `1` - private account with authentication /// - `2` - private account without authentication pub visibility_mask: Vec, - /// Nonces of private accounts. - pub private_account_nonces: Vec, /// Public keys of private accounts. pub private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>, /// Nullifier secret keys for authorized private accounts. @@ -57,7 +55,7 @@ mod tests { use super::*; use crate::{ Commitment, Nullifier, NullifierPublicKey, - account::{Account, AccountId, AccountWithMetadata}, + account::{Account, AccountId, AccountWithMetadata, Nonce}, }; #[test] @@ -69,7 +67,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 12_345_678_901_234_567_890, data: b"test data".to_vec().try_into().unwrap(), - nonce: 0xFFFF_FFFF_FFFF_FFFE, + nonce: Nonce(0xFFFF_FFFF_FFFF_FFFE), }, true, AccountId::new([0; 32]), @@ -79,7 +77,7 @@ mod tests { program_owner: [9, 9, 9, 8, 8, 8, 7, 7], balance: 123_123_123_456_456_567_112, data: b"test data".to_vec().try_into().unwrap(), - nonce: 9_999_999_999_999_999_999_999, + nonce: Nonce(9_999_999_999_999_999_999_999), }, false, AccountId::new([1; 32]), @@ -89,7 +87,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 100, data: b"post state data".to_vec().try_into().unwrap(), - nonce: 0xFFFF_FFFF_FFFF_FFFF, + nonce: Nonce(0xFFFF_FFFF_FFFF_FFFF), }], ciphertexts: vec![Ciphertext(vec![255, 255, 1, 1, 2, 2])], new_commitments: vec![Commitment::new( diff --git a/nssa/core/src/commitment.rs b/nssa/core/src/commitment.rs index c9fcfce0..36730dd0 100644 --- a/nssa/core/src/commitment.rs +++ b/nssa/core/src/commitment.rs @@ -61,7 +61,7 @@ impl Commitment { this.extend_from_slice(&word.to_le_bytes()); } this.extend_from_slice(&account.balance.to_le_bytes()); - this.extend_from_slice(&account.nonce.to_le_bytes()); + this.extend_from_slice(&account.nonce.0.to_le_bytes()); let hashed_data: [u8; 32] = Impl::hash_bytes(&account.data) .as_bytes() .try_into() diff --git a/nssa/core/src/encoding.rs b/nssa/core/src/encoding.rs index 6abd4c11..ac9317c2 100644 --- a/nssa/core/src/encoding.rs +++ b/nssa/core/src/encoding.rs @@ -25,8 +25,8 @@ impl Account { bytes.extend_from_slice(&word.to_le_bytes()); } bytes.extend_from_slice(&self.balance.to_le_bytes()); - bytes.extend_from_slice(&self.nonce.to_le_bytes()); - let data_length: u32 = u32::try_from(self.data.len()).expect("data length fits in u32"); + bytes.extend_from_slice(&self.nonce.0.to_le_bytes()); + let data_length: u32 = u32::try_from(self.data.len()).expect("Invalid u32"); bytes.extend_from_slice(&data_length.to_le_bytes()); bytes.extend_from_slice(self.data.as_ref()); bytes @@ -35,7 +35,7 @@ impl Account { /// Deserializes an account from a cursor. #[cfg(feature = "host")] pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - use crate::account::data::Data; + use crate::account::{Nonce, data::Data}; let mut u32_bytes = [0_u8; 4]; let mut u128_bytes = [0_u8; 16]; @@ -53,7 +53,7 @@ impl Account { // nonce cursor.read_exact(&mut u128_bytes)?; - let nonce = u128::from_le_bytes(u128_bytes); + let nonce = Nonce(u128::from_le_bytes(u128_bytes)); // data let data = Data::from_cursor(cursor)?; @@ -189,7 +189,7 @@ mod tests { let account = Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 123_456_789_012_345_678_901_234_567_890_123_456, - nonce: 42, + nonce: 42_u128.into(), data: b"hola mundo".to_vec().try_into().unwrap(), }; @@ -250,7 +250,7 @@ mod tests { let account = Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 123_456_789_012_345_678_901_234_567_890_123_456, - nonce: 42, + nonce: 42_u128.into(), data: b"hola mundo".to_vec().try_into().unwrap(), }; let bytes = account.to_bytes(); diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index c67a816c..31b76b0f 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -348,7 +348,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 1337, data: vec![0xde, 0xad, 0xbe, 0xef].try_into().unwrap(), - nonce: 10, + nonce: 10_u128.into(), }; let account_post_state = AccountPostState::new_claimed(account.clone()); @@ -363,7 +363,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 1337, data: vec![0xde, 0xad, 0xbe, 0xef].try_into().unwrap(), - nonce: 10, + nonce: 10_u128.into(), }; let account_post_state = AccountPostState::new(account.clone()); @@ -378,7 +378,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 1337, data: vec![0xde, 0xad, 0xbe, 0xef].try_into().unwrap(), - nonce: 10, + nonce: 10_u128.into(), }; let mut account_post_state = AccountPostState::new(account.clone()); diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 084b05db..2ab141a3 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -63,12 +63,11 @@ impl From for ProgramWithDependencies { /// Generates a proof of the execution of a NSSA program inside the privacy preserving execution /// circuit. -#[expect(clippy::too_many_arguments, reason = "TODO: fix later")] +/// TODO: too many parameters. pub fn execute_and_prove( pre_states: Vec, instruction_data: InstructionData, visibility_mask: Vec, - private_account_nonces: Vec, private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>, private_account_nsks: Vec, private_account_membership_proofs: Vec>, @@ -127,7 +126,6 @@ pub fn execute_and_prove( let circuit_input = PrivacyPreservingCircuitInput { program_outputs, visibility_mask, - private_account_nonces, private_account_keys, private_account_nsks, private_account_membership_proofs, @@ -177,7 +175,7 @@ mod tests { use nssa_core::{ Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier, - account::{Account, AccountId, AccountWithMetadata, data::Data}, + account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, }; use super::*; @@ -215,14 +213,14 @@ mod tests { let expected_sender_post = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0, + nonce: Nonce::default(), data: Data::default(), }; let expected_recipient_post = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdead_beef, + nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), data: Data::default(), }; @@ -235,7 +233,6 @@ mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -269,10 +266,11 @@ mod tests { let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); + let sender_nonce = Nonce(0xdead_beef); let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, program_owner: program.id(), data: Data::default(), }, @@ -307,13 +305,13 @@ mod tests { let expected_private_account_1 = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0xdead_beef1, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), ..Default::default() }; let expected_private_account_2 = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdead_beef2, + nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), ..Default::default() }; let expected_new_commitments = vec![ @@ -331,7 +329,6 @@ mod tests { vec![sender_pre, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret_1), (recipient_keys.npk(), shared_secret_2), diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index d164606e..4b93e820 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -140,7 +140,7 @@ pub mod tests { let public_account_ids = vec![AccountId::new([1; 32])]; - let nonces = vec![1, 2, 3]; + let nonces = vec![1_u128.into(), 2_u128.into(), 3_u128.into()]; let public_post_states = vec![Account::default()]; diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 4c4cd0b3..8c84d83c 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -269,7 +269,7 @@ pub mod tests { fn transaction_for_tests() -> PublicTransaction { let (key1, key2, addr1, addr2) = keys_for_tests(); - let nonces = vec![0, 0]; + let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( Program::authenticated_transfer_program().id(), @@ -347,7 +347,7 @@ pub mod tests { fn account_id_list_cant_have_duplicates() { let (key1, _, addr1, _) = keys_for_tests(); let state = state_for_tests(); - let nonces = vec![0, 0]; + let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( Program::authenticated_transfer_program().id(), @@ -367,7 +367,7 @@ pub mod tests { fn number_of_nonces_must_match_number_of_signatures() { let (key1, key2, addr1, addr2) = keys_for_tests(); let state = state_for_tests(); - let nonces = vec![0]; + let nonces = vec![0_u128.into()]; let instruction = 1337; let message = Message::try_new( Program::authenticated_transfer_program().id(), @@ -387,7 +387,7 @@ pub mod tests { fn all_signatures_must_be_valid() { let (key1, key2, addr1, addr2) = keys_for_tests(); let state = state_for_tests(); - let nonces = vec![0, 0]; + let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( Program::authenticated_transfer_program().id(), @@ -408,7 +408,7 @@ pub mod tests { fn nonces_must_match_the_state_current_nonces() { let (key1, key2, addr1, addr2) = keys_for_tests(); let state = state_for_tests(); - let nonces = vec![0, 1]; + let nonces = vec![0_u128.into(), 1_u128.into()]; let instruction = 1337; let message = Message::try_new( Program::authenticated_transfer_program().id(), @@ -428,7 +428,7 @@ pub mod tests { fn program_id_must_belong_to_bulitin_program_ids() { let (key1, key2, addr1, addr2) = keys_for_tests(); let state = state_for_tests(); - let nonces = vec![0, 0]; + let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let unknown_program_id = [0xdead_beef; 8]; let message = diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index 49c18b81..d6b32891 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -67,7 +67,7 @@ mod tests { let pubkey2 = PublicKey::new_from_private_key(&key2); let addr1 = AccountId::from(&pubkey1); let addr2 = AccountId::from(&pubkey2); - let nonces = vec![1, 2]; + let nonces = vec![1_u128.into(), 2_u128.into()]; let instruction = vec![1, 2, 3, 4]; let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap(); diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 63377f15..9dfd47b3 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use borsh::{BorshDeserialize, BorshSerialize}; pub use private_key::PrivateKey; pub use public_key::PublicKey; @@ -12,11 +14,27 @@ pub struct Signature { } 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/nssa/src/state.rs b/nssa/src/state.rs index c1f72b4c..8ae26e74 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, - account::{Account, AccountId}, + account::{Account, AccountId, Nonce}, program::ProgramId, }; @@ -172,10 +172,7 @@ impl V02State { for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce = current_account - .nonce - .checked_add(1) - .ok_or(NssaError::MaxAccountNonceReached)?; + current_account.nonce.public_account_nonce_increment(); } Ok(()) @@ -215,10 +212,7 @@ impl V02State { // 5. Increment nonces for public signers for account_id in tx.signer_account_ids() { let current_account = self.get_account_by_id_mut(account_id); - current_account.nonce = current_account - .nonce - .checked_add(1) - .ok_or(NssaError::MaxAccountNonceReached)?; + current_account.nonce.public_account_nonce_increment(); } Ok(()) @@ -303,7 +297,7 @@ impl V02State { balance: 1_500_000, // Difficulty: 3 data: vec![3; 33].try_into().expect("should fit"), - nonce: 0, + nonce: Nonce::default(), }, ); } @@ -389,7 +383,7 @@ pub mod tests { ..Account::default() }; let account_with_default_values_except_nonce = Account { - nonce: 37, + nonce: Nonce(37), ..Account::default() }; let account_with_default_values_except_data = Account { @@ -463,7 +457,7 @@ pub mod tests { balance: u128, ) -> PublicTransaction { let account_ids = vec![from, to]; - let nonces = vec![nonce]; + let nonces = vec![Nonce(nonce)]; let program_id = Program::authenticated_transfer_program().id(); let message = public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); @@ -577,8 +571,8 @@ pub mod tests { assert_eq!(state.get_account_by_id(from).balance, 95); assert_eq!(state.get_account_by_id(to).balance, 5); - assert_eq!(state.get_account_by_id(from).nonce, 1); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -599,8 +593,8 @@ pub mod tests { assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); assert_eq!(state.get_account_by_id(from).balance, 100); assert_eq!(state.get_account_by_id(to).balance, 0); - assert_eq!(state.get_account_by_id(from).nonce, 0); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(0)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -622,8 +616,8 @@ pub mod tests { assert_eq!(state.get_account_by_id(from).balance, 192); assert_eq!(state.get_account_by_id(to).balance, 108); - assert_eq!(state.get_account_by_id(from).nonce, 1); - assert_eq!(state.get_account_by_id(to).nonce, 0); + assert_eq!(state.get_account_by_id(from).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(to).nonce, Nonce(0)); } #[test] @@ -646,9 +640,9 @@ pub mod tests { assert_eq!(state.get_account_by_id(account_id1).balance, 95); assert_eq!(state.get_account_by_id(account_id2).balance, 2); assert_eq!(state.get_account_by_id(account_id3).balance, 3); - assert_eq!(state.get_account_by_id(account_id1).nonce, 1); - assert_eq!(state.get_account_by_id(account_id2).nonce, 1); - assert_eq!(state.get_account_by_id(account_id3).nonce, 0); + assert_eq!(state.get_account_by_id(account_id1).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(account_id2).nonce, Nonce(1)); + assert_eq!(state.get_account_by_id(account_id3).nonce, Nonce(0)); } #[test] @@ -942,7 +936,6 @@ pub mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -967,7 +960,6 @@ pub mod tests { sender_private_account: &Account, recipient_keys: &TestPrivateKeys, balance_to_move: u128, - new_nonces: [Nonce; 2], state: &V02State, ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); @@ -989,7 +981,6 @@ pub mod tests { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - new_nonces.to_vec(), vec![ (sender_keys.npk(), shared_secret_1), (recipient_keys.npk(), shared_secret_2), @@ -1021,7 +1012,6 @@ pub mod tests { sender_private_account: &Account, recipient_account_id: &AccountId, balance_to_move: u128, - new_nonce: Nonce, state: &V02State, ) -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); @@ -1042,7 +1032,6 @@ pub mod tests { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 0], - vec![new_nonce], vec![(sender_keys.npk(), shared_secret)], vec![sender_keys.nsk], vec![state.get_proof_for_commitment(&sender_commitment)], @@ -1083,7 +1072,7 @@ pub mod tests { let expected_sender_post = { let mut this = state.get_account_by_id(sender_keys.account_id()); this.balance -= balance_to_move; - this.nonce += 1; + this.nonce.public_account_nonce_increment(); this }; @@ -1107,10 +1096,12 @@ pub mod tests { #[test] fn transition_from_privacy_preserving_transaction_private() { let sender_keys = test_private_account_keys_1(); + let sender_nonce = Nonce(0xdead_beef); + let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -1125,7 +1116,6 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -1133,7 +1123,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafe_cafe, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1147,7 +1137,7 @@ pub mod tests { &recipient_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xfeca_feca, + nonce: Nonce::private_account_nonce_init(&recipient_keys.npk()), balance: balance_to_move, ..Account::default() }, @@ -1173,10 +1163,12 @@ pub mod tests { #[test] fn transition_from_privacy_preserving_transaction_deshielded() { let sender_keys = test_private_account_keys_1(); + let sender_nonce = Nonce(0xdead_beef); + let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_public_account_keys_1(); @@ -1200,7 +1192,6 @@ pub mod tests { &sender_private_account, &recipient_keys.account_id(), balance_to_move, - 0xcafe_cafe, &state, ); @@ -1208,7 +1199,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafe_cafe, + nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1257,7 +1248,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1284,7 +1274,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1311,7 +1300,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1338,7 +1326,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1373,7 +1360,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1400,7 +1386,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1436,7 +1421,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1463,7 +1447,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1499,7 +1482,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1537,7 +1519,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -1561,13 +1542,10 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); - // Setting only one nonce for an execution with two private accounts. - let private_account_nonces = [0xdead_beef1]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - private_account_nonces.to_vec(), vec![ ( sender_keys.npk(), @@ -1611,7 +1589,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -1644,7 +1621,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1686,7 +1662,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1744,7 +1719,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), private_account_nsks.to_vec(), private_account_membership_proofs.to_vec(), @@ -1782,7 +1756,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1829,7 +1802,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1876,7 +1848,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1912,7 +1883,7 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new( Account { // Non default nonce - nonce: 0xdead_beef, + nonce: Nonce(0xdead_beef), ..Account::default() }, false, @@ -1923,7 +1894,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1968,7 +1938,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2010,7 +1979,6 @@ pub mod tests { vec![], vec![], vec![], - vec![], &program.into(), ); @@ -2034,14 +2002,10 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); - // Setting three new private account nonces for a circuit execution with only two private - // accounts. - let private_account_nonces = [0xdead_beef1, 0xdead_beef2, 0xdead_beef3]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - private_account_nonces.to_vec(), vec![ ( sender_keys.npk(), @@ -2097,7 +2061,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), vec![1, 2], - vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -2133,7 +2096,6 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10_u128).unwrap(), visibility_mask.to_vec(), - vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2155,10 +2117,12 @@ pub mod tests { #[test] fn private_accounts_can_only_be_initialized_once() { let sender_keys = test_private_account_keys_1(); + let sender_nonce = Nonce(0xdead_beef); + let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdead_beef, + nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -2167,13 +2131,13 @@ pub mod tests { .with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; + let balance_to_move_2 = 30; let tx = private_balance_transfer_for_tests( &sender_keys, &sender_private_account, &recipient_keys, balance_to_move, - [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -2183,8 +2147,8 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), - balance: 100 - balance_to_move, - nonce: 0xcafe_cafe, + balance: 100, + nonce: sender_nonce, data: Data::default(), }; @@ -2192,8 +2156,7 @@ pub mod tests { &sender_keys, &sender_private_account, &recipient_keys, - balance_to_move, - [0x1234, 0x5678], + balance_to_move_2, &state, ); @@ -2229,7 +2192,6 @@ pub mod tests { vec![private_account_1.clone(), private_account_1], Program::serialize_instruction(100_u128).unwrap(), visibility_mask.to_vec(), - vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret), (sender_keys.npk(), shared_secret), @@ -2265,9 +2227,13 @@ pub mod tests { ..Account::default() }; - let message = - public_transaction::Message::try_new(program.id(), vec![from, to], vec![0], amount) - .unwrap(); + let message = public_transaction::Message::try_new( + program.id(), + vec![from, to], + vec![Nonce(0)], + amount, + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); let tx = PublicTransaction::new(message, witness_set); @@ -2307,7 +2273,7 @@ pub mod tests { program.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2347,7 +2313,7 @@ pub mod tests { program.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2444,7 +2410,7 @@ pub mod tests { chain_caller.id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call - vec![0], + vec![Nonce(0)], instruction, ) .unwrap(); @@ -2514,8 +2480,8 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); - let from_new_nonce = 0xdead_beef1; - let to_new_nonce = 0xdead_beef2; + let from_new_nonce = Nonce::default().private_account_nonce_increment(&from_keys.nsk); + let to_new_nonce = Nonce::default().private_account_nonce_increment(&to_keys.nsk); let from_expected_post = Account { balance: initial_balance - u128::from(number_of_calls) * amount, @@ -2536,7 +2502,6 @@ pub mod tests { vec![to_account, from_account], Program::serialize_instruction(instruction).unwrap(), vec![1, 1], - vec![from_new_nonce, to_new_nonce], vec![(from_keys.npk(), to_ss), (to_keys.npk(), from_ss)], vec![from_keys.nsk, to_keys.nsk], vec![ @@ -2732,14 +2697,14 @@ pub mod tests { let expected_sender_post = { let mut this = state.get_account_by_id(sender_id); this.balance = sender_init_balance; - this.nonce = 0; + this.nonce = Nonce(0); this }; let expected_recipient_post = { let mut this = state.get_account_by_id(sender_id); this.balance = recipient_init_balance; - this.nonce = 0; + this.nonce = Nonce(0); this }; @@ -2768,14 +2733,11 @@ pub mod tests { // Balance to initialize the account with (0 for a new account) let balance: u128 = 0; - let nonce = 0xdead_beef1; - // Execute and prove the circuit with the authorized account but no commitment proof let (output, proof) = execute_and_prove( vec![authorized_account], Program::serialize_instruction(balance).unwrap(), vec![1], - vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -2821,14 +2783,12 @@ pub mod tests { let epk = EphemeralPublicKey::from_scalar(esk); let balance: u128 = 0; - let nonce = 0xdead_beef1; // Step 2: Execute claimer program to claim the account with authentication let (output, proof) = execute_and_prove( vec![authorized_account.clone()], Program::serialize_instruction(balance).unwrap(), vec![1], - vec![nonce], vec![(private_keys.npk(), shared_secret)], vec![private_keys.nsk], vec![None], @@ -2869,14 +2829,11 @@ pub mod tests { let esk2 = [4; 32]; let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.vpk()); - let nonce2 = 0xdead_beef2; - // Step 3: Try to execute noop program with authentication but without initialization let res = execute_and_prove( vec![account_metadata], Program::serialize_instruction(()).unwrap(), vec![1], - vec![nonce2], vec![(private_keys.npk(), shared_secret2)], vec![private_keys.nsk], vec![None], @@ -2946,7 +2903,6 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], - vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -2974,7 +2930,6 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![1], - vec![2], vec![( sender_keys.npk(), SharedSecretKey::new(&[3; 32], &sender_keys.vpk()), @@ -3026,14 +2981,11 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); - let recipient_new_nonce = 0xdead_beef1; - // Act - execute the malicious program - this should fail during proving let result = execute_and_prove( vec![sender_account, recipient_account], Program::serialize_instruction(instruction).unwrap(), vec![0, 1], - vec![recipient_new_nonce], vec![(recipient_keys.npk(), recipient)], vec![recipient_keys.nsk], vec![state.get_proof_for_commitment(&recipient_commitment)], diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/program_methods/guest/src/bin/privacy_preserving_circuit.rs index b74b3e65..99782d7f 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -200,7 +200,6 @@ impl ExecutionState { fn compute_circuit_output( execution_state: ExecutionState, visibility_mask: &[u8], - private_account_nonces: &[Nonce], private_account_keys: &[(NullifierPublicKey, SharedSecretKey)], private_account_nsks: &[NullifierSecretKey], private_account_membership_proofs: &[Option], @@ -220,7 +219,6 @@ fn compute_circuit_output( "Invalid visibility mask length" ); - let mut private_nonces_iter = private_account_nonces.iter(); let mut private_keys_iter = private_account_keys.iter(); let mut private_nsks_iter = private_account_nsks.iter(); let mut private_membership_proofs_iter = private_account_membership_proofs.iter(); @@ -246,7 +244,7 @@ fn compute_circuit_output( "AccountId mismatch" ); - let new_nullifier = if account_visibility_mask == 1 { + let (new_nullifier, new_nonce) = if account_visibility_mask == 1 { // Private account with authentication let Some(nsk) = private_nsks_iter.next() else { @@ -270,12 +268,16 @@ fn compute_circuit_output( panic!("Missing membership proof"); }; - compute_nullifier_and_set_digest( + let new_nullifier = compute_nullifier_and_set_digest( membership_proof_opt.as_ref(), &pre_state.account, npk, nsk, - ) + ); + + let new_nonce = pre_state.account.nonce.private_account_nonce_increment(nsk); + + (new_nullifier, new_nonce) } else { // Private account without authentication @@ -300,16 +302,16 @@ fn compute_circuit_output( ); let nullifier = Nullifier::for_account_initialization(npk); - (nullifier, DUMMY_COMMITMENT_HASH) + + let new_nonce = Nonce::private_account_nonce_init(npk); + + ((nullifier, DUMMY_COMMITMENT_HASH), new_nonce) }; output.new_nullifiers.push(new_nullifier); // Update post-state with new nonce let mut post_with_updated_nonce = post_state; - let Some(new_nonce) = private_nonces_iter.next() else { - panic!("Missing private account nonce"); - }; - post_with_updated_nonce.nonce = *new_nonce; + post_with_updated_nonce.nonce = new_nonce; // Compute commitment let commitment_post = Commitment::new(npk, &post_with_updated_nonce); @@ -332,8 +334,6 @@ fn compute_circuit_output( } } - assert!(private_nonces_iter.next().is_none(), "Too many nonces"); - assert!( private_keys_iter.next().is_none(), "Too many private account keys" @@ -386,7 +386,6 @@ fn main() { let PrivacyPreservingCircuitInput { program_outputs, visibility_mask, - private_account_nonces, private_account_keys, private_account_nsks, private_account_membership_proofs, @@ -398,7 +397,6 @@ fn main() { let output = compute_circuit_output( execution_state, &visibility_mask, - &private_account_nonces, &private_account_keys, &private_account_nsks, &private_account_membership_proofs, diff --git a/programs/amm/Cargo.toml b/programs/amm/Cargo.toml index 449d5dcc..4fcadb9f 100644 --- a/programs/amm/Cargo.toml +++ b/programs/amm/Cargo.toml @@ -8,10 +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"] \ No newline at end of file +[dev-dependencies] +nssa = { workspace = true, features = ["test-utils"] } diff --git a/programs/amm/src/tests.rs b/programs/amm/src/tests.rs index 9509d39e..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") @@ -446,7 +444,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::user_token_a_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::user_token_a_id(), @@ -462,7 +460,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::user_token_b_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::user_token_b_id(), @@ -478,7 +476,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_init(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_a_id(), @@ -494,7 +492,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_init(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_b_id(), @@ -510,7 +508,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_high(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_a_id(), @@ -526,7 +524,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_high(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_b_id(), @@ -542,7 +540,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_low(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_a_id(), @@ -558,7 +556,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_low(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_b_id(), @@ -574,7 +572,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_a_id(), @@ -590,7 +588,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_b_id(), @@ -607,7 +605,7 @@ impl AccountWithMetadataForTests { total_supply: BalanceForTests::lp_supply_init(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::token_lp_definition_id(), @@ -624,7 +622,7 @@ impl AccountWithMetadataForTests { total_supply: BalanceForTests::lp_supply_init(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::vault_a_id(), @@ -640,7 +638,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_lp_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::user_token_lp_id(), @@ -656,7 +654,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_lp_definition_id(), balance: BalanceForTests::user_token_lp_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::user_token_lp_id(), @@ -680,7 +678,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -704,7 +702,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -728,7 +726,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -752,7 +750,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -776,7 +774,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -800,7 +798,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -824,7 +822,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -848,7 +846,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -872,7 +870,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -896,7 +894,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -920,7 +918,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: false, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -944,7 +942,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: false, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: AccountId::new([4; 32]), @@ -960,7 +958,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_a_definition_id(), balance: BalanceForTests::vault_a_reserve_init(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: AccountId::new([4; 32]), @@ -976,7 +974,7 @@ impl AccountWithMetadataForTests { definition_id: IdForTests::token_b_definition_id(), balance: BalanceForTests::vault_b_reserve_init(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: AccountId::new([4; 32]), @@ -1000,7 +998,7 @@ impl AccountWithMetadataForTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -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 { @@ -1239,7 +1234,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1251,7 +1246,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1271,7 +1266,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1284,7 +1279,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::token_a_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1297,7 +1292,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::token_b_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1310,7 +1305,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::token_lp_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1322,7 +1317,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::vault_a_balance_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1334,7 +1329,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::vault_b_balance_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1346,7 +1341,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_lp_definition_id(), balance: BalanceForExeTests::user_token_lp_holding_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1358,7 +1353,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::vault_a_balance_swap_1(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1370,7 +1365,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::vault_b_balance_swap_1(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1390,7 +1385,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1402,7 +1397,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_swap_1(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1414,7 +1409,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_swap_1(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1426,7 +1421,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::vault_a_balance_swap_2(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1438,7 +1433,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::vault_b_balance_swap_2(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1458,7 +1453,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1470,7 +1465,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_swap_2(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1482,7 +1477,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_swap_2(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1494,7 +1489,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::vault_a_balance_add(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1506,7 +1501,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::vault_b_balance_add(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1526,7 +1521,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1538,7 +1533,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_add(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1550,7 +1545,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_add(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1562,7 +1557,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_lp_definition_id(), balance: BalanceForExeTests::user_token_lp_holding_add(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1575,7 +1570,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::token_lp_supply_add(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1587,7 +1582,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::vault_a_balance_remove(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1599,7 +1594,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::vault_b_balance_remove(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1619,7 +1614,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1631,7 +1626,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_remove(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1643,7 +1638,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_remove(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1655,7 +1650,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_lp_definition_id(), balance: BalanceForExeTests::user_token_lp_holding_remove(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1668,7 +1663,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::token_lp_supply_remove(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1681,7 +1676,7 @@ impl AccountsForExeTests { total_supply: 0, metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1693,7 +1688,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1705,7 +1700,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1725,7 +1720,7 @@ impl AccountsForExeTests { fees: 0_u128, active: false, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1737,7 +1732,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_a_definition_id(), balance: BalanceForExeTests::user_token_a_holding_new_definition(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1749,7 +1744,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_b_definition_id(), balance: BalanceForExeTests::user_token_b_holding_new_definition(), }), - nonce: 1, + nonce: 1_u128.into(), } } @@ -1761,7 +1756,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_lp_definition_id(), balance: BalanceForExeTests::lp_supply_init(), }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1774,7 +1769,7 @@ impl AccountsForExeTests { total_supply: BalanceForExeTests::lp_supply_init(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1794,7 +1789,7 @@ impl AccountsForExeTests { fees: 0_u128, active: true, }), - nonce: 0, + nonce: 0_u128.into(), } } @@ -1806,7 +1801,7 @@ impl AccountsForExeTests { definition_id: IdForExeTests::token_lp_definition_id(), balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), } } } @@ -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(); @@ -2730,7 +2722,7 @@ fn simple_amm_remove() { IdForExeTests::user_token_b_id(), IdForExeTests::user_token_lp_id(), ], - vec![0], + vec![0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -2808,7 +2799,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { IdForExeTests::user_token_b_id(), IdForExeTests::user_token_lp_id(), ], - vec![0, 0], + vec![0_u128.into(), 0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -2893,7 +2883,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { IdForExeTests::user_token_b_id(), IdForExeTests::user_token_lp_id(), ], - vec![0, 0], + vec![0_u128.into(), 0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -2966,7 +2955,7 @@ fn simple_amm_new_definition_uninitialized_pool() { IdForExeTests::user_token_b_id(), IdForExeTests::user_token_lp_id(), ], - vec![0, 0], + vec![0_u128.into(), 0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -3029,7 +3017,7 @@ fn simple_amm_add() { IdForExeTests::user_token_b_id(), IdForExeTests::user_token_lp_id(), ], - vec![0, 0], + vec![0_u128.into(), 0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -3090,7 +3077,7 @@ fn simple_amm_swap_1() { IdForExeTests::user_token_a_id(), IdForExeTests::user_token_b_id(), ], - vec![0], + vec![0_u128.into()], instruction, ) .unwrap(); @@ -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(); @@ -3141,7 +3127,7 @@ fn simple_amm_swap_2() { IdForExeTests::user_token_a_id(), IdForExeTests::user_token_b_id(), ], - vec![0], + vec![0_u128.into()], instruction, ) .unwrap(); diff --git a/programs/token/src/tests.rs b/programs/token/src/tests.rs index db0aa1bb..640d6d76 100644 --- a/programs/token/src/tests.rs +++ b/programs/token/src/tests.rs @@ -37,7 +37,7 @@ impl AccountForTests { total_supply: BalanceForTests::init_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -54,7 +54,7 @@ impl AccountForTests { total_supply: BalanceForTests::init_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::pool_definition_id(), @@ -70,7 +70,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id_diff(), balance: BalanceForTests::holding_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -86,7 +86,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::holding_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -102,7 +102,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::holding_balance(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::holding_id(), @@ -118,7 +118,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::init_supply(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::holding_id(), @@ -135,7 +135,7 @@ impl AccountForTests { total_supply: BalanceForTests::init_supply_burned(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -151,7 +151,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::holding_balance_burned(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::holding_id(), @@ -175,7 +175,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::mint_success(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::holding_id(), @@ -191,7 +191,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::holding_balance_mint(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -208,7 +208,7 @@ impl AccountForTests { total_supply: BalanceForTests::init_supply_mint(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -224,7 +224,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::mint_overflow(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -241,7 +241,7 @@ impl AccountForTests { printable_supply: BalanceForTests::printable_copies(), metadata_id: AccountId::new([0; 32]), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -265,7 +265,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::init_supply(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -282,7 +282,7 @@ impl AccountForTests { total_supply: BalanceForTests::init_supply(), metadata_id: None, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::pool_definition_id(), @@ -298,7 +298,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::init_supply(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -314,7 +314,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::init_supply(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id_2(), @@ -330,7 +330,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::recipient_post_transfer(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id_2(), @@ -346,7 +346,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), balance: BalanceForTests::sender_post_transfer(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -362,7 +362,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), print_balance: BalanceForTests::printable_copies(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -378,7 +378,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), print_balance: 1, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -394,7 +394,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), print_balance: BalanceForTests::printable_copies() - 1, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), @@ -410,7 +410,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), owned: true, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: false, account_id: IdForTests::holding_id(), @@ -426,7 +426,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), print_balance: BalanceForTests::printable_copies(), }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id_2(), @@ -442,7 +442,7 @@ impl AccountForTests { definition_id: IdForTests::pool_definition_id(), print_balance: 0, }), - nonce: 0, + nonce: 0_u128.into(), }, is_authorized: true, account_id: IdForTests::holding_id(), 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 91% rename from sequencer_core/src/block_store.rs rename to sequencer/core/src/block_store.rs index eb541188..7a226d45 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, DbError> { + self.dbio.get_block(id) } pub fn delete_block_at_id(&mut self, block_id: u64) -> Result<()> { @@ -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/config.rs b/sequencer/core/src/config.rs similarity index 94% rename from sequencer_core/src/config.rs rename to 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/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 99% rename from sequencer_core/src/lib.rs rename to sequencer/core/src/lib.rs index c844c193..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}, @@ -387,14 +388,12 @@ mod tests { 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: 10000, block_create_timeout: Duration::from_secs(1), - port: 8080, initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), @@ -475,7 +474,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; @@ -693,6 +691,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); // Only one should be included in the block @@ -720,6 +719,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!(block.body.transactions, vec![tx.clone()]); @@ -731,6 +731,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert!(block.body.transactions.is_empty()); } @@ -765,6 +766,7 @@ mod tests { let block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!(block.body.transactions, vec![tx.clone()]); } @@ -883,6 +885,7 @@ mod tests { let new_block = sequencer .store .get_block_at_id(sequencer.chain_height) + .unwrap() .unwrap(); assert_eq!( 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 63% rename from sequencer_runner/Cargo.toml rename to sequencer/service/Cargo.toml index 71404d13..6fee808c 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 } @@ -9,20 +9,25 @@ workspace = true [dependencies] common.workspace = true +nssa.workspace = true +mempool.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } -sequencer_rpc.workspace = true +sequencer_service_protocol.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 +borsh.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_runner/Dockerfile b/sequencer/service/Dockerfile similarity index 79% rename from sequencer_runner/Dockerfile rename to sequencer/service/Dockerfile index 0efdf561..414d4889 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/sequencer_config.json"] diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer/service/configs/debug/sequencer_config.json similarity index 62% rename from sequencer_runner/configs/debug/sequencer_config.json rename to sequencer/service/configs/debug/sequencer_config.json index 2313ae20..4088fc4a 100644 --- a/sequencer_runner/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", @@ -20,50 +18,50 @@ "indexer_rpc_url": "ws://localhost:8779", "initial_accounts": [ { - "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", + "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", "balance": 10000 }, { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", + "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", "balance": 20000 } ], "initial_commitments": [ { - "npk":[ - 177, - 64, - 1, + "npk": [ + 139, + 19, + 158, 11, - 87, - 38, - 254, - 159, + 155, 231, - 165, - 1, - 94, - 64, - 137, - 243, - 76, - 249, - 101, - 251, - 129, - 33, - 101, - 189, - 30, - 42, - 11, - 191, - 34, - 103, - 186, - 227, - 230 - ] , + 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 + ], "account": { "program_owner": [ 0, @@ -82,38 +80,38 @@ }, { "npk": [ - 32, - 67, - 72, - 164, - 106, - 53, - 66, - 239, - 141, - 15, - 52, - 230, - 136, - 177, - 2, - 236, - 207, - 243, + 173, 134, - 135, - 210, - 143, - 87, - 232, + 33, + 223, + 54, + 226, + 10, + 71, 215, - 128, - 194, - 120, - 113, - 224, - 4, - 165 + 254, + 143, + 172, + 24, + 244, + 243, + 208, + 65, + 112, + 118, + 70, + 217, + 240, + 69, + 100, + 129, + 3, + 121, + 25, + 213, + 132, + 42, + 45 ], "account": { "program_owner": [ @@ -166,4 +164,4 @@ 37, 37 ] -} +} \ No newline at end of file diff --git a/sequencer_runner/configs/docker/sequencer_config.json b/sequencer/service/configs/docker/sequencer_config.json similarity index 64% rename from sequencer_runner/configs/docker/sequencer_config.json rename to sequencer/service/configs/docker/sequencer_config.json index ce79f4e2..f5a243d5 100644 --- a/sequencer_runner/configs/docker/sequencer_config.json +++ b/sequencer/service/configs/docker/sequencer_config.json @@ -1,13 +1,11 @@ { - "home": "/var/lib/sequencer_runner", - "override_rust_log": null, + "home": "/var/lib/sequencer_service", "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": { @@ -20,49 +18,49 @@ "indexer_rpc_url": "ws://localhost:8779", "initial_accounts": [ { - "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", + "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", "balance": 10000 }, { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", + "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", "balance": 20000 } ], "initial_commitments": [ { "npk": [ - 63, - 202, - 178, + 139, + 19, + 158, + 11, + 155, 231, - 183, - 82, - 237, - 212, - 216, - 221, - 215, - 255, - 153, - 101, - 177, - 161, - 254, - 210, - 128, - 122, - 54, - 190, - 230, - 151, - 183, - 64, - 225, - 229, - 113, - 1, + 85, + 206, + 132, 228, - 97 + 220, + 114, + 145, + 89, + 113, + 156, + 238, + 142, + 242, + 74, + 182, + 91, + 43, + 100, + 6, + 190, + 31, + 15, + 31, + 88, + 96, + 204 ], "account": { "program_owner": [ @@ -82,38 +80,38 @@ }, { "npk": [ - 192, - 251, - 166, - 243, - 167, - 236, - 84, - 249, - 35, - 136, - 130, + 173, + 134, + 33, + 223, + 54, + 226, + 10, + 71, + 215, + 254, + 143, 172, - 219, - 225, - 161, - 139, - 229, - 89, - 243, - 125, - 194, - 213, - 209, - 30, - 23, - 174, - 100, + 24, 244, - 124, - 74, - 140, - 47 + 243, + 208, + 65, + 112, + 118, + 70, + 217, + 240, + 69, + 100, + 129, + 3, + 121, + 25, + 213, + 132, + 42, + 45 ], "account": { "program_owner": [ diff --git a/sequencer/service/docker-compose.yml b/sequencer/service/docker-compose.yml new file mode 100644 index 00000000..81520e7b --- /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 file + - ./configs/docker/sequencer_config.json:/etc/sequencer_service/sequencer_config.json + # 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/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 new file mode 100644 index 00000000..d8f16b86 --- /dev/null +++ b/sequencer/service/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "sequencer_service_rpc" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +sequencer_service_protocol.workspace = true + +jsonrpsee = { workspace = true, features = ["macros"] } + +[features] +client = ["jsonrpsee/client"] +server = ["jsonrpsee/server"] diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs new file mode 100644 index 00000000..6c03cdb6 --- /dev/null +++ b/sequencer/service/rpc/src/lib.rs @@ -0,0 +1,92 @@ +use std::collections::BTreeMap; + +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 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."); + +/// 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 +/// +/// ```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")] +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))] +pub trait Rpc { + #[method(name = "sendTransaction")] + async fn send_transaction(&self, tx: NSSATransaction) -> Result; + + // TODO: expand healthcheck response into some kind of report + #[method(name = "checkHealth")] + async fn check_health(&self) -> Result<(), ErrorObjectOwned>; + + // TODO: These functions should be removed after wallet starts using indexer + // for this type of queries. + // + // ============================================================================================= + + #[method(name = "getBlock")] + async fn get_block(&self, block_id: BlockId) -> Result, ErrorObjectOwned>; + + #[method(name = "getBlockRange")] + async fn get_block_range( + &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 = "getTransaction")] + async fn get_transaction( + &self, + tx_hash: HashType, + ) -> Result, ErrorObjectOwned>; + + #[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, ErrorObjectOwned>; + + #[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_runner/src/lib.rs b/sequencer/service/src/lib.rs similarity index 65% rename from sequencer_runner/src/lib.rs rename to sequencer/service/src/lib.rs index a17ecbf9..5373b31f 100644 --- a/sequencer_runner/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. + const 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 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 run_forever(&mut self) -> Result { + pub async fn failed(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")? @@ -72,11 +88,25 @@ 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_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_healthy(&self) -> bool { + let Self { + addr: _, + server_handle, + main_loop_handle, + retry_pending_blocks_loop_handle, + listen_for_bedrock_blocks_loop_handle, + } = self; + + 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(); + !stopped } #[must_use] @@ -89,7 +119,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 +129,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 +180,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 +273,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 +285,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 +350,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 new file mode 100644 index 00000000..e78ad502 --- /dev/null +++ b/sequencer/service/src/main.rs @@ -0,0 +1,60 @@ +use std::path::PathBuf; + +use anyhow::Result; +use clap::Parser; +use log::{error, info}; +use tokio_util::sync::CancellationToken; + +#[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.failed() => { + error!("Sequencer failed 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..71645363 --- /dev/null +++ b/sequencer/service/src/service.rs @@ -0,0 +1,183 @@ +use std::{collections::BTreeMap, sync::Arc}; + +use common::transaction::NSSATransaction; +use jsonrpsee::{ + core::async_trait, + types::{ErrorCode, ErrorObjectOwned}, +}; +use log::warn; +use mempool::MemPoolHandle; +use nssa::{self, program::Program}; +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; + +pub struct SequencerService { + sequencer: Arc>>, + mempool_handle: MemPoolHandle, + max_block_size: u64, +} + +impl SequencerService { + pub const 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 encoded_tx = + borsh::to_vec(&tx).expect("Transaction borsh serialization should not fail"); + let tx_size = u64::try_from(encoded_tx.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(&self, block_id: BlockId) -> Result, ErrorObjectOwned> { + let sequencer = self.sequencer.lock().await; + sequencer + .block_store() + .get_block_at_id(block_id) + .map_err(|err| internal_error(&err)) + } + + 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| { + let block = sequencer + .block_store() + .get_block_at_id(block_id) + .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::, _>>() + } + + 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( + &self, + tx_hash: HashType, + ) -> Result, ErrorObjectOwned> { + let sequencer = self.sequencer.lock().await; + Ok(sequencer.block_store().get_transaction_by_hash(tx_hash)) + } + + 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, ErrorObjectOwned> { + let sequencer = self.sequencer.lock().await; + Ok(sequencer.state().get_proof_for_commitment(&commitment)) + } + + 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) + } +} + +fn internal_error(err: &DbError) -> ErrorObjectOwned { + ErrorObjectOwned::owned(ErrorCode::InternalError.code(), err.to_string(), None::<()>) +} diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml deleted file mode 100644 index 5c76ba34..00000000 --- a/sequencer_rpc/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "sequencer_rpc" -version = "0.1.0" -edition = "2024" -license = { workspace = true } - -[lints] -workspace = true - -[dependencies] -nssa.workspace = true -common.workspace = true -mempool.workspace = true -sequencer_core = { workspace = true } -bedrock_client.workspace = true - -anyhow.workspace = true -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"] } - -[features] -default = [] -# Includes types to run the sequencer in standalone mode -standalone = ["sequencer_core/mock"] diff --git a/sequencer_rpc/src/lib.rs b/sequencer_rpc/src/lib.rs deleted file mode 100644 index 47e4fa75..00000000 --- a/sequencer_rpc/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::sync::Arc; - -use common::{ - rpc_primitives::errors::{RpcError, RpcErrorKind}, - 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 self::types::err_rpc::RpcErr; - -pub mod net_utils; -pub mod process; -pub mod types; - -#[cfg(feature = "standalone")] -pub type JsonHandlerWithMockClients = JsonHandler; - -// 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, - } -} diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs deleted file mode 100644 index e306ec0e..00000000 --- a/sequencer_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_rpc/src/process.rs b/sequencer_rpc/src/process.rs deleted file mode 100644 index 3a6a4d60..00000000 --- a/sequencer_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) - .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_rpc/src/types/err_rpc.rs b/sequencer_rpc/src/types/err_rpc.rs deleted file mode 100644 index 4cb75606..00000000 --- a/sequencer_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_rpc/src/types/mod.rs b/sequencer_rpc/src/types/mod.rs deleted file mode 100644 index 0b78fea1..00000000 --- a/sequencer_rpc/src/types/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod err_rpc; 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/sequencer_runner/src/main.rs b/sequencer_runner/src/main.rs deleted file mode 100644 index 3bf4ee2d..00000000 --- a/sequencer_runner/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -use anyhow::Result; -use sequencer_runner::main_runner; - -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()) -} diff --git a/storage/src/indexer/mod.rs b/storage/src/indexer/mod.rs index c5d47c1f..bb84069a 100644 --- a/storage/src/indexer/mod.rs +++ b/storage/src/indexer/mod.rs @@ -262,7 +262,7 @@ mod tests { let is_first_set = dbio.get_meta_is_first_block_set().unwrap(); let last_observed_l1_header = dbio.get_meta_last_observed_l1_lib_header_in_db().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(); @@ -313,7 +313,7 @@ mod tests { .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(); @@ -353,7 +353,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; @@ -376,7 +376,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(); @@ -425,7 +425,7 @@ mod tests { let sign_key = acc1_sign_key(); 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 = @@ -437,7 +437,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 = @@ -449,7 +449,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 = @@ -461,7 +461,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 = @@ -472,10 +472,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); @@ -502,7 +508,7 @@ mod tests { let sign_key = acc1_sign_key(); 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 = @@ -513,7 +519,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 = @@ -524,7 +530,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 = @@ -535,7 +541,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 = @@ -600,7 +606,7 @@ mod tests { let mut tx_hash_res = vec![]; 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_tx1 = @@ -619,7 +625,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_tx1 = @@ -638,7 +644,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_tx1 = @@ -657,7 +663,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 = diff --git a/storage/src/indexer/read_once.rs b/storage/src/indexer/read_once.rs index f966f349..19aee681 100644 --- a/storage/src/indexer/read_once.rs +++ b/storage/src/indexer/read_once.rs @@ -146,7 +146,7 @@ impl RocksDBIO { // Block - 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 @@ -162,16 +162,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::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Ok(None) } } @@ -208,7 +206,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 @@ -224,17 +222,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::db_interaction_error( - "Block on this hash not found".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 @@ -250,13 +246,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::db_interaction_error( - "Block for this tx hash not found".to_owned(), - )) + Ok(None) } } diff --git a/storage/src/sequencer.rs b/storage/src/sequencer.rs index 8d072a52..143b96ce 100644 --- a/storage/src/sequencer.rs +++ b/storage/src/sequencer.rs @@ -442,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 @@ -458,16 +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::db_interaction_error( - "Block on this id not found".to_owned(), - )) + Ok(None) } } @@ -495,7 +493,7 @@ impl RocksDBIO { })?) } else { Err(DbError::db_interaction_error( - "Block on this id not found".to_owned(), + "NSSA state not found".to_owned(), )) } } @@ -512,9 +510,9 @@ 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::db_interaction_error(format!( + "Block with id {block_id} not found" + ))); } self.db @@ -525,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/test_program_methods/guest/src/bin/nonce_changer.rs b/test_program_methods/guest/src/bin/nonce_changer.rs index d7bea154..52d2e392 100644 --- a/test_program_methods/guest/src/bin/nonce_changer.rs +++ b/test_program_methods/guest/src/bin/nonce_changer.rs @@ -11,7 +11,7 @@ fn main() { let account_pre = &pre.account; let mut account_post = account_pre.clone(); - account_post.nonce = account_post.nonce.overflowing_add(1).0; + account_post.nonce.public_account_nonce_increment(); write_nssa_outputs( instruction_words, diff --git a/wallet-ffi/Cargo.toml b/wallet-ffi/Cargo.toml index 93096e12..0af20a54 100644 --- a/wallet-ffi/Cargo.toml +++ b/wallet-ffi/Cargo.toml @@ -13,8 +13,8 @@ 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 [build-dependencies] diff --git a/wallet-ffi/src/keys.rs b/wallet-ffi/src/keys.rs index 8030bf5a..4eeadd8f 100644 --- a/wallet-ffi/src/keys.rs +++ b/wallet-ffi/src/keys.rs @@ -123,7 +123,7 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys( }; // NPK is a 32-byte array - let npk_bytes = key_chain.nullifer_public_key.0; + let npk_bytes = key_chain.nullifier_public_key.0; // VPK is a compressed secp256k1 point (33 bytes) let vpk_bytes = key_chain.viewing_public_key.to_bytes(); 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-ffi/src/types.rs b/wallet-ffi/src/types.rs index 21942e8d..87c30315 100644 --- a/wallet-ffi/src/types.rs +++ b/wallet-ffi/src/types.rs @@ -222,7 +222,7 @@ impl From for FfiAccount { balance: value.balance.into(), data, data_len, - nonce: value.nonce.into(), + nonce: value.nonce.0.into(), } } } @@ -244,7 +244,7 @@ impl TryFrom<&FfiAccount> for nssa::Account { program_owner: value.program_owner.data, balance: value.balance.into(), data, - nonce: value.nonce.into(), + nonce: nssa_core::account::Nonce(value.nonce.into()), }) } } diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 63e14bb6..2e628790 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 @@ -25,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/configs/debug/wallet_config.json b/wallet/configs/debug/wallet_config.json index aae6293e..6604f65b 100644 --- a/wallet/configs/debug/wallet_config.json +++ b/wallet/configs/debug/wallet_config.json @@ -1,147 +1,411 @@ { - "override_rust_log": null, - "sequencer_addr": "http://127.0.0.1:3040", - "seq_poll_timeout": "30s", - "seq_tx_poll_max_blocks": 15, - "seq_poll_max_retries": 10, - "seq_block_poll_max_amount": 100, - "initial_accounts": [ - { - "Public": { - "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", - "pub_sign_key": [ - 16, - 162, - 106, - 154, - 236, - 125, - 52, - 184, - 35, - 100, - 238, - 174, - 69, - 197, - 41, - 77, - 187, - 10, - 118, - 75, - 0, - 11, - 148, - 238, - 185, - 181, - 133, - 17, - 220, - 72, - 124, - 77 - ] - } - }, - { - "Public": { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", - "pub_sign_key": [ - 113, - 121, - 64, - 177, - 204, - 85, - 229, - 214, - 178, - 6, - 109, - 191, - 29, - 154, - 63, - 38, - 242, - 18, - 244, - 219, - 8, - 208, - 35, - 136, - 23, - 127, - 207, - 237, - 216, - 169, - 190, - 27 - ] - } - }, + "sequencer_addr": "http://127.0.0.1:3040", + "seq_poll_timeout": "30s", + "seq_tx_poll_max_blocks": 15, + "seq_poll_max_retries": 10, + "seq_block_poll_max_amount": 100, + "initial_accounts": [ { - "Private": { - "account_id": "2ECgkFTaXzwjJBXR7ZKmXYQtpHbvTTHK9Auma4NL9AUo", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 10000, - "data": [], - "nonce": 0 + "Public": { + "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", + "pub_sign_key": "7f273098f25b71e6c005a9519f2678da8d1c7f01f6a27778e2d9948abdf901fb" + } }, - "key_chain": { - "secret_spending_key": [112, 17, 152, 192, 217, 201, 142, 92, 111, 68, 85, 222, 107, 73, 78, 196, 118, 226, 37, 17, 185, 177, 149, 182, 9, 85, 187, 152, 163, 144, 68, 121], - "private_key_holder": { - "nullifier_secret_key": [52, 33, 235, 245, 42, 132, 163, 182, 114, 56, 144, 187, 147, 23, 184, 227, 128, 12, 180, 142, 217, 110, 188, 177, 155, 141, 23, 127, 216, 185, 33, 126], - "viewing_secret_key": [44, 81, 165, 166, 34, 188, 192, 240, 40, 9, 83, 189, 215, 184, 246, 154, 247, 227, 155, 16, 121, 238, 4, 245, 63, 135, 192, 213, 222, 247, 120, 86] - }, - "nullifer_public_key": [13, 25, 40, 5, 198, 248, 210, 248, 237, 121, 124, 145, 186, 142, 253, 216, 236, 69, 193, 32, 166, 167, 49, 133, 172, 111, 159, 46, 84, 17, 157, 23], - "viewing_public_key": [3, 43, 116, 165, 161, 27, 150, 158, 175, 198, 215, 27, 121, 126, 158, 224, 249, 92, 168, 163, 173, 115, 120, 122, 89, 173, 133, 94, 39, 238, 62, 52, 193] - } - } - }, - { - "Private": { - "account_id": "E8HwiTyQe4H9HK7icTvn95HQMnzx49mP9A2ddtMLpNaN", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 20000, - "data": [], - "nonce": 0 + { + "Public": { + "account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2", + "pub_sign_key": "f434f8741720014586ae43356d2aec6257da086222f604ddb75d69733b86fc4c" + } }, - "key_chain": { - "secret_spending_key": [48, 175, 124, 10, 230, 240, 166, 14, 249, 254, 157, 226, 208, 124, 122, 177, 203, 139, 192, 180, 43, 120, 55, 151, 50, 21, 113, 22, 254, 83, 148, 56], - "private_key_holder": { - "nullifier_secret_key": [99, 82, 190, 140, 234, 10, 61, 163, 15, 211, 179, 54, 70, 166, 87, 5, 182, 68, 117, 244, 217, 23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30], - "viewing_secret_key": [205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21, 154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128] - }, - "nullifer_public_key": [32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210, 143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165], - "viewing_public_key": [2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11, 171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238] + { + "Private": { + "account_id": "9DGDXnrNo4QhUUb2F8WDuDrPESja3eYDkZG5HkzvAvMC", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 10000, + "data": [], + "nonce": 0 + }, + "key_chain": { + "secret_spending_key": [ + 75, + 231, + 144, + 165, + 5, + 36, + 183, + 237, + 190, + 227, + 238, + 13, + 132, + 39, + 114, + 228, + 172, + 82, + 119, + 164, + 233, + 132, + 130, + 224, + 201, + 90, + 200, + 156, + 108, + 199, + 56, + 22 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 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": [ + 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": [ + 122, + 213, + 113, + 8, + 118, + 179, + 235, + 94, + 5, + 219, + 131, + 106, + 246, + 253, + 14, + 204, + 65, + 93, + 0, + 198, + 100, + 108, + 57, + 48, + 6, + 65, + 183, + 31, + 136, + 86, + 82, + 165 + ], + "viewing_public_key": [ + 3, + 165, + 235, + 215, + 77, + 4, + 19, + 45, + 0, + 27, + 18, + 26, + 11, + 226, + 126, + 174, + 144, + 167, + 160, + 199, + 14, + 23, + 49, + 163, + 49, + 138, + 129, + 229, + 79, + 9, + 15, + 234, + 30 + ] + } + } + }, + { + "Private": { + "account_id": "A6AT9UvsgitUi8w4BH43n6DyX1bK37DtSCfjEWXQQUrQ", + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 20000, + "data": [], + "nonce": 0 + }, + "key_chain": { + "secret_spending_key": [ + 107, + 49, + 136, + 174, + 162, + 107, + 250, + 105, + 252, + 146, + 166, + 197, + 163, + 132, + 153, + 222, + 68, + 17, + 87, + 101, + 22, + 113, + 88, + 97, + 180, + 203, + 139, + 18, + 28, + 62, + 51, + 149 + ], + "private_key_holder": { + "nullifier_secret_key": [ + 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": [ + 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": [ + 33, + 68, + 229, + 154, + 12, + 235, + 210, + 229, + 236, + 144, + 126, + 122, + 58, + 107, + 36, + 58, + 243, + 128, + 174, + 197, + 141, + 137, + 162, + 190, + 155, + 234, + 94, + 156, + 218, + 34, + 13, + 221 + ], + "viewing_public_key": [ + 3, + 122, + 7, + 137, + 250, + 84, + 10, + 85, + 3, + 15, + 134, + 250, + 205, + 40, + 126, + 211, + 14, + 120, + 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/chain_storage.rs b/wallet/src/chain_storage.rs index 90325666..a88e0b8b 100644 --- a/wallet/src/chain_storage.rs +++ b/wallet/src/chain_storage.rs @@ -161,110 +161,48 @@ 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": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", - "pub_sign_key": [ - 16, - 162, - 106, - 154, - 236, - 125, - 52, - 184, - 35, - 100, - 238, - 174, - 69, - 197, - 41, - 77, - 187, - 10, - 118, - 75, - 0, - 11, - 148, - 238, - 185, - 181, - 133, - 17, - 220, - 72, - 124, - 77 - ] - } - }"#, - ) - .unwrap(); - - let initial_acc2 = serde_json::from_str( - r#"{ - "Public": { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", - "pub_sign_key": [ - 113, - 121, - 64, - 177, - 204, - 85, - 229, - 214, - 178, - 6, - 109, - 191, - 29, - 154, - 63, - 38, - 242, - 18, - 244, - 219, - 8, - 208, - 35, - 136, - 23, - 127, - 207, - 237, - 216, - 169, - 190, - 27 - ] - } - }"#, - ) - .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 { 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/account.rs b/wallet/src/cli/account.rs index 319fac0e..2a8ed2c7 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 as _; use token_core::{TokenDefinition, TokenHolding}; use crate::{ @@ -145,7 +146,7 @@ impl WalletSubcommand for NewSubcommand { println!( "Generated new account with account_id Private/{account_id} at path {chain_index}", ); - println!("With npk {}", hex::encode(key.nullifer_public_key.0)); + println!("With npk {}", hex::encode(key.nullifier_public_key.0)); println!( "With vpk {}", hex::encode(key.viewing_public_key.to_bytes()) @@ -208,7 +209,7 @@ impl WalletSubcommand for AccountSubcommand { .get_private_account(account_id) .context("Private account not found in storage")?; - println!("npk {}", hex::encode(key.nullifer_public_key.0)); + println!("npk {}", hex::encode(key.nullifier_public_key.0)); println!("vpk {}", hex::encode(key.viewing_public_key.to_bytes())); } } @@ -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/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/cli/mod.rs b/wallet/src/cli/mod.rs index 58d77d6a..85e792cc 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 as _; 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..b3f833ac 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!("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:?}"); @@ -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!("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 { @@ -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..94cb0649 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..4274b1da 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/config.rs b/wallet/src/config.rs index 7e4c4cec..60164e86 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -186,9 +186,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. @@ -209,299 +206,61 @@ 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 { - 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, seq_poll_max_retries: 5, seq_block_poll_max_amount: 100, basic_auth: None, - initial_accounts: { - let init_acc_json = r#" - [ - { - "Public": { - "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", - "pub_sign_key": [ - 16, - 162, - 106, - 154, - 236, - 125, - 52, - 184, - 35, - 100, - 238, - 174, - 69, - 197, - 41, - 77, - 187, - 10, - 118, - 75, - 0, - 11, - 148, - 238, - 185, - 181, - 133, - 17, - 220, - 72, - 124, - 77 - ] - } - }, - { - "Public": { - "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", - "pub_sign_key": [ - 113, - 121, - 64, - 177, - 204, - 85, - 229, - 214, - 178, - 6, - 109, - 191, - 29, - 154, - 63, - 38, - 242, - 18, - 244, - 219, - 8, - 208, - 35, - 136, - 23, - 127, - 207, - 237, - 216, - 169, - 190, - 27 - ] - } - }, - { - "Private": { - "account_id": "FpdcxBrMkHWqXCBQ6FG98eYfWGY6jWZRsKNSi1FwDMxy", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 10000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 239, - 27, - 159, - 83, - 199, - 194, - 132, - 33, - 20, - 28, - 217, - 103, - 101, - 57, - 27, - 125, - 84, - 57, - 19, - 86, - 98, - 135, - 161, - 221, - 108, - 125, - 152, - 174, - 161, - 64, - 16, - 200 - ], - "private_key_holder": { - "nullifier_secret_key": [ - 71, - 195, - 16, - 119, - 0, - 98, - 35, - 106, - 139, - 82, - 145, - 50, - 27, - 140, - 206, - 19, - 53, - 122, - 166, - 76, - 195, - 0, - 16, - 19, - 21, - 143, - 155, - 119, - 9, - 200, - 81, - 105 - ], - "viewing_secret_key": [ - 5, - 117, - 221, - 27, - 236, - 199, - 53, - 22, - 249, - 231, - 98, - 147, - 213, - 116, - 191, - 82, - 188, - 148, - 175, - 98, - 139, - 52, - 232, - 249, - 220, - 217, - 83, - 58, - 112, - 155, - 197, - 196 - ] + initial_accounts: vec![ + InitialAccountData::Public(InitialAccountDataPublic { + account_id: public_account_id1, + pub_sign_key: pub_sign_key1, + }), + InitialAccountData::Public(InitialAccountDataPublic { + account_id: public_account_id2, + pub_sign_key: pub_sign_key2, + }), + InitialAccountData::Private(Box::new(InitialAccountDataPrivate { + account_id: private_account_id1, + account: nssa::Account { + balance: 10_000, + ..Default::default() }, - "nullifer_public_key": [ - 177, - 64, - 1, - 11, - 87, - 38, - 254, - 159, - 231, - 165, - 1, - 94, - 64, - 137, - 243, - 76, - 249, - 101, - 251, - 129, - 33, - 101, - 189, - 30, - 42, - 11, - 191, - 34, - 103, - 186, - 227, - 230 - ], - "viewing_public_key": [ - 2, 69, 126, 43, 158, 209, 172, 144, 23, 185, 208, 25, 163, 166, 176, 200, 225, 251, 106, 211, 4, 199, 112, 243, 207, 144, 135, 56, 157, 167, 32, 219, 38] - } - } - }, - { - "Private": { - "account_id": "E8HwiTyQe4H9HK7icTvn95HQMnzx49mP9A2ddtMLpNaN", - "account": { - "program_owner": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "balance": 20000, - "data": [], - "nonce": 0 - }, - "key_chain": { - "secret_spending_key": [ - 48, 175, 124, 10, 230, 240, 166, 14, 249, 254, 157, 226, 208, 124, 122, 177, 203, 139, 192, 180, 43, 120, 55, 151, 50, 21, 113, 22, 254, 83, 148, 56], - "private_key_holder": { - "nullifier_secret_key": [ - 99, 82, 190, 140, 234, 10, 61, 163, 15, 211, 179, 54, 70, 166, 87, 5, 182, 68, 117, 244, 217, 23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30 - ], - "viewing_secret_key": [ - 205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21, 154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128 - ] + key_chain: key_chain1, + })), + InitialAccountData::Private(Box::new(InitialAccountDataPrivate { + account_id: private_account_id2, + account: nssa::Account { + balance: 20_000, + ..Default::default() }, - "nullifer_public_key": [ - 32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210, 143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165 - ], - "viewing_public_key": [ - 2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11, 171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238 - ] - } - } - } - ] - "#; - serde_json::from_str(init_acc_json).unwrap() - }, + key_chain: key_chain2, + })), + ], } } } @@ -546,7 +305,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, @@ -557,7 +315,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, @@ -567,10 +324,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; diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index c7be5811..74f7bab3 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -44,7 +44,7 @@ impl From for HumanReadableAccount { balance: account.balance, program_owner, data, - nonce: account.nonce, + nonce: account.nonce.0, } } } @@ -145,12 +145,16 @@ pub fn produce_data_for_storage( } } +#[expect(dead_code, reason = "Maybe used later")] pub(crate) fn produce_random_nonces(size: usize) -> Vec { let mut result = vec![[0; 16]; size]; for bytes in &mut result { OsRng.fill_bytes(bytes); } - result.into_iter().map(Nonce::from_le_bytes).collect() + result + .into_iter() + .map(|x| Nonce(u128::from_le_bytes(x))) + .collect() } pub(crate) fn parse_addr_with_privacy_prefix( diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index a3c58a97..bf82a1bd 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; @@ -26,13 +22,16 @@ 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 _; use crate::{ config::{PersistentStorage, WalletConfigOverrides}, - helperfunctions::{produce_data_for_storage, produce_random_nonces}, + helperfunctions::produce_data_for_storage, poller::TxPoller, }; @@ -51,6 +50,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")] + SequencerClientError(#[from] sequencer_service_rpc::ClientError), + #[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, @@ -58,7 +73,7 @@ pub struct WalletCore { storage: WalletChainStore, storage_path: PathBuf, poller: TxPoller, - pub sequencer_client: Arc, + pub sequencer_client: SequencerClient, pub last_synced_block: u64, } @@ -129,11 +144,25 @@ 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( + std::iter::once(( + "Authorization".parse().expect("Header name is valid"), + format!("Basic {basic_auth}") + .parse() + .context("Invalid basic auth format")?, + )) + .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)?; @@ -222,26 +251,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) + pub async fn get_accounts_nonces(&self, accs: Vec) -> Result> { + 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] @@ -265,16 +285,12 @@ impl WalletCore { #[must_use] pub fn get_private_account_commitment(&self, account_id: AccountId) -> Option { let (keys, account) = self.storage.user_data.get_private_account(account_id)?; - Some(Commitment::new(&keys.nullifer_public_key, account)) + Some(Commitment::new(&keys.nullifier_public_key, account)) } /// 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( @@ -285,7 +301,7 @@ impl WalletCore { self.sequencer_client .get_proof_for_commitment(acc_comm) .await - .map_err(anyhow::Error::from) + .map_err(Into::into) } else { Ok(None) } @@ -325,17 +341,12 @@ 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, 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(()) }) @@ -348,7 +359,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(); @@ -364,7 +375,6 @@ impl WalletCore { pre_states, instruction_data, acc_manager.visibility_mask().to_vec(), - produce_random_nonces(private_account_keys.len()), private_account_keys .iter() .map(|keys| (keys.npk.clone(), keys.ssk)) @@ -401,7 +411,9 @@ impl WalletCore { .collect(); Ok(( - self.sequencer_client.send_tx_private(tx).await?, + self.sequencer_client + .send_transaction(NSSATransaction::PrivacyPreserving(tx)) + .await?, shared_secrets, )) } @@ -428,11 +440,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); } @@ -470,7 +482,7 @@ impl WalletCore { let affected_accounts = private_account_key_chains .flat_map(|(acc_account_id, key_chain, index)| { let view_tag = EncryptedAccountData::compute_view_tag( - &key_chain.nullifer_public_key, + &key_chain.nullifier_public_key, &key_chain.viewing_public_key, ); 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<()> { diff --git a/wallet/src/pinata_interactions.rs b/wallet/src/pinata_interactions.rs index abcfcf6a..b883e7e6 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).into()).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).into()).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).into()).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 5418c58d..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 { @@ -214,7 +213,7 @@ async fn private_acc_preparation( let nsk = from_keys.private_key_holder.nullifier_secret_key; - let from_npk = from_keys.nullifer_public_key; + let from_npk = from_keys.nullifier_public_key; let from_vpk = from_keys.viewing_public_key; // TODO: Remove this unwrap, error types must be compatible diff --git a/wallet/src/program_facades/amm.rs b/wallet/src/program_facades/amm.rs index 251970bc..f1b94621 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 { @@ -92,7 +93,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( @@ -102,7 +107,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, @@ -197,7 +202,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( @@ -208,7 +217,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, @@ -286,7 +295,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( @@ -297,7 +310,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, @@ -366,6 +379,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..c771c735 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; @@ -15,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, ) -> ( 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 eb2adc9a..f91171db 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) @@ -42,7 +44,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) } @@ -51,7 +57,7 @@ impl NativeTokenTransfer<'_> { pub async fn register_account( &self, from: AccountId, - ) -> Result { + ) -> Result { let nonces = self .0 .get_accounts_nonces(vec![from]) @@ -73,6 +79,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 fe5165ff..3aa6891f 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 { @@ -159,7 +164,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( @@ -167,7 +176,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, }; @@ -198,7 +207,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, }; @@ -231,7 +240,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, }; @@ -262,7 +271,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, }; @@ -294,7 +303,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, }; @@ -328,7 +337,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, @@ -358,7 +367,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( @@ -366,7 +379,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, }; @@ -396,7 +409,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, }; @@ -427,7 +440,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, }; @@ -458,7 +471,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, @@ -490,7 +503,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( @@ -498,7 +515,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, }; @@ -529,7 +546,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, }; @@ -562,7 +579,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, }; @@ -593,7 +610,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, }; @@ -625,7 +642,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 2a48d3e6..1bcb971f 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, @@ -39,7 +40,7 @@ impl WalletCore { let mut nsk = None; let mut proof = None; - let from_npk = from_keys.nullifer_public_key; + let from_npk = from_keys.nullifier_public_key; let from_vpk = from_keys.viewing_public_key; let sender_commitment = Commitment::new(&from_npk, &from_acc); @@ -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).into()).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).into()).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).into()).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).into()).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).into()).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).into()).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).into()).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).into()).await?, [shared_secret_from], )) }